Android10
需求_调用服务的方法
在Activity里面直接调用Service里面的方法,直接调用时行不通的.
Activity和Service 是Context的子类,不能被new,是系统框架得到的.
绑定服务调用服务方法的原理
在服务里面创建内部类,间接的去调用服务里面的方法
- 绑定服务,得到中间人的对象, onBind()方法[MyBinder对象]
- MyBinder对象,就是服务内部类的对象(中间人的对象)
- 可以拿中间人的对象,调用中间人内部类的方法
- 而内部类的方法,可以去调用外部类的方法
- 间接的调用到了,外部类方法,服务里面的方法数据了
服务内部代码的编写
public class TestService extends Service {
/**
* 服务内部的中间人
*/
public class MyBinder extends Binder {
/**
* 中间人帮忙简介的调用服务的方法.
* @param name 姓名
* @param money 钱
*/
public void callMethodInService(String name, int money) {
if (money > 200) {
methodInService(name);
} else {
Toast.makeText(TestService.this, "这点钱不够用,我们要按照制度办事", 0).show();
}
}
}
// 在服务成功绑定的时候 返回服务中的代理人(中间人)
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
@Override
public void onCreate() {
System.out.println("服务被创建了..");
super.onCreate();
}
@Override
public void onDestroy() {
System.out.println("服务被销毁了..");
super.onDestroy();
}
/**
* 服务内部的方法,帮助你办暂住证.
* @param name 姓名
*/
public void methodInService(String name) {
Toast.makeText(this, name + "你的暂住证办好了...", 0).show();
}
}
绑定服务调用服务方法
/**
* 代理人
*/
private MyBinder myBinder;
/**
* 绑定服务获取中间人
*/
public void bind(View view) {
Intent intent = new Intent(this, TestService.class);
// conn 通讯频道. BIND_AUTO_CREATE如果服务不存在,会把服务创建出来.
bindService(intent, new MyConn(), BIND_AUTO_CREATE);
}
private class MyConn implements ServiceConnection {
// 当服务被成功连接的时候调用的方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (MyBinder) service;
}
// 当服务失去连接的时候调用的方法.
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
/**
* 通过中间人调用服务里面的方法
*/
public void call(View view) {
myBinder.callMethodInService("小XX", 250);
}
}
绑定服务调用方法的回顾
服务端
public IBinder onBind(Intent intent) {
return new MyBinder();
}
public class MyBinder extends Binder{
//自定义一个方法调用methodInService
public void CallMethodInService(String name , int money){
if (money >100) {
methodInService(name);
}else{
Toast.makeText(TestService.this, name + "钱太少了,办不了暂住证", 0).show();
}
}
}
Activity端
-----------------------------------------
Intent intent = new Intent(this, TestService.class);
bindService(intent, new MyConn(), BIND_AUTO_CREATE);
public class MyConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (MyBinder) service;
}
}
public void call(View view){
myBinder.CallMethodInService("sam", 10);
}
通过接口隐藏代码内部实现的细节
public interface IService {
public void callMethodInService(String name,int money);
}
//private 和 implements IService{
private class MyBinder extends Binder implements IService{
public void callMethodInService(String name, int money) {
if (money > 200) {
methodInService(name);
}else{
Toast.makeText(TestService.this, "这点钱不够用,我们要按照制度办事", 0).show();
}
}
public void 洗桑拿(){
Toast.makeText(TestService.this, "走,一起去洗桑拿吧...", 0).show();
}
public void 打麻将(){
Toast.makeText(TestService.this, "走,一起去打麻将吧...", 0).show();
}
}
-------------------------------------------------------
private IService myBinder;
private class MyConn implements ServiceConnection{
//当服务被成功连接的时候调用的方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (IService) service;
}
//当服务失去连接的时候调用的方法.
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
public void call(View view){
myBinder.callMethodInService("XXX", 250);
}
绑定服务的生命周期
- 绑定的方式开启服务,如果服务不存在,先执行onCreate在执行onbind
- 服务的onstart和onstartcommand方法不会被执行
- 解除绑定服务,先执行onunbind在执行ondetroy
- 多次绑定服务,服务只会被创建一次,oncreate方法只会被执行一次
- 多次绑定服务,onBind方法不会被重复调用
- 在实际开发的时候,如果需要调用服务的方法,就绑定服务,只能绑定一次
- 服务只可以被解绑一次,如果用同一个conn对象多次解绑,服务和抛出异常
两种开启服务方式比较
start的方式开启服务器
服务一旦开启,长期后台运行,服务和开启者(Activity)没有任何的关系,开启者退出了,服务还是继续在后台长期运行,开启者(Activity)不可以调用服务里面的方法,在系统设置界面可以观察到
bind的方式开启服务
不求同时生,但求同时死,如果开启者(Activity)退出了,服务也会跟者挂掉,
开启者(Activity)可以间接的利用中间人调用服务里面的方法.在系统设置界面看不到的
服务如果被开启同时被绑定,服务就停不掉了.必须解除绑定才可以停止服务
混合调用服务的生命周期
- 为了保证服务又能长期后台运行,又能调用到服务里面的方法
- 采用混合的方式开启服务
按照步骤编写代码:
- start的方式开启服务(保证服务长期后台运行)
- bind的方式绑定服务(调用服务的方法)
- unbind的方式解除绑定服务
- stop的方式停止服务
本地服务和远程服务
进程
操作系统分配的独立的内存空间
IPC
inter process communication 进程间通讯
aidl
android interface definition language 安卓接口定义语言
aidl的编写步骤
- 跟本地服务的代码是一样
- 远程服务的接口的定义文件.java—>.aidl
- 把接口定义文件的访问修饰符全部删除 public private
- 原来代理人MyBinder extend Binder implement IService —>:extend IService.Stub
- 先把远程服务.AIDL文件拷贝到本地应用程序的工程目录里面,包名一致
- IService = IService.Stub.asInterface(service);得到远程服务的代理对象
- 通过代理对象调用远程服务的方法
绑定远程服务的应用场景
- 捕鱼游戏
支付宝
bindService(intent, conn, BIND_AUTO_CREATE); iService = IService.Stub.asInterface(service);
支付宝安全支付案例
private class MyBinder extends IAlipayService.Stub{
@Override
public int callSafePay(String username, String password, float money) {
return safePay(username, password, money);
}
}
public int safePay(String username ,String password , float money){
if ("zhangsan".equals(username) && "123".equals(password)) {
if (money < 500) {//余额只有500元
return 200;
} else {
return 250;
}
} else {
return 404;
}
}
<service android:name="com.xxx.newswork.service.AlipayService" ><!-- 远程项目调用服务 -->
<intent-filter >
<action android:name="com.xxx.alipay"/>
</intent-filter>
</service>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alipay);
//得到远程服务的代理人iAlipayService
Intent intent = new Intent();
intent.setAction("com.heima.alipay");
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iAlipayService = IAlipayService.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, BIND_AUTO_CREATE);
}
public void buyBall(View view){
//买炮弹
try {
int result = iAlipayService.callSafePay("zhangsan", "123", 800);//买个100元的炮弹
switch (result) {
case 200:
Toast.makeText(this, "支付成功", 0).show();
break;
case 250:
Toast.makeText(this, "卡上余额不足", 0).show();
break;
case 404:
Toast.makeText(this, "账号或者密码不正确", 0).show();
break;
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
系统服务
- 普通的服务(startService) ,activity想去调用服务的方法
- 绑定的服务(bindService),一个应用程序需要调用另一个应用程序的服务
- 远程的服务AIDL,系统服务对象 = context.getSystemService(系统服务)
- 系统的服务
利用系统服务监听通话的状态
private class MyPhoneListener extends PhoneStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE: // 空闲状态,代表当前没有电话
if (mRecorder != null) {
System.out.println("停止录音");
stopRecording();
}
break;
case TelephonyManager.CALL_STATE_RINGING:// 响铃状态
break;
case TelephonyManager.CALL_STATE_OFFHOOK:// 通话状态
System.out.println("通话状态,开启录音机,录音.");
startRecording();
break;
}
}
通话录音
/**
* 开始录音
*/
private void startRecording() {
mRecorder = new MediaRecorder();
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();
}
/**
* 停止录音
*/
private void stopRecording() {
mRecorder.stop();
mRecorder.release();
mRecorder = null;
}