[android]AIDL详解

来源:互联网 发布:js拼接json字符串 编辑:程序博客网 时间:2024/06/12 01:46

AIDL详解

AIDL:Android Interface Definition Language,即Android接口定义语言。

从定义上看,这个AIDL有两个特点:1、是用来定义接口的  2、是另一种“语言”,也不完全算一种语言。3、实现了远程接口

为什么有ADIL来定义接口,直接public interface不好吗?

在线程间通信的时候,用Bound Service(什么是Bound Service?先接着看。。),通过继承Binder的方式,会获得Service的实例,然后调用Service里所有的方法。的那是当有些方法不想被公开的时候,当然你可以将方法声明为private,但是倘若到后期,又需要公开这些方法,你是不是还要将声明改为public?当方法较多时,显然不符合松耦合的思想。

这时,可以将MyBinder继承Binder的类私有,用MyBinder里的方法,调用Service中的私有方法(这些方法是不公开的,但是可以通过这种方法调用)。这时候,我们如果将MyBider里的方法私有,外部就访问部了Service的方法了。

那么如何公开这些方法呢?这时候,可以声明一个接口,接口里声明想要公开的方法,然后让MyBinder extends Binder implements Inter,这样就必须要重写接口里公开的方法。

如何创建AIDL?

将上面的接口文件Inter.java拷贝到桌面,更改后缀为Inter.aidl,再把这个文件拷贝回工程里。删除原来的Inter.java。双击进去,看到有报错,这是因为接口用了public修饰,在adil语言里,没有public,所以只需要删除掉前面的修饰符就好。


工程里还会报错。因为已经没有了Inter.java,所以implements那里会报错。这时候,打开工程里的gen文件,找到Inter.java文件(自动生成的)




打开Inter.java发现,有一个Stub方法,实现了Binder和Inter。所以在



所以做如下修改即可(注释的是修改之前的),这样就不会报错,可以运行。


远程访问:

远程访问时,需要事先知道哪个接口是公开的,只需要拷贝这个文件到src文件里,但是有一个条件,那就aidl文件所在的包名必须和原来的一样。

和上图里那个包名一样。


所以要在目标工程里这么写:


这样就把接口公开出去了。可以通过给Service添加隐式意图来实现远程访问。

有什么好处?

这些东西的设计,都是为了更好的适应高内聚低耦合的思想。android整体的设计,和web那一套MVC三层架构一样,例如Broadcast,就是类UDP通信。而这里的AIDL,就实现远程(不同线程之间)的访问,这个远程访问和Activity的隐式意图启动一样,在Activity的Intent里,setAction()方法可以指定要启动的Activity。同理在Service里,startService()方法里也是传一个Intent,可以通过setAction来指定要访问的uri。然后后台在你看不到的情况下开启了一个服务。服务可以当做没有界面的Activity来理解。


一个小Demo

服务端:(在服务端的代码里,也自己访问了一次自己)

献上代码,注释没有去掉,有些地方值得思考,为什么不能那样做,又为什么可以这样写。

下面是Mainactivity

import com.example.aidldemo.Inter.Stub;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.view.View;import android.view.View.OnClickListener;public class MainActivity extends Activity {private Conn conn;private boolean isConn;private Inter inter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);conn = new Conn();findViewById(R.id.btn).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// 调用服务提供出来的方法try {inter.m1();} catch (RemoteException e) {e.printStackTrace();}}});// 绑定上Service----》调用Service提供出来的方法bindService(new Intent(MainActivity.this, Service01.class), conn,Context.BIND_AUTO_CREATE);}class Conn implements ServiceConnection {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {isConn = true;// inter = (Inter) service;inter = Stub.asInterface(service);}@Overridepublic void onServiceDisconnected(ComponentName name) {// if(isConn){// unbindService(conn);isConn = false;// }}}@Overrideprotected void onDestroy() {if (isConn) {unbindService(conn);isConn = false;}super.onDestroy();}}


下面是Service

