Android AIDL远程服务demo

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.

第一句最重要,"只有当你允许来自不同的客户端访问你的服务并且需要处理多线程问题时你才必须使用AIDL",其他情况下你都可以选择其他方法,如使用Messager,也能跨进程通讯。可见AIDL是处理多线程、多客户端并发访问的。而Messager是单线程处理。还是官方文档说的明白,一句话就可以理解为什么要有AIDL。那么是不是这样的写个AIDL试试。

   

2、AIDL使用

第一、定义AIDL协议文件(这是一个标准的协议文件,定义对外服务)。客户端服务端包名内容都一样

// IPayServiceAidlInterface.aidl
package cqu.remoteservice;

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

interface IPayServiceAidlInterface {
/**
* 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);
void callPay();
}

   

编译后,自动生成class:

   

第二步,服务端实现Service

   

package cqu.remoteservice;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
import android.os.Process;

/**
* Created by Administrator on 2015/11/24.
*/
public class PayService extends Service {
private final String TAG = "PayService";
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG,"onBind, Thread name : "+Thread.currentThread().getName()+" process id : "+Process.myPid());
return new MyBinder();
}

class MyBinder extends IPayServiceAidlInterface.Stub{

@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
Log.d(TAG,"basicTypes, aDouble: " + aDouble + " anInt: " + anInt + " aBoolean " + aBoolean + " aString " + aString);
}

@Override
public void callPay() throws RemoteException {
Log.d(TAG,"callPay, Thread name : "+Thread.currentThread().getName()+" process id : "+Process.myPid());
}
}
}

   

第三步,服务端manifest.xml

   

<service android:name=".PayService" android:process=":remote">
<intent-filter>
<action android:name="cqu.remoteservice.PayService"></action>
</intent-filter>
</service>

   

这样我们的服务端就完成了,把服务端运行到模拟器(或者手机上),等一会可以看一下打印信息,重点看"线程名"

   

第四步,实现客户端测试代码

   

public class MainActivity extends Activity{
private final String TAG = "MyClient";
Button aidl_btn;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

aidl_btn = (Button) findViewById(R.id.aidl_btn);
aidl_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("cqu.remoteservice.PayService");
intent.setPackage("cqu.remoteservice");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
});
}

IPayServiceAidlInterface mIPayServiceAidlInterface;
private ServiceConnection mConnection = new ServiceConnection() {

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG,"onServiceConnected, Thread name:"+Thread.currentThread().getName()+" process id:"+ Process.myPid());

mIPayServiceAidlInterface = IPayServiceAidlInterface.Stub.asInterface(service);
if(null != mIPayServiceAidlInterface){
try {
mIPayServiceAidlInterface.basicTypes(1,1,true,1.1f,1.1,"Love U");
mIPayServiceAidlInterface.callPay();
} catch (RemoteException e) {
e.printStackTrace();
}
}

}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG,"onServiceDisconnected");
// mIPayServiceAidlInterface = null;
}
};

   

   

第五步,执行 点击客户端按钮,执行,看打印信息:

   

07-18 22:09:15.632 13251-13251/? D/PayService: onBind, Thread name : main process id : 13251

07-18 22:09:15.634 13377-13377/? D/MyClient: onServiceConnected, Thread name:main process id:13377

07-18 22:09:15.636 13251-13269/? D/PayService: basicTypes, aDouble: 1.1 anInt: 1 aBoolean true aString Love U

07-18 22:09:15.637 13251-13268/? D/PayService: callPay, Thread name : Binder_1 process id : 13251

   

注意:intent.setPackage("cqu.remoteservice");

不写便会报错:Service Intent must be explicit

原因:从Lollipop开始,service服务必须采用显示方式启动

posted on 2015-11-24 17:30  商声主西方之音  阅读(341)  评论(0编辑  收藏  举报

导航