1.服务
-
startService()
缺陷: 我们不可以调用服务的方法, 不可以与服务进行通信.
-
bindService() 绑定服务
可以间接的调用到服务里面的方法, 可以与服务进行通信.
2.为什么不能通过new Service()来调用服务里面的方法
服务是系统new出来的,系统new出来之后会把上下文为什么准备好,我们自己去new的Service和系统new的Service不是同一个对象,拿不到上下文
3.通过什么方式来调用服务里的方法
Android中提供了调用服务里的方法的解决方案,就是要获取到服务的代理
4.服务返回其代理
-
服务通过onBind()方法返回代理,其返回值是一个IBinder的实现类
@Override
public IBinder onBind(Intent intent) {
System.out.println("服务被绑定了, 返回IBinder的中间人");
return new MyBinder();
} -
创建一个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.绑定服务调用服务方法的步骤
-
编写服务代码
public IBinder onBind(Intent intent) {}
-
在服务内部定义一个代理人对象 MyBinder
代理人对象有一个方法可以间接的调用服务内部的方法
在onbind方法里面返回代理人对象
-
在Activity代码采用绑定的方式连接到服务
bindService(intent, new MyConn(), BIND_AUTO_CREATE);
-
在serviceConnection的实现类里面有一个方法,获取到服务返回的代理人对象
public void onServiceConnected(ComponentName name, IBinder service)
-
强制类型转换IBinder转化成 MyBinder类型
myBinder = (MyBinder) service;
调用代理人对象的方法–间接调用了服务里面的方法.
7.绑定方式开启服务的生命周期
- 绑定的方式开启服务,如果服务不存在, oncreate—>onbind
- 服务的onstart和onstartcommand方法不会被执行.
- 解除绑定服务 onunbind()—>ondetroy()
- 多次绑定服务,服务只会被创建一次,oncreate方法只会被执行一次
- 多次绑定服务,onbind方法不会被重复调用.
- 在实际开发的时候,如果需要调用服务的方法,就绑定服务,只能绑定一次
- 服务只可以被解绑一次,如果用同一个conn对象多次解绑,服务会抛出一次.
8.通过接口隐藏代码内部实现的细节
- 学习一种代码的设计方式,如果一个内部类有多个方法,我只想暴露出其中的一部分方法时,可以通过接口将想要暴露的方法暴露出去。
- 如果将内部类设置为public,则所有方法都暴露出去了,如果将内部类设置为private,则所有方法其他人都不能调用了
- 具体实现方式:设置内部类为private的,将想要暴露出去的方法抽取到一个public的接口中
9.两种开启服务方式的比较
-
start的方式开启服务
服务一旦开启,长期后台运行,服务和开启者(Activity)没有任何的关系,开启者退出了,服务还是继续在后台长期运行, 开启者(Activity)不可以调用服务里面的方法. 在系统设置界面里面可以观察到
-
bind的方式开启服务
不求同时生,但求同时死. 如果开启者(Activity)退出了, 服务也会跟着挂掉.
开启者(Activity)可以间接的利用中间人调用服务里面的方法.在系统设置界面看不到的.
服务如果被开启同时被绑定,服务就停不掉了.必须解除绑定服务才可以停止服务.
10.混合的方式开启服务.
- 为了保证服务又能长期后台运行,又能调用到服务里面的方法.
- 采用混合的方式开启服务.
请严格按照步骤编写代码:
- start的方式开启服务 (保证服务长期后台运行)
- bind的方式绑定服务 (调用服务的方法)
- unbind的方式解除绑定服务
- stop的方式停止服务
11.本地服务和远程服务
-
本地服务 local service
服务的代码在当前应用程序的内部
-
远程服务 remote service
服务的代码在另外一个应用程序里面
12.重要概念
-
进程
操作系统分配的独立的内存空间.
-
IPC
inter process communication 进程间通讯
-
aidl
android interface definition language 安卓接口定义语言
13.绑定远程服务调用服务方法的流程
-
服务提供者
- 跟本地服务的代码编写是一样
- 远程服务的接口定义文件,将.java的后缀名修改为 —> .aidl
- 把接口定义文件的访问修饰符全部删除,如public、private。系统会在gen文件夹下自动为我们生成.java文件
- 原来代理人MyBinder,由extend Binder implemet IService修改为 –> extends IService.Stub
-
使用服务者
- 先把远程服务的.aidl文件拷贝到本地应用程序的工程目录里面,包名必须一致,系统会在gen文件夹下自动为我们生成.java文件
- 获取到代理的iBinder对象后,通过iService = IService.Stub.asInterface(service)得到远程服务的代理对象
- 通过代理对象调用远程服务的方法
14.系统服务了解
- 系统开启后,就会开启大量的常用服务,以后其他应用想使用系统服务的时候,可以通过context.getSystemService(String 服务名)方法获取到对应的系统服务
15.监听通话状态
-
获取系统服务,设置通话状态监听器
tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
listener = new MyPhoneListener();
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE); -
创建通话状态监听器
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;
}
}
} -
不使用的时候注销掉监听器,释放资源
tm.listen(listener, PhoneStateListener.LISTEN_NONE);
16.录音API
-
开始录音
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(); -
停止录音
mRecorder.stop();
mRecorder.release();
mRecorder = null;
17.serviceMethod
18.总结
- 服务(Service)
- 通过什么方式调用服务中的方法
- 创建服务的代理,将服务中的方法暴露出去
- 绑定服务,调用服务中的方法
- 通过接口隐藏代码内部实现细节
- 绑定服务的生命周期
- startService和bindService两种开启服务方式的区别
- 如何保证服务又能长期后台运行,又能调用到服务里面的方法
- 本地服务和远程服务的区别
- 进程、IPC、AIDL
- 绑定远程服务,调用服务中的方法
- 系统服务了解,如何使用系统提供的服务
- 使用系统服务的案例——监听通话状态,进行录音