Android - 绑定服务调用服务里面的方法,start/bind开启服务的比较,混合方式开启服务,本地服务,远程服务,系统服务,录音API

时间:2021-09-05 06:27:43

1.服务

  • startService()

    缺陷: 我们不可以调用服务的方法, 不可以与服务进行通信.

  • bindService() 绑定服务

    可以间接的调用到服务里面的方法, 可以与服务进行通信.

2.为什么不能通过new Service()来调用服务里面的方法

服务是系统new出来的,系统new出来之后会把上下文为什么准备好,我们自己去new的Service和系统new的Service不是同一个对象,拿不到上下文

3.通过什么方式来调用服务里的方法

Android中提供了调用服务里的方法的解决方案,就是要获取到服务的代理

4.服务返回其代理

  1. 服务通过onBind()方法返回代理,其返回值是一个IBinder的实现类

    @Override
    public IBinder onBind(Intent intent) {
    System.out.println("服务被绑定了, 返回IBinder的中间人");
    return new MyBinder();
    }
  2. 创建一个IBinder的实现类,IBinder是一个接口,实现该接口我们需要实现里面所有的方法,非常不方便,系统为我们提供了一个方便的实现类Binder,让该类继承Binder,我们就可以提供代理方法了

    public class MyBinder extends Binder{

    public void callMethodInService(String name){
    methodInService(name);
    }

    }

5.绑定服务获得其代理,调用服务里的方法

public class MainActivity extends Activity {

//代理人
private MyBinder myBinder;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

//绑定服务获取中间人
public void bind(View view){
//2. 要绑定哪个Service
Intent intent = new Intent(this,TestService.class);

//1. 绑定Service
//intent 要绑定哪个Service
//conn 通讯频道,通过该conn来获取服务的代理
//BIND_AUTO_CREATE如果服务不存在,会把服务创建出来.
bindService(intent, new MyConn(), BIND_AUTO_CREATE);
}

//3. 创建通讯频道
private class MyConn implements ServiceConnection{

//当服务被成功连接的时候调用的方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//4. 成功连接后,得到了服务的代理对象
myBinder = (MyBinder) service;
}

//当服务失去连接的时候调用的方法.
@Override
public void onServiceDisconnected(ComponentName name) {

}
}

//通过中间人调用服务里面的方法
public void call(View view){
//5. 通过得到的代理对象,调用服务里的方法
myBinder.callMethodInService("小华华", 250);
}
}

6.绑定服务调用服务方法的步骤

  1. 编写服务代码

    public IBinder onBind(Intent intent) {}
  2. 在服务内部定义一个代理人对象 MyBinder

    代理人对象有一个方法可以间接的调用服务内部的方法
  3. 在onbind方法里面返回代理人对象

  4. 在Activity代码采用绑定的方式连接到服务

    bindService(intent, new MyConn(),  BIND_AUTO_CREATE);
  5. 在serviceConnection的实现类里面有一个方法,获取到服务返回的代理人对象

    public void onServiceConnected(ComponentName name, IBinder service)
  6. 强制类型转换IBinder转化成 MyBinder类型

    myBinder = (MyBinder) service;
  7. 调用代理人对象的方法–间接调用了服务里面的方法.

7.绑定方式开启服务的生命周期

  • 绑定的方式开启服务,如果服务不存在, oncreate—>onbind
  • 服务的onstart和onstartcommand方法不会被执行.
  • 解除绑定服务 onunbind()—>ondetroy()
  • 多次绑定服务,服务只会被创建一次,oncreate方法只会被执行一次
  • 多次绑定服务,onbind方法不会被重复调用.
  • 在实际开发的时候,如果需要调用服务的方法,就绑定服务,只能绑定一次
  • 服务只可以被解绑一次,如果用同一个conn对象多次解绑,服务会抛出一次.

8.通过接口隐藏代码内部实现的细节

  • 学习一种代码的设计方式,如果一个内部类有多个方法,我只想暴露出其中的一部分方法时,可以通过接口将想要暴露的方法暴露出去。
  • 如果将内部类设置为public,则所有方法都暴露出去了,如果将内部类设置为private,则所有方法其他人都不能调用了
  • 具体实现方式:设置内部类为private的,将想要暴露出去的方法抽取到一个public的接口中

