Binder的使用方法和原始碼解析
1.BInder驅動機制說明
首先Binder是用於程式間通訊,這個我們都知道,但是它是基於Binder驅動來完成程式間通訊的。Binder驅動是一個驅動程式,而這個驅動程式存在於Linux核心層,Linux核心層又可以說是作業系統層,是程式的管理者。
一個程式A要呼叫程式B的一個方法,這個程式A就需要獲取程式B的Binder代理物件,這個BInder代理物件就是程式B的BInder本地物件。當然這個Binder本地物件需要我們在程式B去實現在Service裡面,實現的同時還要實現程式A想要呼叫方法。而在程式A裡也要實現Binder代理物件。 程式A呼叫Binder代理物件時會通知Binder驅動,Binder驅動又會去呼叫程式B實現的Binder本地物件到實現的方法。
這裡要注意為何BInder驅動能夠知道程式A和程式B的所在,首先程式也可以看做記憶體裡的一個地址,然後無論是BInder代理物件和Binder本地物件都會實現IBinder介面,都會在ServiceManager裡註冊地址通過所在的Service的名字(比如:Action)註冊的,這樣一來雙方通過像是訪問Service就可以訪問對方的IBinder實現類。首先要注意無論是註冊還是傳遞資料、回撥資料都是通過Binder驅動實現,具體Binder驅動如何實現我們不需要知道,我們所能做的就是實現BInder本地物件和Binder代理物件。
2.BInder的使用方法
Server端負責實現Binder本地物件,Client負責實現Binder代理物件,實現Client端要呼叫Server完成兩個不同計算函式。這裡既然要呼叫兩個函式,我們就要教兩者學會如何分辨,就像使用handler一樣,通過數字來分辨,畢竟佔用位元組少。
mPlusBinder.transact(0x110, _data, _reply, 0);
因為呼叫函式會有返回值,所以我們在使用Binder代理物件呼叫函式時需要首先傳輸資料過去,然後在接收資料。
_data.writeInterfaceToken("CalcPlusService");
_data.writeInt(36);
_data.writeInt(12);
mPlusBinder.transact(0x111, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
同時Server端需要首先接收函式,進過計算再返回值
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = _arg0 * _arg1;
reply.writeNoException();
reply.writeInt(_result);
完整例項程式碼如下
BinderServer的程式碼
public class CalcPlusService extends Service
{
private static final String DESCRIPTOR = "CalcPlusService";
private static final String TAG = "CalcPlusService";
public void onCreate()
{
Log.e(TAG, "onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.e(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
public IBinder onBind(Intent t)
{
Log.e(TAG, "onBind");
return mBinder;
}
public void onDestroy()
{
Log.e(TAG, "onDestroy");
super.onDestroy();
}
public boolean onUnbind(Intent intent)
{
Log.e(TAG, "onUnbind");
return super.onUnbind(intent);
}
public void onRebind(Intent intent)
{
Log.e(TAG, "onRebind");
super.onRebind(intent);
}
private MyBinder mBinder = new MyBinder();
private class MyBinder extends Binder
{
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException
{
switch (code)
{
case 0x110:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = _arg0 * _arg1;
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case 0x111:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = _arg0 / _arg1;
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
};
}
<service android:name="com.example.zhy_binder.CalcPlusService" >
<intent-filter>
<action android:name="com.zhy.aidl.calcplus" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
BinderClient
public class MainActivity extends Activity
{
private IBinder mPlusBinder;
private ServiceConnection mServiceConnPlus = new ServiceConnection()
{
@Override
public void onServiceDisconnected(ComponentName name)
{
Log.e("client", "mServiceConnPlus onServiceDisconnected");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
Log.e("client", " mServiceConnPlus onServiceConnected");
mPlusBinder = service;
}
};
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void bindService(View view)
{
Intent intentPlus = new Intent();
intentPlus.setAction("com.zhy.aidl.calcplus");
boolean plus = bindService(intentPlus, mServiceConnPlus,
Context.BIND_AUTO_CREATE);
Log.e("plus", plus + "");
}
public void unbindService(View view)
{
unbindService(mServiceConnPlus);
}
public void mulInvoked(View view)
{
if (mPlusBinder == null)
{
Toast.makeText(this, "未連線服務端或服務端被異常殺死", Toast.LENGTH_SHORT).show();
} else
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try
{
_data.writeInterfaceToken("CalcPlusService");
_data.writeInt(50);
_data.writeInt(12);
mPlusBinder.transact(0x110, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
Toast.makeText(this, _result + "", Toast.LENGTH_SHORT).show();
} catch (RemoteException e)
{
e.printStackTrace();
} finally
{
_reply.recycle();
_data.recycle();
}
}
}
public void divInvoked(View view)
{
if (mPlusBinder == null)
{
Toast.makeText(this, "未連線服務端或服務端被異常殺死", Toast.LENGTH_SHORT).show();
} else
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try
{
_data.writeInterfaceToken("CalcPlusService");
_data.writeInt(36);
_data.writeInt(12);
mPlusBinder.transact(0x111, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
Toast.makeText(this, _result + "", Toast.LENGTH_SHORT).show();
} catch (RemoteException e)
{
e.printStackTrace();
} finally
{
_reply.recycle();
_data.recycle();
}
}
}
}
<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="fill_parent"
android:layout_height="wrap_content"
android:onClick="bindService"
android:text="BindService" />
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="unbindService"
android:text="UnbindService" />
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="mulInvoked"
android:text="50*12" />
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="divInvoked"
android:text="36/12" />
</LinearLayout>
相關文章
- 【Android原始碼】Binder機制和AIDL分析Android原始碼AI
- Picasso的使用和原始碼解析原始碼
- EventBus的使用和原始碼解析原始碼
- Binder學習(二)Binder機制解析
- RecyclerView用法和原始碼深度解析View原始碼
- HandlerThread和IntentService原始碼解析threadIntent原始碼
- RxBinding使用和原始碼解析原始碼
- binder核心原理解析
- net/http包的使用模式和原始碼解析HTTP模式原始碼
- redux的原始碼解析Redux原始碼
- Glide原始碼解析四(解碼和轉碼)IDE原始碼
- spark的基本運算元使用和原始碼解析Spark原始碼
- mybatis原始碼學習------resultMap和sql片段的解析MyBatis原始碼SQL
- 【原始碼解析】- ArrayList原始碼解析,絕對詳細原始碼
- Mybatis原始碼分析(二)XML的解析和Annotation的支援MyBatis原始碼XML
- HashMap原始碼解析和設計解讀HashMap原始碼
- UGUI原始碼解析(Toggle和ToggleGroup)UGUI原始碼
- Retrofit2使用方式和原始碼解析原始碼
- Android 系統原始碼-2:Binder 通訊機制Android原始碼
- Android 原始碼分析之 EventBus 的原始碼解析Android原始碼
- Spark原始碼-SparkContext原始碼解析Spark原始碼Context
- mybatis原始碼學習------cache-ref和cache的解析MyBatis原始碼
- CountDownLatch原始碼解析CountDownLatch原始碼
- LeakCanary原始碼解析原始碼
- vuex原始碼解析Vue原始碼
- ArrayBlockQueue原始碼解析BloC原始碼
- AsyncTask原始碼解析原始碼
- CopyOnWriteArrayList原始碼解析原始碼
- Express原始碼解析Express原始碼
- Observer原始碼解析Server原始碼
- SparseArray 原始碼解析原始碼
- RecyclerView原始碼解析View原始碼
- Promise 原始碼解析Promise原始碼
- Koa原始碼解析原始碼
- RateLimiter原始碼解析MIT原始碼
- redux原始碼解析Redux原始碼
- SDWebImage原始碼解析Web原始碼
- CyclicBarrier原始碼解析原始碼