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,所以只需要删除掉前面的修饰符就好。

Android aidl实现 android aidl详解_java

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

Android aidl实现 android aidl详解_ide_02



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

Android aidl实现 android aidl详解_java_03


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



远程访问:

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

Android aidl实现 android aidl详解_Android aidl实现_04

和上图里那个包名一样。


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


这样就把接口公开出去了。可以通过给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;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		conn = new Conn();
		findViewById(R.id.btn).setOnClickListener(new OnClickListener() {

			@Override
			public 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 {

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			isConn = true;
			// inter = (Inter) service;
			inter = Stub.asInterface(service);
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			// if(isConn){
			// unbindService(conn);
			isConn = false;
			// }
		}
	}

	@Override
	protected 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();

	@Override
	public IBinder onBind(Intent intent) {
		return mBinder;
	}

	private class MyBinder extends Stub{
		public void get02() {
			methodService02();
		}
		public void m2() {

		}

		@Override
		public 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;
	@Override
	protected 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() {
			
			@Override
			public void onClick(View v) {
				//调用远程服务中的方法
				try {
					inter.m1();
				} catch (RemoteException e) {
					e.printStackTrace();
				}
			}
		});
	}

	class Conn implements ServiceConnection{
		
		//Service连接上的时候
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			isConn = true;
			 inter = Stub.asInterface(service);
			 Toast.makeText(getApplicationContext(), "连接上了", 0).show();
		}
		
		//意外断开连接的时候
		@Override
		public void onServiceDisconnected(ComponentName name) {
				isConn =false;
		}
	}
	@Override
	protected void onDestroy() {
		
		if(isConn){
			unbindService(conn);
			isConn=false;
		}
		super.onDestroy();
	}
}


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

Android aidl实现 android aidl详解_Android aidl实现_05



其他作用:电话监听

这个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{
	//接收到广播的时候,会执行
	@Override
	public 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文件,及其包名


Android aidl实现 android aidl详解_ide_06