AIDL (Android Interface Definition Language)
近期做了一個進程間通信的需求,這里總結一下送挑。具體的需求是這樣的:
B應用在詳情頁需要調起A應用的播放功能柿祈,但播放地址是必須在播放器頁面再去獲取的哈误,但A應用不能調取B應用的請求,只能通過B應用中的請求拿到播放地址傳給A應用躏嚎,A然后進行播放蜜自。
- 這里就需要用到進程間通信(icp:inter process communication:內部進程通信。)了卢佣。 業(yè)務邏輯大體如下:B在詳情頁點擊播放的時候通過普通的Intent或者scheme方式調起A應用對應的activity重荠,之后A應用會啟動B中定義的service,然后通過aidl的方法傳遞請求參數數據到B中虚茶,B拿到請求參數后起線程獲取播放地址戈鲁,然后回傳給A應用尾膊,A拿到播放地址后再進行播放。
流程圖如下(B應用就叫main應用荞彼,A應用就叫l(wèi)ite應用):
- 下面是具體實現:
1.先在main應用中建立對應的aidl文件冈敛,
這樣會在我們包名下建出aidl文件,這時鸣皂,我們需要在build下重新make project一下抓谴,這樣在build文件夾中就會生成對應的接口文件,如下圖:
這樣寞缝,我們才能在代碼中引用這個接口癌压。
這時在IRemoteService.aidl文件中,還只是默認的方法荆陆,這里我們需要加上我們自己的方法滩届,這個文件其實就是一個接口文件,所以我們只能寫上方法的定義被啼,具體的實現還得再接口的實現中完成帜消。
在IRemoteService.aidl我們加上
/**
* @param couldId 視頻id
* @param callback 獲取playurl的回調
*/String getPlayInfo(String couldId, LiteappCallback callback);
注意:上面方法中的參數LIteappCallback是又lite中需要傳給main的回調類,我們需要再次建一個aidl文件浓体,就叫LiteappCallback.aidl,代碼如下:
// LiteappCallback.aidlpackage
com.main.mainapplication;
// Declare any non-default types here with import statements
interface LiteappCallback {
/**
* 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);
//獲取url成功
void getPlayUrlSuccess(String playUrl);
//獲取url失敗
void getPlayUrlFail(String message);
}
其中兩個方法的具體實現在需要在lite應用中做的泡挺。
---別忘了添加aidl之后需要make project一下,否則你會發(fā)現在IRemoteService中用不了命浴。這里還需要注意的是娄猫,在aidl中如果引用其他aidl接口類型,需要import生闲,即使是在相同的包結構下媳溺。所以我們在IRemoteService的方法中引用LiteappCallback需要導包,在IRemoteService.aidl文件中加入import com.main.mainapplication.LiteappCallback;
至此,aidl基本定義完畢碍讯。
2.創(chuàng)建main中的service悬蔽。
這里我們創(chuàng)建叫l(wèi)iteservice的服務,其中需要實現IRemoteService冲茸。
package com.main.mainapplication.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import com.main.mainapplication.IRemoteService;
import com.main.mainapplication.LiteappCallback;
/**
* Date: 2016-04-15
* Time: 12:58
* Description: FIXME
*/
public class LiteService extends Service{
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { }
@Override
public String getPlayInfo(String couldId, LiteappCallback callback) throws RemoteException {
requestPlayUrl(couldId, callback);
return "http://";
}
};
private void requestPlayUrl(String couldId, LiteappCallback callback) { //TODO 進行異步操作
//在異步請求里如果成功執(zhí)行callback.getPlayUrlSuccess(playurl); //如果失敗之執(zhí)行callback.getPlayUrlFail(message);
}
}
其中具體的異步請求就不寫了屯阀,總之會回調callback的兩個方法缅帘。由于是異步的處理轴术,所以這里getPlayInfo方法的直接返回結果并沒有什么卵用。
別忘了我們需要在main應用的清單文件中注冊service:
<service android:name="com.main.mainapplication.service.LiteService">
<intent-filter>
<action android:name="com.main.mainapplication.intent.action.FORURL"/>
</intent-filter>
</service>
這里采用隱式的調起方式钦无。
3.回到lite應用中
首先需要將main中創(chuàng)建的aidl文件copy到lite中逗栽,這里需要注意的是aidl的包名也一并copy過來:
同樣需要make project生成對應接口文件。
由于只是事例代碼失暂,所以我就寫在liteApplication的MainActivity中了彼宠,
private IRemoteService mRemoteService;
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mRemoteService = IRemoteService.Stub.asInterface(service);
System.out.println("bind success" + mRemoteService.toString());
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private final LiteappCallback.Stub callback = new LiteappCallback.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public void getPlayUrlSuccess(String playUrl) throws RemoteException {
System.out.println("playUrl: " + playUrl);
}
@Override
public void getPlayUrlFail(String message) throws RemoteException {
System.out.println("message: " + message);
}
};
這里是先創(chuàng)建ServiceConnection鳄虱,并且實現LiteappCallback接口,getPlayUrlSuccess功能只是打印該url凭峡。這個方法會在main應用中的異步處理中調用拙已。
這里就直接在mainactivity的oncreate方法中綁定服務了,場景不一樣摧冀,需要另外處理:
Intent intent = new Intent("com.main.mainapplication.intent.action.FORURL");
intent.setPackage("com.main.mainapplication");
System.out.println("開始bind");
bindService(intent, conn, Context.BIND_AUTO_CREATE);
這里注意:Android 5.0一出來后倍踪,其中有個特性就是Service Intent must be explitict,也就是說從Lollipop開始索昂,service服務必須采用顯式意圖方式啟動.解決辦法就是增加intent.setPackage("com.main.mainapplication");
設置包名建车。才可以綁定service。然后在需要的地方直接調用getPlayInfo方法椒惨。
try {
mRemoteService.getPlayInfo("23456789", callback);
} catch (RemoteException e) {
e.printStackTrace();
}
此時缤至,同一個手機上都裝了main應用和lite應用后,main應用帶數據到lite之后康谆,lite通過綁定service领斥,調用getPlayInfo方法,然后會在service中異步請求獲取后調用了lite中的getPlayUrlSuccess方法后沃暗,成功在lite中拿到了main中請求的url數據戒突,然后lite中再處理播放的邏輯。
至此描睦,aidl實現基本完成膊存。