Android跨程式通訊之非AIDL(二)
目錄
Android跨程式通訊之小例子(一)
Android跨程式通訊之非AIDL(二)
Android跨程式通訊之Proxy與Stub(三)
Android跨程式通訊之AIDL(四)
從最常用的例子談起
這篇文章圍繞的核心主題就是
IBinder
,或許你早就在Service
的onBind
方法中見過。該方法就是返回一個IBinder
物件。一般我們的做法是這樣的:
service程式碼
public class MusicService extends Service{
public IBinder onBind(Intent intent) {
return new MyBinder();
}
public class MyBinder extends Binder {
public MyService getMyService() {
return MusicService.this;
}
}
public void play(){
Log.i("TAG", "play");
}
public void pause(){
Log.i("TAG", "pause");
}
}
獲取service控制權程式碼
public class MainActivity extends Activity {
Intent service;
ServiceConnection conn;
MyService myService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
service = new Intent(MainActivity.this, MusicService.class);
conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
myService = ((MyBinder) binder).getMyService();
}
};
bindService(service, conn, BIND_AUTO_CREATE);
}
}
我們通過
ServiceConnection
去繫結一個Service
然後繫結成功後返回一個IBinder
物件,其中IBinder
就充當與一個中介
。是的,中介這個詞沒有用錯。再通過MyBinder
提供的getMyService
來獲取服務進而控制Service
。
一個真相引發的血案
其實上面的例子跟文章要說的內容沒什麼卵關係,只是讓你更好的回憶一下
IBinder
介面。這篇文章主要講一下onTransact
方法。
IBinder跨程式通訊圖
下面就大概簡單說明一下。
- 首先
myActivity
通過呼叫bindService
去繫結一個遠端的服務(myService
),繫結成功後返回一個IBinder
物件。這時候雙方就算是建立了連線了。 - 建立連線之後,雙方就可以通過持有的
IBinder
進行通訊。myActivity
使用IBinder
的transact
方法去給底層的Binder Driver
(Linux層)傳送訊息間接呼叫底層的IBinder
的execTransact
方法。 - 而
execTransact
導致的結果就是呼叫onTransact
方法。那麼這時候事件的處理就可以在該環節進行了。
其實就是一個transact->onTransact的一個過程
事實上我們看到
transact
和onTransact
的引數是一模一樣的。
protected boolean onTransact(int code, Parcel data, Parcel reply,int flags);
public final boolean transact(int code, Parcel data, Parcel reply,int flags);
transact的引數
-
code
: 這是一個識別碼,類似於Handler體系裡面的Message的what屬性。根據不同的code產生不同的響應。 -
data
: 呼叫transact的物件傳送過去的引數。 -
reply
: 呼叫onTransact的物件返回的引數。 -
flags
: Java裡面預設的native方法都是阻塞的,當不需要阻塞的時候設定為IBinder.FLAG_ONEWAY
,否則設定為0
一個小例子
環境:
- 一個叫做RemoteService的APP
- 一個叫做RemoteServiceDemo的APP
- RemoteServiceDemo中的Activity去控制RemoteService中的Service。
RemoteService
Service宣告
<service android:name="com.example.remoteservice.MusicService" >
<intent-filter>
<action android:name="top.august1996.musicservice" />
</intent-filter>
</service>
別忘了加入<action android:name="top.august1996.musicservice" />,否則會丟擲安全異常。
Service程式碼
public class MusicService extends Service {
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
public class MyBinder extends Binder {
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case 0:
Log.i("TAG", data.readString());
play();
reply.writeString("Service play Music at " + sdf.format(new Date()));
break;
case 1:
Log.i("TAG", data.readString());
pause();
reply.writeString("Service pause Music at " + sdf.format(new Date()));
break;
default:
break;
}
return true;
}
}
public void play() {
Log.d("TAG", "play");
}
public void pause() {
Log.d("TAG", "pause");
}
}
服務的程式碼很簡單,也沒什麼需要說的。
RemoteServiceDemo
佈局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="bind"
android:text="bind service" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="unbind"
android:text="unbind service" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="play"
android:text="play" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="pause"
android:text="pause" />
</LinearLayout>
程式碼
public class MainActivity extends Activity {
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name,
IBinder service) {
mBinder = service;
}
};
private IBinder mBinder = null;
private Parcel data = Parcel.obtain();
private Parcel reply = Parcel.obtain();
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void bind(View v) {
if (isBinded()) {
return;
}
/**
* 通過ComponentName去定位意圖
* 第一個引數是應用包名
* 第二個引數是Service或者Activity所在的包名+類名
*/
bindService(
new Intent().setComponent(
new ComponentName("com.example.remoteservice", "com.example.remoteservice.MusicService")),
mServiceConnection, Context.BIND_AUTO_CREATE);
}
public void unbind(View v) {
if (!isBinded()) {
return;
}
unbindService(mServiceConnection);
mBinder = null;
}
public void play(View v) {
if (!isBinded()) {
return;
}
try {
data.writeString("Activity request to play music at " + sdf.format(new Date()));
mBinder.transact(0, data, reply, 0);
Log.i("TAG", reply.readString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void pause(View v) {
try {
data.writeString("Activity request to pause music at " + sdf.format(new Date()));
mBinder.transact(1, data, reply, 0);
Log.i("TAG", reply.readString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
private boolean isBinded() {
return mBinder != null;
}
}
因為我們需要使用
reply
,所以我們使用阻塞的transact
,否則我們呼叫了transact
,但是那邊還未給reply寫入字串,最終導致NullPointException。
專案地址
相關文章
- 從AIDL看Android跨程式通訊AIAndroid
- Android程式間通訊之AIDLAndroidAI
- Android 程式通訊機制之 AIDLAndroidAI
- 4-AIII–Service跨程式通訊:aidlAI
- Android探索之AIDL實現程式間通訊AndroidAI
- Android程式間通訊,AIDL工作原理AndroidAI
- Android 程式間通訊 AIDL詳解AndroidAI
- Android跨程式通訊Android
- Android IPC程式間通訊之AIDL和Messenger的使用AndroidC程式AIMessenger
- [Android]你不知道的Android程式化(4)--程式通訊AIDL框架AndroidAI框架
- Android AIDL SERVICE 雙向通訊 詳解AndroidAI
- 【漫畫技術】Android跨程式通訊Android
- Android中AIDL實現程式通訊(附原始碼下載)AndroidAI原始碼
- 從AIDL開始談Android程式間Binder通訊機制AIAndroid
- Android Studio 建立aidl檔案,用於程式間通訊AndroidAI
- Android 程式之間通訊Android
- Aidl程式間通訊詳細介紹AI
- 使用AIDL實現程式間的通訊AI
- 快速入門android AIDL(開啟多程式並進行通訊)AndroidAI
- AIDL使用學習(二):跨程式回撥以及RemoteCallbackListAIREM
- android AIDL程式間通訊(只介紹了簡單資料型別)AndroidAI資料型別
- 使用AIDL實現程式間的通訊之複雜型別傳遞AI型別
- android-IPC/Binder/D-BUS(Binder/Messager/AIDL)程式間通訊(訊息機制)AndroidAI
- Android 之 Binder與程式間通訊Android
- Android IPC 之AIDLAndroidAI
- Webview獨立程式並通過AIDL實現資料通訊WebViewAI
- AIDL 跨程式呼叫 -- 介面層解析AI
- 使用AIDL實現跨程式介面回掉AI
- 【React】元件通訊 - 跨層通訊React元件
- Android 元件化之通訊(多模組,多程式)Android元件化
- 一行程式碼實現Android的跨程式呼叫與通訊行程Android
- Android 程式間通訊Android
- Android 多程式通訊Android
- Android Binder跨程式與非跨程式的傳輸異同原始碼分析Android原始碼
- android藍芽BLE(二) —— 通訊Android藍芽
- Binder學習(三)通過AIDL分析Binder通訊流程AI
- Android 多程式通訊之幾個基本問題Android
- Android多程式通訊之幾個基本問題Android