• Service


    什么是服务?

    windows下的服务:没有界面、长期运行在后台的应用程序;
    android下的服务:应用程序的一个组件,没有界面activity,长期运行在后台;

    进程:是应用程序运行的载体。
    进程与应用程序之间的关系: linux操作系统创建一个进程,这个进程负责运行dalvik虚拟机,Android的应用程序都是运行在dalvik虚拟机上的。

    进程的生命周期:

    1、应用程序一启动的时候就创建了进程;
    2、当应用程序退出的时候进程并没有退出;
    3、只有手工停止这个进程,进程才会结束;如果是自动关闭,内存充足就会重启。


    操作系统尽量长时间的运行应用程序的进程,为了保证内从空间不被大量占用,它会按照进程的优先级,从低到高一级一级的杀死进程,直到内存空间被清理的差不多。

    进程的等级:

    1. Foreground process(前台进程)

    应用程序,用户正在操作,activity的onResume方法被执行了,可以相应点击事件。(onResume)

    2. Visible process (可视进程)

    应用程序的ui界面,用户还可以看到,但是不能操作了。(onPause)

    3. Service process (服务进程)

    应用程序没有界面,但是有一个后台的服务还处于运行状态.

    4. Background process(后台进程)

    应用程序没有服务处于运行状态,应用程序被最小化了,activity执行了onstop方法.(onStop)

    5. Empty process (空进程)

    没有任何组件运行,所有的activity都关闭了,任务栈清空了

    服务的特点

    服务被创建时调用onCreate、onStartCommand;
    服务只能被创建一次,可以开启多次onStartCommand;
    服务只能被停止一次 onDestroy;
    没有onPause、onStop、onResume、onRestart方法,因为service没有界面,长期运行在后台。

    生命周期的方法:

    onCreate()--->onStartCommand()--->onDestroy()(stopService())


    onCreate:服务被创建的时候调用这个方法;
    onStartCommand :开启服务
    onDestroy:销毁服务

    电话qietingqi的模板代码(重点)

    步骤:

    1、在工程中添加一个服务Service,重写onCreate方法;

    2、在清单文件中配置服务;

    3、在activity中开启服务,在onCreate方法中使用TelephonyManager监听电话的状态;

    4、创建一个广播接收者,开机即开启录音服务;

    5、在清单文件中配置广播接收者

    6、在清单配置文件中添加权限

    代码:

     1 package com.ahu.lichang.recorderservice;
     2 
     3 import android.app.Service;
     4 import android.content.Intent;
     5 import android.media.MediaRecorder;
     6 import android.os.IBinder;
     7 import android.support.annotation.Nullable;
     8 import android.telephony.PhoneStateListener;
     9 import android.telephony.TelephonyManager;
    10 
    11 /**
    12  * Created by ahu_lichang on 2017/3/24.
    13  */
    14 public class RecorderService extends Service{
    15     private MediaRecorder recorder;
    16     /**
    17      * 绑定服务时,要调用此方法
    18      * @param intent
    19      * @return
    20      */
    21     @Nullable
    22     @Override
    23     public IBinder onBind(Intent intent) {
    24         return null;
    25     }
    26 
    27     /**
    28      * 创建服务时,调用此方法
    29      */
    30     @Override
    31     public void onCreate() {
    32         super.onCreate();
    33         //拿到系统服务电话管理器
    34         TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
    35         //监听电话状态
    36         tm.listen(new MyPhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE);
    37     }
    38     class MyPhoneStateListener extends PhoneStateListener {
    39         @Override
    40         public void onCallStateChanged(int state, String incomingNumber) {
    41             super.onCallStateChanged(state, incomingNumber);
    42             switch (state){
    43                 case TelephonyManager.CALL_STATE_IDLE://空闲状态
    44                     if(recorder != null){
    45                         recorder.stop();
    46                         recorder.release();
    47                         recorder = null;
    48                     }
    49                     break;
    50                 case TelephonyManager.CALL_STATE_RINGING://响铃状态
    51                     if(recorder == null){
    52                         //创建录音机
    53                         recorder = new MediaRecorder();
    54                         //设置声音来源
    55                         recorder.setAudioSource(MediaRecorder.AudioSource.MIC);//MIC:只能录自己的声音
    56                         //设置音频文件格式
    57                         recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    58                         recorder.setOutputFile("storage/sdcard/luyin.3gp");
    59                         //设置音频文件编码
    60                         recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    61                         try {
    62                             recorder.prepare();
    63                         } catch (Exception e) {
    64                             e.printStackTrace();
    65                         }
    66                     }
    67                     break;
    68                 case TelephonyManager.CALL_STATE_OFFHOOK://摘机状态
    69                     if(recorder != null){
    70                         recorder.start();
    71                     }
    72                     break;
    73             }
    74         }
    75     }
    76 
    77     /**
    78      * 开启服务时,调用此方法
    79      * @param intent
    80      * @param flags
    81      * @param startId
    82      * @return
    83      */
    84     @Override
    85     public int onStartCommand(Intent intent, int flags, int startId) {
    86         return super.onStartCommand(intent, flags, startId);
    87     }
    88 
    89     /**
    90      * 销毁服务时,调用此方法
    91      */
    92     @Override
    93     public void onDestroy() {
    94         super.onDestroy();
    95     }
    96 }
     1 package com.ahu.lichang.recorderservice;
     2 
     3 import android.content.Intent;
     4 import android.support.v7.app.AppCompatActivity;
     5 import android.os.Bundle;
     6 import android.view.View;
     7 
     8 public class MainActivity extends AppCompatActivity {
     9 
    10     @Override
    11     protected void onCreate(Bundle savedInstanceState) {
    12         super.onCreate(savedInstanceState);
    13         setContentView(R.layout.activity_main);
    14     }
    15 
    16     public void click(View view){
    17         Intent intent = new Intent(this,RecorderService.class);
    18         startService(intent);
    19     }
    20 }
     1 package com.ahu.lichang.recorderservice;
     2 
     3 import android.content.BroadcastReceiver;
     4 import android.content.Context;
     5 import android.content.Intent;
     6 
     7 /**
     8  * Created by ahu_lichang on 2017/3/24.
     9  */
    10 
    11 public class RecorderReceiver extends BroadcastReceiver {
    12     @Override
    13     public void onReceive(Context context, Intent intent) {
    14         //开机启动时,开启录音服务
    15         Intent i = new Intent(context,RecorderService.class);
    16         context.startService(i);
    17     }
    18 }
     1 <?xml version="1.0" encoding="utf-8"?>
     2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     3     package="com.ahu.lichang.recorderservice">
     4     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
     5     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     6     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     7     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
     8     <uses-permission android:name="android.permission.RECORD_AUDIO"/>
     9 
    10     <application
    11         android:allowBackup="true"
    12         android:icon="@mipmap/ic_launcher"
    13         android:label="@string/app_name"
    14         android:supportsRtl="true"
    15         android:theme="@style/AppTheme">
    16         <activity android:name=".MainActivity">
    17             <intent-filter>
    18                 <action android:name="android.intent.action.MAIN" />
    19 
    20                 <category android:name="android.intent.category.LAUNCHER" />
    21             </intent-filter>
    22         </activity>
    23 
    24         <receiver android:name=".RecorderReceiver">
    25             <intent-filter>
    26                 <!--开机启动-->
    27                 <action android:name="android.intent.action.BOOT_COMPLETED"/>
    28             </intent-filter>
    29         </receiver>
    30 
    31         <service android:name=".RecorderService">
    32         </service>
    33     </application>
    34 
    35 </manifest>

    服务的两种开启方式:

    1、startService方式开启服务

    服务启动之后,跟启动他的组件没有关系。该方法启动的服务所在进程属于服务进程

    2、bindService方式开启服务(重点)

    bindService绑定服务、unBindService解除绑定的服务;
    服务是在被绑定的时候被创建,调用oncreate、onbind方法;
    服务只能被绑定一次;
    服务只能被解除一次,解除绑定的时候调用onUnbind、onDestrory方法,如果多次解除绑定会抛出异常

    推荐的方式:跟他启动的组件同生共死,该方法启动的服务所在进程不属于服务进程

    startService:开启并创建一个服务,服务长期运行在后台;
    bindService:绑定服务,可以调用服务里面的方法;
    unBindService:解除服务,停止服务里面的方法;
    stopService:停止服务,销毁服务对象;

    为什么要引入bindservice的API?

    为了调用服务中的业务逻辑方法。

    绑定服务调用服务方法的过程

    通过bindservice方式实现调用服务里面业务逻辑方法:
    步骤:

    1、在服务类中创建一个中间人MyBinder,继承了Binder,Binder实现了IBinder接口:

    public class MyBinder extends Binder{

    }

    2、在服务类里面创建了一个MyBinder的成员变量:
          private MyBinder myBinder;

    3、在MyBinder类中写一个方法用于调用服务的业务逻辑方法:
          public class MyBinder extends Binder{

          //使用中间人调用服务里的方法
          public void callMethodInService(){
                   methodInService();
           }

         }

    4、在activity中bindService时,定义了ServiceConnection,在这个连接中实现了两个方法:

                private class MyConn implements ServiceConnection {

        /**
        * 服务连接成功时调用这个方法
        */
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
                        //得到服务绑定成功后返回的中间人MyBinder对象
                        myBinder = (MyBinder) service;

         }

        /**
         * 服务断开成功时调用这个方法
         */
        @Override
         public void onServiceDisconnected(ComponentName name) {
                System.out.println("-------onServiceDisconnected-------");

         }

    }

    5、通过在activity中通过中间人调用服务的业务逻辑方法:
                myBinder.callMethodInService();

    绑定服务抽取接口(重点)

    接口(interface): 对外开放暴露的功能,但是不会暴露功能实现的细节;
    让中间人实现服务接口的目的:只对外暴露接口里面业务逻辑方法,隐藏中间人里面的其他方法;

    步骤:

    1、创建一个服务的接口类,里面包含需要对外暴露的业务逻辑方法:
    public interface IService {
      public void callMethodInService();
    }

    2、让服务中的中间人实现了服务的接口类:
      private class MyBinder extends Binder implements IService{

      //(实现服务接口中的方法)使用中间人调用服务里的方法
      public void callMethodInService(){
        methodInService();
        }
      }

    3、在activity中声明接口的成员变量:
      private IService myBinder;

    4、强制转换成服务的接口类型
      private class MyConn implements ServiceConnection {

      /**
      * 服务连接成功时调用这个方法
      */
      @Override
      public void onServiceConnected(ComponentName name, IBinder service) {
        //强制转换成服务的接口类型
        myBinder = (IService) service;
      }

    5、在activity中通过接口的成员变量调用服务的业务逻辑方法:
      public void call(View view){
        myBinder.callMethodInService();

      }

    案例:在activity里面不能直接去调用服务中的方法,所以要想调用服务里面的方法必须通过一个中间人,通过中间人的牵线才能去调用服务里的方法。

    PublicBusiness接口是服务LeaderService的接口类,对象暴露出中间人的业务逻辑方法QianXian(),隐藏了中间人的其他方法daMaJiang()。

    1 public interface PublicBusiness {
    2 
    3     void QianXian();
    4 }
     1 public class LeaderService extends Service {
     2 
     3     @Override
     4     public IBinder onBind(Intent intent) {
     5         // 返回一个Binder对象,这个对象就是中间人对象
     6         return new ZhouMi();
     7     }
     8 
     9     class ZhouMi extends Binder implements PublicBusiness{
    10         public void QianXian(){
    11             banZheng();//banZheng()方法是服务中的方法
    12         }
    13         
    14         public  void daMaJiang(){
    15             System.out.println("陪李处打麻将");
    16         }
    17     }
    18     
    19     public void banZheng(){
    20         System.out.println("李处帮你来办证");
    21     }
    22 }
     1 public class MainActivity extends Activity {
     2 
     3     private Intent intent;
     4     private MyServiceConn conn;
     5     PublicBusiness pb;
     6     
     7     @Override
     8     protected void onCreate(Bundle savedInstanceState) {
     9         super.onCreate(savedInstanceState);
    10         setContentView(R.layout.activity_main);
    11         intent = new Intent(this, LeaderService.class);
    12         conn = new MyServiceConn();
    13         //绑定领导服务
    14         bindService(intent, conn, BIND_AUTO_CREATE);
    15     }
    16     
    17     public void click(View v){
    18         //调用服务的办证方法
    19         pb.QianXian();
    20     }
    21 
    22     class MyServiceConn implements ServiceConnection{
    23 
    24         //连接服务成功,此方法调用
    25         @Override
    26         public void onServiceConnected(ComponentName name, IBinder service) {
    27             // TODO Auto-generated method stub
    28             pb = (PublicBusiness) service;
    29         }
    30 
    31         @Override
    32         public void onServiceDisconnected(ComponentName name) {
    33             // TODO Auto-generated method stub
    34             
    35         }
    36         
    37     }
    38     
    39 }

    两种启动方式混合使用

    用服务实现音乐播放时,因为音乐播放必须运行在服务进程中,可是音乐服务中的方法,需要被前台activity所调用,所以需要混合启动音乐服务。

    //混合调用
    //为了把服务所在进程变成服务进程
    startService(intent);//先开启服务进程------------>只是在之前的程序中多了这句代码!!!
    //为了拿到中间人对象
    bindService(intent, new MusicServiceConn(), BIND_AUTO_CREATE);//拿到中间人对象

    先startService,后bindService,销毁时先unbind,在stop。

    绑定服务的应用场景


    1、需要在后台运行一定的业务逻辑,而且需要与服务器端交互数据,都是写在服务里面的。
    2、天气预报、股票行情软件;

    利用服务注册广播接收者

    操作频繁的广播事件,如果只是在清单配置文件配置,是不生效的。需要使用代码注册才能生效;

    步骤:

    // 1、得到广播接收者的对象

    ScreenBroadCastReceiver screenReceiver = new ScreenBroadCastReceiver();

    // 2、创建一个intentFilter对象
    IntentFilter filter = new IntentFilter();

    // 3、注册接收的事件类型
    filter.addAction("android.intent.action.SCREEN_ON");
    filter.addAction("android.intent.action.SCREEN_OFF");

    // 4、注册广播接收者
    this.registerReceiver(screenReceiver, filter);

    远程服务aidl的写法(重点)

    本地服务:写在自己的应用程序的工程里的服务 ,使用自己应用程序的进程运行这个服务;

    远程服务:写在别的应用程序的工程里的服务,使用别的应用程序的进程运行这个服务(安装在同一个手机上的应用程序);

    IPC: Inter Process Communication(进程间的通讯);

    aidl: Android Interface definition language 安卓接口定义语言;安卓接口语言作用是用于跨进程间通信。
    aidl的接口类里面不需要public 、protected、private 等修饰符,默认是公开共享;


    步骤:

    1、创建一个服务的接口类,里面包含需要对外暴露的业务逻辑方法

    2、让服务中的中间人实现了服务的接口类

    3、修改并拷贝接口文件

    4、在本地服务的工程中的activity里,绑定服务
    5、通过接口调用远程服务的方法

  • 相关阅读:
    页面加载完成前的loading加载效果
    javascript数组常用的遍历方法
    JavaScript的值传递和引用传递
    操作iframe的一些方法
    函数依赖与数据库范式
    微信分享到朋友圈
    计算机原理基础-原反补
    async eachSeries如何按序列执行下去
    使用 VLOOKUP、INDEX 或 MATCH 查找值
    编码问题
  • 原文地址:https://www.cnblogs.com/ahu-lichang/p/6613847.html
Copyright © 2020-2023  润新知