在Android系統中實現AIDL 自定義物件傳遞
今天要在《在Android系統中實現AIDL介面回撥》這篇文章的基礎上實現AIDL自定義物件的傳遞功能。還是上一篇說到的三個專案:
├── SimpleJar ├── SimpleJarClient └── SimpleJarService
一、在SimpleJar專案中新增aidl中要傳遞的物件StudentInfo.aidl跟StudentInfo.java,具體如下:
├── Android.mk └── src └── com └── china └── jar ├── IVoiceCallBackInterface.aidl ├── IVoiceClientInterface.aidl ├── StudentInfo.aidl ├── StudentInfo.java ├── VoiceChangedListener.java └── VoiceManager.java StudentInfo.aidl跟StudentInfo.java的程式碼實現如下:
package com.china.jar;
parcelable StudentInfo;
package com.china.jar; import android.os.Parcel; import android.os.Parcelable; public class StudentInfo implements Parcelable{ String name; int age; protected StudentInfo(Parcel in){ name = in.readString(); age = in.readInt(); } public StudentInfo(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeInt(age); } public static final Creator<StudentInfo> CREATOR = new Creator<StudentInfo>() { @Override public StudentInfo createFromParcel(Parcel in) { return new StudentInfo(in); } @Override public StudentInfo[] newArray(int size) { return new StudentInfo[size]; } }; }
由於是跨程序之間的通訊,所以傳遞物件需要序列化,讓StudentInfo實現Parcelable。這樣就可以在IVoiceClientInterface.aidl中使用StudentInfo物件進行資料傳遞了,如下:
package com.china.jar; import com.china.jar.IVoiceCallBackInterface; import com.china.jar.StudentInfo; interface IVoiceClientInterface{ void face(); void registerCallBack(IVoiceCallBackInterface callback); void unRegisterCallBack(IVoiceCallBackInterface callback); void registerUser(in StudentInfo studentInfo); }
二、在SimpleJarService專案的SimpleService.java類中實現 registerUser(in StudentInfo studentInfo)方法,具體實現如下:
├── AndroidManifest.xml ├── Android.mk ├── libs │ ├── android-support-v4.jar │ ├── fw.jar │ └── simple.jar ├── res │ ├── drawable-hdpi │ │ └── ic_launcher.png │ ├── drawable-ldpi │ ├── drawable-mdpi │ │ └── ic_launcher.png │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ ├── layout │ ├── values │ │ ├── strings.xml │ │ └── styles.xml │ ├── values-v11 │ │ └── styles.xml │ └── values-v14 │ └── styles.xml └── src └── com └── china └── service ├── BootReceiverBroadcast.java ├── Logger.java ├── SimpleControl.java └── SimpleService.java
package com.china.service;
import com.china.jar.IVoiceCallBackInterface;
import com.china.jar.IVoiceClientInterface;
import com.china.jar.StudentInfo;
import com.china.jar.VoiceChangedListener;
import com.china.jar.VoiceManager;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
public class SimpleService extends Service{
private static VoiceClientInterfaceImpl mBinder;
@Override
public IBinder onBind(Intent intent) {
Logger.d();
return mBinder;//跟客戶端繫結
}
@Override
public void onCreate() {
super.onCreate();
Logger.d();
if (null == mBinder){
initService();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Logger.d();
if (null == mBinder){
initService();
}
return START_STICKY;
}
//實現AIDL的介面
private class VoiceClientInterfaceImpl extends IVoiceClientInterface.Stub{
protected RemoteCallbackList<IVoiceCallBackInterface> mRemoteCallbackList =
new RemoteCallbackList<IVoiceCallBackInterface>();
private SimpleControl control;
public VoiceClientInterfaceImpl(){
control = new SimpleControl(voiceChangedListener);
}
@Override
public void face() throws RemoteException {
Logger.d("face----excute!");//客戶端呼叫face方法時這裡會執行,會列印face----excute!
}
//註冊回撥
@Override
public void registerCallBack(IVoiceCallBackInterface arg0)
throws RemoteException {
Logger.d();
mRemoteCallbackList.register(arg0);
}
//登出回撥
@Override
public void unRegisterCallBack(IVoiceCallBackInterface arg0)
throws RemoteException {
Logger.d();
mRemoteCallbackList.unregister(arg0);
}
//呼叫回撥方法
private VoiceChangedListener voiceChangedListener = new VoiceChangedListener() {
@Override
public void openAppByVoice(String arg0) {
Logger.d("arg0 = " + arg0);
int len = mRemoteCallbackList.beginBroadcast();
for (int i = 0; i <len; i++) {
try {
mRemoteCallbackList.getBroadcastItem(i).openAppByVoice(arg0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
mRemoteCallbackList.finishBroadcast();
}
};
@Override
public void registerUser(StudentInfo studentInfo) throws RemoteException {
Logger.d("name = " + studentInfo.getName() + " ,age = " + studentInfo.getAge());
}
}
//初始化服務,主要是向系統註冊服務
private void initService(){
Logger.d();
if (null == mBinder){
synchronized (SimpleService.class) {
if (null == mBinder){
try {
mBinder = new VoiceClientInterfaceImpl();
ServiceManager.addService(VoiceManager.NAME, mBinder);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
registerUser(in StudentInfo studentInfo)方法體中實現非常簡單,就是列印學生姓名跟年齡。
三、在SimpleJarClient專案中呼叫registerUser(in StudentInfo studentInfo)方法,進行自定義物件的資料傳遞,如下:
├── AndroidManifest.xml ├── Android.mk ├── libs │ └── simple.jar ├── res │ ├── drawable-hdpi │ │ └── ic_launcher.png │ ├── drawable-ldpi │ ├── drawable-mdpi │ │ └── ic_launcher.png │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ ├── drawable-xxhdpi │ │ └── ic_launcher.png │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_tss.xml │ │ ├── test.xml │ │ ├── usb.xml │ │ └── version.xml │ ├── menu │ ├── values │ │ ├── dimens.xml │ │ └── strings.xml │ ├── values-v11 │ ├── values-v14 │ └── values-w820dp │ └── dimens.xml └── src └── com └── example └── helloworld ├── TestVoice.java ├── UsbTest.java └── util ├── Logger.java └── USBUtil.java
package com.example.helloworld;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import com.china.jar.StudentInfo;
import com.china.jar.VoiceChangedListener;
import com.china.jar.VoiceManager;
import com.example.helloworld.util.Logger;
public class TestVoice extends Activity{
VoiceManager voiceManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.version);
voiceManager = VoiceManager.getInstance();
if (voiceManager != null){
voiceManager.addVoiceChangedListener(new VoiceChangedListener() {//客戶端的監聽及實現
@Override
public void openAppByVoice(String arg0) {
Logger.d("packageName = " + arg0);
}
});
}
voiceManager.registerUser(new StudentInfo("趙敏", 18));//aidl中客戶端傳遞自定義物件StudentInfo到服務端
}
public void startVoice(View view){
Logger.d();
Intent intent = new Intent();
intent.setClass(TestVoice.this, UsbTest.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
public void stopVoice(View view){
Logger.d();
VoiceManager.getInstance().face();
}
public void finishVoice(View view){
Logger.d();
finish();
}
}
四、執行結果如下: