彻底明确Android中AIDL及其使用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了彻底明确Android中AIDL及其使用相关的知识,希望对你有一定的参考价值。

1、为什么要有AIDL?

不管学什么东西,最先得弄明确为什么要有这个东西。不要说存在即是合理。存在肯定合理,可是你还是没有明确。

对于AIDL有一些人的浅显概念就是,AIDL能够跨进程訪问其它应用程序,和其它应用程序通讯,那我告诉你。非常多技术都能够訪问,如广播(应用A在androidManifest.xml中注冊指定Action的广播)应用B发送指定Action的广播,A就能收到信息,这样也能看成不同应用之间完毕了通讯(可是这样的通讯是单向的)。还如ContentProvider,通过URI接口暴露数据给其它应用訪问;可是这样的都算不上是应用之间的通讯。

可能最让人迷惑的是Android推出来了Messager,它就是完毕应用之间的通讯的。那么为什么还要有AIDL呢。官方文档介绍AIDL中有这么一句话:

Note: Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by implementing a Binder or, if you want to perform IPC, but do not need to handle multithreading, implement your interface using a Messenger. Regardless, be sure that you understand Bound Services before implementing an AIDL.
第一句最重要,“仅仅有当你同意来自不同的client訪问你的服务而且须要处理多线程问题时你才必须使用AIDL”。其它情况下你都能够选择其它方法。如使用Messager,也能跨进程通讯。

可见AIDL是处理多线程、多client并发訪问的。而Messager是单线程处理。还是官方文档说的明确,一句话就能够理解为什么要有AIDL。那么是不是这样的写个AIDL试试。

2、AIDL使用

第一、定义AIDL文件
// IRemoteService.aidl
package com.example.android;

// Declare any non-default types here with import statements

/** Example service interface */
interface IRemoteService {
    /** Request the process ID of this service, to do evil things with it. */
    int getPid();

    /** Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}
这段代码也是官方文档的。

命名为IRemoteService.aidl。放在com.example.android包下(这个能够任意),保存后Android编译器会在gen文件夹下自己主动生成IRemoteService.java文件

第二、定义我们的服务,DDService.java,而且须要在AndroidManifest.xml中注冊,并加入“duanqing.test.aidl” 的ACTION
package com.example.service;

import com.example.android.IRemoteService;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Process;

public class DDService extends Service {
	@Override
	public void onCreate() {
		super.onCreate();
		System.out.println("DDService onCreate........" + "Thread: " + Thread.currentThread().getName());
	}
	@Override
	public IBinder onBind(Intent arg0) {
		System.out.println("DDService onBind");
		return mBinder;
	}

	private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
	    public int getPid(){
	    	System.out.println("Thread: " + Thread.currentThread().getName());
	    	System.out.println("DDService getPid ");
	        return Process.myPid();
	    }
	    public void basicTypes(int anInt, long aLong, boolean aBoolean,
	        float aFloat, double aDouble, String aString) {
	    	System.out.println("Thread: " + Thread.currentThread().getName());
	    	System.out.println("basicTypes aDouble: " + aDouble +" anInt: " + anInt+" aBoolean " + aBoolean+" aString " + aString);
	    }
	};

}

这样我们的服务端就完毕了。把服务端执行到模拟器(或者手机上)。等一会能够看一下信息打印,重点看“线程名”

第三、实现client測试代码
新建还有一个project,相同须要加入AIDL协议文件(这是一个标准的协议文件。定义对外服务),这里我列出来我的測试代码:
package com.example.aidlclient;

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.Process;
import android.os.RemoteException;
import android.view.View;

import com.example.android.IRemoteService;

public class MainActivity extends Activity {
	private IRemoteService remoteService;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    
    ServiceConnection conn = new ServiceConnection() {
		
		@Override
		public void onServiceDisconnected(ComponentName name) {
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			remoteService =	IRemoteService.Stub.asInterface(service);
			try {
				int pid = remoteService.getPid();
				int currentPid = Process.myPid();
				System.out.println("currentPID: " + currentPid +"  remotePID: " + pid);
				remoteService.basicTypes(12, 1223, true, 12.2f, 12.3, "我们的爱,我明确");
			} catch (RemoteException e) {
				e.printStackTrace();
			}
			System.out.println("bind success! " + remoteService.toString());
		}
	};
		
    /**
     * 监听按钮点击
     * @param view
     */
    public void buttonClick(View view) {
    	System.out.println("begin bindService");
    	Intent intent = new Intent("duanqing.test.aidl");
    	bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
    	super.onDestroy();
    	unbindService(conn);
    }
}
4、运行
点击clientbutton,运行。看信息打印:技术分享

看服务端打印,DDService onCreate..........Thread: main,主线程,当client调用服务端getPid方法时,服务端是在Thread: Binder2中运行,当client调用服务端basicType方法时,服务端是在Thread:Binder1中运行



以上是关于彻底明确Android中AIDL及其使用的主要内容,如果未能解决你的问题,请参考以下文章

android 怎么永久杀死进程

客户端进程(在带有aidl的android IPC中)如何知道远程服务器类?

Android AIDL使用详解_Android IPC 机制详解

Android 使用AIDL实现进程间的通信

Android设计模式之中的一个个样例让你彻底明确装饰者模式(Decorator Pattern)

Android AIDL 使用教程