9.两种开启服务方式的比较

  • start的方式开启服务

    服务一旦开启,长期后台运行,服务和开启者(Activity)没有任何的关系,开启者退出了,服务还是继续在后台长期运行, 开启者(Activity)不可以调用服务里面的方法. 在系统设置界面里面可以观察到

  • bind的方式开启服务

    不求同时生,但求同时死. 如果开启者(Activity)退出了, 服务也会跟着挂掉.
    开启者(Activity)可以间接的利用中间人调用服务里面的方法.在系统设置界面看不到的.

服务如果被开启同时被绑定,服务就停不掉了.必须解除绑定服务才可以停止服务.

10.混合的方式开启服务.

  • 为了保证服务又能长期后台运行,又能调用到服务里面的方法.
  • 采用混合的方式开启服务.

请严格按照步骤编写代码:

  1. start的方式开启服务 (保证服务长期后台运行)
  2. bind的方式绑定服务 (调用服务的方法)
  3. unbind的方式解除绑定服务
  4. stop的方式停止服务

11.本地服务和远程服务

  • 本地服务 local service

    服务的代码在当前应用程序的内部

  • 远程服务 remote service

    服务的代码在另外一个应用程序里面

12.重要概念

  • 进程

    操作系统分配的独立的内存空间.

  • IPC

    inter process communication 进程间通讯

  • aidl

    android interface definition language 安卓接口定义语言

13.绑定远程服务调用服务方法的流程

  • 服务提供者

    1. 跟本地服务的代码编写是一样
    2. 远程服务的接口定义文件,将.java的后缀名修改为 —> .aidl
    3. 把接口定义文件的访问修饰符全部删除,如public、private。系统会在gen文件夹下自动为我们生成.java文件
    4. 原来代理人MyBinder,由extend Binder implemet IService修改为 –> extends IService.Stub
  • 使用服务者

    1. 先把远程服务的.aidl文件拷贝到本地应用程序的工程目录里面,包名必须一致,系统会在gen文件夹下自动为我们生成.java文件
    2. 获取到代理的iBinder对象后,通过iService = IService.Stub.asInterface(service)得到远程服务的代理对象
    3. 通过代理对象调用远程服务的方法

14.系统服务了解

  1. 系统开启后,就会开启大量的常用服务,以后其他应用想使用系统服务的时候,可以通过context.getSystemService(String 服务名)方法获取到对应的系统服务

15.监听通话状态

  1. 获取系统服务,设置通话状态监听器

    tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
    listener = new MyPhoneListener();
    tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
  2. 创建通话状态监听器

    private class MyPhoneListener extends PhoneStateListener {

    @Override
    public void onCallStateChanged(int state, String incomingNumber) {
    super.onCallStateChanged(state, incomingNumber);
    switch (state) {
    case TelephonyManager.CALL_STATE_IDLE: // 空闲状态,代表当前没有电话
    System.out.println("停止录音");
    break;
    case TelephonyManager.CALL_STATE_RINGING:// 响铃状态

    break;
    case TelephonyManager.CALL_STATE_OFFHOOK:// 通话状态
    System.out.println("通话状态,开启录音机,录音.");
    break;
    }
    }

    }
  3. 不使用的时候注销掉监听器,释放资源

    tm.listen(listener, PhoneStateListener.LISTEN_NONE);

16.录音API

  1. 开始录音

    mRecorder = new MediaRecorder();

    //从麦克风录音,VOICE_CALL可录双向的,但是法律不允许
    mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    //输出格式
    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    //文件存放位置
    mRecorder.setOutputFile("/mnt/sdcard/"+SystemClock.uptimeMillis()+".3gp");
    //音频编码方式
    mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

    try {
    mRecorder.prepare();
    } catch (Exception e) {
    System.out.println("prepare() failed");
    }

    mRecorder.start();
  2. 停止录音

    mRecorder.stop();
    mRecorder.release();
    mRecorder = null;

17.serviceMethod

Android - 绑定服务调用服务里面的方法,start/bind开启服务的比较,混合方式开启服务,本地服务,远程服务,系统服务,录音API

18.总结

  1. 服务(Service)
    1. 通过什么方式调用服务中的方法
    2. 创建服务的代理,将服务中的方法暴露出去
    3. 绑定服务,调用服务中的方法
    4. 通过接口隐藏代码内部实现细节
    5. 绑定服务的生命周期
    6. startService和bindService两种开启服务方式的区别
    7. 如何保证服务又能长期后台运行,又能调用到服务里面的方法
    8. 本地服务和远程服务的区别
    9. 进程、IPC、AIDL
    10. 绑定远程服务,调用服务中的方法
    11. 系统服务了解,如何使用系统提供的服务
    12. 使用系统服务的案例——监听通话状态,进行录音