AIDL跨进程的服务:
Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。
为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言(Interface Definition Language,IDL)来公开服务的接口。我们知道4个Android应用程序组件中的3个(Activity、BroadcastReceiver 和ContentProvider)都可以进行跨进程访问,另外一个Android应用程序组件Service同样可以。因此,可以将这种可以跨进程访问的服务称为AIDL(Android Interface Definition Language)服务。
一,监听电话:
1.在main目录下,创建aidl目录
2.在aidl目录下,创建两个包,并复制两个文件到对应的包中,并Make Project
com.android.internal.telephony 对应的ITelephony.aidl
android.telephony 对应的NeighboringCellInfo.aidl
3.在MainActivity中,声明两个变量
private TelephonyManager tm;
private PhoneStateListener listener;
TelephonyManager 获取电话服务
PhoneStateListener 电话状态监听
4.在onCreate方法中,初始化变量
tm=(TelephonyManager) getSystemService(TELEPHONY_SERVICE);
listener=new PhoneStateListener(){
@Override
public void onCallStateChanged(int state, String incomingNumber) {
// TODO Auto-generated method stub
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:{
Log.i("info", "空闲状态");
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:{
Log.i("info", "占线状态");
}
break;
case TelephonyManager.CALL_STATE_RINGING:{
Log.i("info", "响铃状态");
Log.i("info", "来电:"+incomingNumber);
//拦截来电代码:
catComeCall();
}
break;
}
}
};
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
5.写一个拦截电话的方法
protected void catComeCall() {
// 拦截来电
try {
Method method=Class.forName("android.os.ServiceManager")
.getMethod("getService", String.class);
//获取远程TELEPHONY_SERVICE的IBinder对象的代理
IBinder iBinder=(IBinder) method.invoke(null,new Object[]{TELEPHONY_SERVICE});
//将IBinder对象的代理转换为ITelephony对象
ITelephony telephony=ITelephony.Stub.asInterface(iBinder);
//挂断电话
telephony.endCall();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
6.在Activity退出时,把监听设置为不监听
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
tm.listen(listener, PhoneStateListener.LISTEN_NONE);
}
7.权限声明
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
PROCESS_OUTGOING_CALLS 允许应用程序监听、控制、取消呼出电话的权限
READ_PHONE_STATE 读取电话状态权限
二,服务端写法:
package com.qf.xs.day24servieraidl;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
/**
* Aidl实现进程间通信的步骤:
* 服务端:
* 1.定义aidl文件,在接口中声明服务可以提供给客户端使用的方法
* 2.重构项目
* 3.定义类继承Service,重写onBind方法
* 3.1 定义一个内部类继承IXiaoHuangAidlInterface.Stub
* 3.2 实例化Stub的子类
* 3.3 在onBind方法中返回Stub的子类对象即可
*
* 4.注册到清单
*/
public class XiaoHuangService extends Service {
public XiaoHuangService() {
}
public void sing(String name) {
Log.e("print","小黄在唱歌:"+name);
}
// Stub类的原型: class Stub extends Binder implements IXiaoHuangAidlInterface
public class XiaoHuangBinder extends IXiaoHuangAidlInterface.Stub {
@Override
public void sing(String name) throws RemoteException {
XiaoHuangService.this.sing(name);
}
}
@Override
public void onCreate() {
super.onCreate();
Log.e("print", "onCreate.....");
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.e("print", "onBind.....");
return new XiaoHuangBinder();
}
@Override
public void onDestroy() {
Log.e("print", "onDestroy.....");
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("print", "onStartCommand.....");
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
Log.e("print", "onUnbind.....");
return super.onUnbind(intent);
}
}
1.在main目录下,创建aidl目录
// IXiaoHuangAidlInterface.aidl
package com.qf.xs.day24servieraidl;
// Declare any non-default types here with import statements
/**
* aidl声明的接口:
* 1.接口interface前不能加任何修饰符
* 2.接口中声明的方法不能有任何修饰符
* 3.接口中声明的方法的参数和返回值的类型是有要求的
* 支持的类型:
* 基本类型,String,
*
*
* aidl,修改后,必须重构项目,------开发工具就会自动将aidl声明的接口生成对应的java的接口
* */
interface IXiaoHuangAidlInterface {
void sing(String name);
}
2.在aidl目录中,写一个声明接口声明,并放在对应的包名下
aidl声明的接口:
1》.接口interface前不能加任何修饰符
2》.接口中声明的方法不能有任何修饰符
3》.接口中声明的方法的参数和返回值的类型是有要求的
支持的类型:
基本类型,String,
3.定义类继承Service,重写onBind方法
package com.qf.xs.day24servieraidl;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
/**
* Aidl实现进程间通信的步骤:
* 服务端:
* 1.定义aidl文件,在接口中声明服务可以提供给客户端使用的方法
* 2.重构项目
* 3.定义类继承Service,重写onBind方法
* 3.1 定义一个内部类继承IXiaoHuangAidlInterface.Stub
* 3.2 实例化Stub的子类
* 3.3 在onBind方法中返回Stub的子类对象即可
*
* 4.注册到清单
*/
public class XiaoHuangService extends Service {
public XiaoHuangService() {
}
public void sing(String name) {
Log.e("print","小黄在唱歌:"+name);
}
// Stub类的原型: class Stub extends Binder implements IXiaoHuangAidlInterface
public class XiaoHuangBinder extends IXiaoHuangAidlInterface.Stub {
@Override
public void sing(String name) throws RemoteException {
XiaoHuangService.this.sing(name);
}
}
@Override
public void onCreate() {
super.onCreate();
Log.e("print", "onCreate.....");
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.e("print", "onBind.....");
return new XiaoHuangBinder();
}
@Override
public void onDestroy() {
Log.e("print", "onDestroy.....");
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("print", "onStartCommand.....");
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
Log.e("print", "onUnbind.....");
return super.onUnbind(intent);
}
}
1》定义一个内部类继承IXiaoHuangAidlInterface.Stub
2》实例化Stub的子类
3》在onBind方法中返回Stub的子类对象即可
4.注册Service
<service
android:name=".XiaoHuangService"
android:enabled="true"
android:exported="true"><!--这里要为true 其他应用是否可以和它交互-->
<intent-filter>
<!--这个是其他应用访问该服务的的身份标识-->
<action android:name="com.xiaohuang.service"></action>
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</service>
重要:注册服务的时候,需要给服务添加一个动作(身份标识)。
三,访问端写法:
package com.qf.xs.day24aidldemo;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import com.qf.xs.day24servieraidl.IXiaoHuangAidlInterface;
/**
* Aidl客户端
* 1.创建aidl文件,必须和服务端aidl文件一模一样
* 可以直接拷贝,拷贝到项目目录/main/
*
* 2.重构项目
*
* 3.定义类实现ServiceConnection接口,重写onServiceConnected方法,
* 在这个方法中,利用Stub的asInterface方法将IBinder参数转换成接口对象
*
* 4.实例化ServiceConnection,通过调用bindService 绑定服务
*
* 5.服务连接成功,就通过接口调用服务中的方法即可
*/
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// IXiaoHuangAidlInterface asInterface(android.os.IBinder obj)
iXiaoHuangAidlInterface = IXiaoHuangAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private IXiaoHuangAidlInterface iXiaoHuangAidlInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
findViewById(R.id.start_btn).setOnClickListener(this);
findViewById(R.id.stop_btn).setOnClickListener(this);
findViewById(R.id.bind_btn).setOnClickListener(this);
findViewById(R.id.unbind_btn).setOnClickListener(this);
findViewById(R.id.invoke_btn).setOnClickListener(this);
}
@Override
public void onClick(View v) {
//3.0以后,服务的意图,必须是显式意图
// Intent intent = new Intent("com.xiaohuang.service");
Intent intent = new Intent();
ComponentName comName= new ComponentName("com.qf.xs.day24servieraidl",//包名
"com.qf.xs.day24servieraidl.XiaoHuangService");//类名
intent.setComponent(comName);
switch (v.getId()){
case R.id.start_btn:
startService(intent);
break;
case R.id.stop_btn:
stopService(intent);
break;
case R.id.bind_btn:
bindService(intent, connection,BIND_AUTO_CREATE);
break;
case R.id.invoke_btn:
try {
iXiaoHuangAidlInterface.sing("冰雨");
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.unbind_btn:
unbindService(connection);
connection = null;
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (connection != null) {
unbindService(connection);
connection = null;
}
}
}
1》复制服务端的aidl目录到main目录下,并重构:Build--make Project.
2》定义类实现ServiceConnection接口,重写onServiceConnected方法,
在这个方法中,利用Stub的asInterface方法将IBinder参数转换成接口对象
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// IXiaoHuangAidlInterface asInterface(android.os.IBinder obj)
iXiaoHuangAidlInterface = IXiaoHuangAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private IXiaoHuangAidlInterface iXiaoHuangAidlInterface;
public void onServiceConnected(ComponentName name, IBinder service) {
// IXiaoHuangAidlInterface asInterface(android.os.IBinder obj)
iXiaoHuangAidlInterface = IXiaoHuangAidlInterface.Stub.asInterface(service);
}
3》实例化ServiceConnection,通过调用bindService 绑定服务
//3.0以后,服务的意图,必须是显式意图
// Intent intent = new Intent("com.xiaohuang.service");
Intent intent = new Intent();
ComponentName comName= new ComponentName("com.qf.xs.day24servieraidl",//包名
"com.qf.xs.day24servieraidl.XiaoHuangService");//类名
intent.setComponent(comName);
bindService(intent, connection,BIND_AUTO_CREATE);
4》服务连接成功,就通过接口调用服务中的方法即可
try {
iXiaoHuangAidlInterface.sing("冰雨");
} catch (RemoteException e) {
e.printStackTrace();
}