本帖最后由 小鲁哥哥 于 2016-12-4 15:17 编辑
【济南中心】Android课程同步笔记day08:Android应用开发基础
通过Bind方式来调用服务里的方法
Android中提供了调用服务里的方法的解决方案,就是要获取到服务的代理
服务返回其代理服务通过onBind()方法返回代理,其返回值是一个IBinder的实现类[Java] 纯文本查看 复制代码 @Override
public IBinder onBind(Intent intent) {
//绑定服务, 返回IBinder的中间人[/align][align=left] return new MyBinder();
} 创建一个IBinder的实现类,IBinder是一个接口,实现该接口我们需要实现里面所有的方法,非常不方便,系统为我们提供了一个方便的实现类Binder,让该类继承Binder,我们就可以提供代理方法了 [Java] 纯文本查看 复制代码 public class MyBinder extends Binder{
public void callMethodInService(String name){
methodInService(name);
}
}
绑定服务获得其代理,调用服务里的方法
[Java] 纯文本查看 复制代码 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){
//1. 绑定Service
//intent 要绑定哪个Service
//conn 通讯频道,通过该conn来获取服务的代理
//BIND_AUTO_CREATE如果服务不存在,会把服务创建出来.
//2. 要绑定哪个Service
Intent intent = new Intent(this,TestService.class);
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);
}
}
绑定服务调用服务方法的步骤
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. 调用代理人对象的方法--间接调用了服务里面的方法
通过接口隐藏代码内部实现的细节
学习一种代码的设计方式,如果一个内部类有多个方法,我只想暴露出其中的一部分方法时,可以通过接口将想要暴露的方法暴露出去。
如果将内部类设置为public,则所有方法都暴露出去了,如果将内部类设置为private,则所有方法其他人都不能调用了
具体实现方式:设置内部类为private的,将想要暴露出去的方法抽取到一个public的接口中
绑定方式开启服务的生命周期
1. 绑定的方式开启服务:如果服务不存在,执行onCreate()--->onBind(),不会执行onStart()和onStartCommand()方法
2. 解除绑定服务:会执行onUnbind()--->onDetroy()
3. 多次绑定服务:服务只会被创建一次,onCreate()方法只会被执行一次,onBind()方法也只会执行一次
4. 在实际开发的时候,如果需要调用服务的方法,就绑定服务,只能绑定一次。多次绑定会导致解绑时onUnbind()方法不会调用,并且第二次解绑会导致程序异常
两种开启服务方式的比较
1. start的方式开启服务
* 服务一旦开启,长期后台运行,服务和开启者(Activity)没有任何的关系,开启者退出了,服务还是继续在后台长期运行
* 开启者(Activity)不可以调用服务里面的方法
* 在系统设置界面里面可以观察到
2. bind的方式开启服务
* 如果开启者(Activity)退出了,服务也会跟着挂掉
* 开启者(Activity)可以间接的利用中间人调用服务里面的方法
* 在系统设置界面看不到的.
3. 服务如果被开启同时被绑定,服务就停不掉了,必须解除绑定服务才可以停止服务
混合的方式开启服务
为了保证服务又能长期后台运行,又能调用到服务里面的方法,采用混合的方式开启服务.
请严格按照以下步骤编写代码:
1. start的方式开启服务 (保证服务长期后台运行)
2. bind的方式绑定服务 (可调用服务的方法)
3. unbind的方式解除绑定服务
4. stop的方式停止服务
本地服务和远程服务
本地服务 local service :服务的代码在当前应用程序的内部
远程服务 remote service :服务的代码在另外一个应用程序里面
进程 :操作系统分配的独立的内存空间.
IPC :inter process communication 进程间通讯
aidl : android interface definition language 安卓接口定义语言
绑定远程服务调用服务方法的流程
服务提供者
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. 通过代理对象调用远程服务的方法
监听通话状态
1. 获取系统服务,设置通话状态监听器
[Java] 纯文本查看 复制代码 tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
listener = new MyPhoneListener();
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
2. 创建通话状态监听器
[Java] 纯文本查看 复制代码 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. 不使用的时候注销掉监听器,释放资源
[Java] 纯文本查看 复制代码 tm.listen(listener, PhoneStateListener.LISTEN_NONE);
录音API
1. 开始录音
[Java] 纯文本查看 复制代码 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. 停止录音
[Java] 纯文本查看 复制代码 mRecorder.stop();
mRecorder.release();
mRecorder = null;
|