import com.example.aidldemo.Inter.Stub;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.widget.Toast;public class Service01 extends Service {private MyBinder mBinder = new MyBinder();@Overridepublic IBinder onBind(Intent intent) {return mBinder;}private class MyBinder extends Stub{public void get02() {methodService02();}public void m2() {}@Overridepublic void m1() {//Toast.makeText(getApplicationContext(), "调用成功", 0).show();System.out.println("打印信息 服务端");}}private void methodService01() {}private void methodService02() {}}

AIDL

package com.example.aidldemo;interface Inter {void m1();}

Mainfest,在application节点下添加

       <service android:name="com.example.aidldemo.Service2406">            <intent-filter >                <action android:name="service01aidl"/>            </intent-filter>        </service>

===================================================


模拟远程客户端访问

import com.example.aidldemo.Inter;import com.example.aidldemo.Inter.Stub;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.view.View;import android.view.View.OnClickListener;import android.widget.Toast;public class MainActivity extends Activity {private Conn conn;private boolean isConn;private Inter inter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);conn = new Conn();//绑定远程方法bindService(new Intent("service01aidl"), conn, Context.BIND_AUTO_CREATE);findViewById(R.id.btn).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {//调用远程服务中的方法try {inter.m1();} catch (RemoteException e) {e.printStackTrace();}}});}class Conn implements ServiceConnection{//Service连接上的时候@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {isConn = true; inter = Stub.asInterface(service); Toast.makeText(getApplicationContext(), "连接上了", 0).show();}//意外断开连接的时候@Overridepublic void onServiceDisconnected(ComponentName name) {isConn =false;}}@Overrideprotected void onDestroy() {if(isConn){unbindService(conn);isConn=false;}super.onDestroy();}}

客户端里还有一个这个东东




其他作用:电话监听

这个AIL还可以实现电话监听,手机黑名单的制作。

权限:

    <uses-permission android:name="android.permission.CALL_PHONE"/>   <span style="white-space:pre"></span> <uses-permission android:name="android.permission.READ_PHONE_STATE"/><uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>

注册reciver节点(因为电话的信息是通过ContentProvider提供出来的)

        <receiver android:name="com.example.endcall.Reciver02">            <intent-filter >                <action android:name="android.intent.action.PHONE_STATE"/>            </intent-filter>        </receiver>

思路:通过BroadcastReciver接收信息,判断是打出去电话还是打进来电话。如果是打进来电话,判断是挂断,接通和响铃。

通过反射,获得ServiceManager的getService方法,这个方法invoke返回的是一个Binder类。通过Stub.asInterface(binder)得到了endCall的接口,进而调用endCall挂断电话。

package com.example.day24demo08endcall;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import com.android.internal.telephony.ITelephony;import com.android.internal.telephony.ITelephony.Stub;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.telephony.TelephonyManager;/*** * 监听--》电话 * 电话挂断 * 电话响铃 * 电话接通 * @author cj * */public class Receiver01 extends BroadcastReceiver{//接收到广播的时候,会执行@Overridepublic void onReceive(Context context, Intent intent) {//打进来电话的时候,挂断if(Intent.ACTION_NEW_OUTGOING_CALL.equals(intent.getAction())){//打出去电话}else{TelephonyManager manager=(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);//获取电话状态int state = manager.getCallState();//判断状态switch (state) {case TelephonyManager.CALL_STATE_IDLE://挂断break;case TelephonyManager.CALL_STATE_OFFHOOK://接通break;case TelephonyManager.CALL_STATE_RINGING://响铃--->挂断电话System.out.println("电话响了~~~");//得到ITelephony对象,调用挂断电话的方法//"android.os.ServiceManager"try {//Method[] methods = Class.forName("android.os.ServiceManager").getDeclaredMethods();////for (Method method : methods) {//System.out.println(method);//}Method method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);//执行方法IBinder ibinder=(IBinder) method.invoke(null, new Object[]{Context.TELEPHONY_SERVICE});ITelephony itelephony=Stub.asInterface(ibinder);itelephony.endCall();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (RemoteException e) {e.printStackTrace();}break;default:break;}}}}

AIDL文件,及其包名






0 0
原创粉丝点击