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、通过接口调用远程服务的方法

原文地址:https://www.cnblogs.com/ahu-lichang/p/6613847.html