在Android中每個(gè)app都由Activity和Service組成的,這而Activity和Service可能運(yùn)行在同一個(gè)進(jìn)程中,也可能在不同的進(jìn)程中。
那么,不在同一個(gè)進(jìn)程的Activity或者Service是如何通信的呢?這時(shí)候就要用到Binder進(jìn)程間通信機(jī)制了。
而接下來要使用的一切都是基于Binder完成的,在Android中,無Binder不Andorid.
Bundle
public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
}
Bundle已經(jīng)實(shí)現(xiàn)了Parcelable接口,在它的序列化與反序列化特性下,他可以在不同的進(jìn)程中進(jìn)行數(shù)據(jù)的傳輸.
常規(guī)的是Intent又可以對Bundle進(jìn)行傳遞數(shù)據(jù),因此我們經(jīng)常在一個(gè)activity,service中利用intent傳輸數(shù)據(jù)就是Bundle的利用之一
- ProcessActivity數(shù)據(jù)傳輸方
Bundle bundle = new Bundle();
bundle.putString("ipc_bundle", "BundleName");
Intent intent=new Intent(ProcessActivity.this,ProcessActivity2.class);
intent.putExtras(bundle);
startActivity(intent);
- ProcessActivity2數(shù)據(jù)接收方
Bundle bundle=getIntent().getExtras();
String ipc=bundle.getString("ipc_bundle");
Messenger
Messenger屬于輕量化的IPC通信,他的底層是基于AIDL實(shí)現(xiàn).可以在不同的進(jìn)程中傳輸Message對象,客戶端發(fā)送一個(gè)Message到服務(wù)端,服務(wù)端借到消息后對消息進(jìn)行處理在包裝成Message再次反饋到客戶端.
- 服務(wù)端
public class MessengerService extends Service {
public static final String TAG = "MessengerService";
private HandlerThread handlerThread;
private Handler handler;
//Messenger
private Messenger messenger;
@Override
public void onCreate() {
super.onCreate();
int pid = android.os.Process.myPid();
Log.d(TAG, "進(jìn)程Id:" + pid + "");
//HandlerThread,使用Looper處理隊(duì)列消息
handlerThread = new HandlerThread("messenger_server");
handlerThread.start();
//獲取Looper
Looper looper = handlerThread.getLooper();
//讓Handler 運(yùn)行在HandlerThread中
handler = new Handler(looper) {
@Override
public void handleMessage(Message msg) {
replyToClientMsg(msg);//回復(fù)客戶端消息
super.handleMessage(msg);
}
};
messenger = new Messenger(handler);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
private void replyToClientMsg(Message msg) {
switch (msg.what) {
case Constants.MSG_FROM_CLIENT://接受消息處理
//模擬器服務(wù)器響應(yīng)過程
Log.d(TAG, "msg what= [" + msg.what + "" + "]");
Log.d(TAG, "msg arg1= [" + msg.arg1 + "" + "]");
Log.d(TAG, "msg arg2= [" + msg.arg2 + "" + "]");
Log.d(TAG,"客戶端發(fā)送的消息:"+msg.getData().getString(Constants.MESSENGER_KEY));
Toast.makeText(MessengerService.this, msg.getData().getString(Constants.MESSENGER_KEY), Toast.LENGTH_SHORT).show();
try {
Messenger msgFromClient = msg.replyTo;//客戶端回調(diào)
Message replyMsgToClient = Message.obtain(null, Constants.MSG_FROM_SERVICE);//回復(fù)給客戶端的消息
Bundle bundle = new Bundle();
bundle.putString(Constants.MESSENGER_KEY, "我也愛你");
replyMsgToClient.setData(bundle);
msgFromClient.send(replyMsgToClient);//發(fā)送Message消息體給客戶端
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
}
服務(wù)端通過Service來回應(yīng)客戶端的請求,通過一個(gè)Handler來實(shí)例化一個(gè)Messenger對象,在onBind中返回底層的Binder對象.
因?yàn)榭蛻舳丝赡芤淮涡曰蛘叨啻伟l(fā)送消息,在服務(wù)端需要一個(gè)消息隊(duì)列處理數(shù)據(jù)信息,因此使用HandlerThread,實(shí)現(xiàn)使用Looper來維護(hù)消息隊(duì)列.以此保證不會出現(xiàn)并發(fā)的情況。
- 客戶端
public class MessengerActivity extends AppCompatActivity {
private static final String TAG = MessengerActivity.class.getSimpleName();
private Button button;
private Messenger messengerService;//服務(wù)端Service
private Messenger messengerClient = new Messenger(new MessageHandler());//客戶端Messenger
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
int pid = android.os.Process.myPid();
Log.d(TAG, "進(jìn)程Id:" + pid + "");
bindMessengerService();
button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
sendMessage();
}
}).start();
}
});
}
//綁定服務(wù)
public void bindMessengerService() {
Intent mIntent = new Intent(this, MessengerService.class);
bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
Log.e(TAG, "bindService invoked !");
}
//發(fā)送消息
public void sendMessage() {
Message msgFromClient = Message.obtain(null, Constants.MSG_FROM_CLIENT, 1, 2);
Bundle data = new Bundle();
data.putString(Constants.MESSENGER_KEY, "我愛你,你愛我嗎?");
msgFromClient.setData(data);
msgFromClient.replyTo = messengerClient;
try {
messengerService.send(msgFromClient);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
unbindService(mServiceConnection);
super.onDestroy();
}
private class MessageHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Constants.MSG_FROM_SERVICE:
Log.d(TAG,"服務(wù)端回復(fù)消息:"+msg.getData().getString(Constants.MESSENGER_KEY));
Toast.makeText(MessengerActivity.this, msg.getData().getString(Constants.MESSENGER_KEY) , Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
/**
* @param name
* @param service
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
messengerService = new Messenger(service);
}
/**
* @param name
*/
@Override
public void onServiceDisconnected(ComponentName name) {
messengerService = null;
}
};
}
- 圖示
09-08 03:12:19.052 15181-15228/com.allure.study D/MessengerService: 客戶端發(fā)送的消息:我愛你,你愛我嗎?
09-08 03:12:19.056 15181-15181/com.allure.study D/MessengerActivity: 服務(wù)端回復(fù)消息:我也愛你

客戶端主要用于綁定服務(wù)端,綁定之后生成一個(gè)Messenger,通過這個(gè)Messenger可以實(shí)現(xiàn)想服務(wù)端的消息發(fā)送.
服務(wù)端收到消息之后的反饋需要客戶端使用Message.reply回調(diào)給服務(wù)端,服務(wù)端在同樣使用Message.reply即可實(shí)現(xiàn)雙向的通信.
特別注意在客戶端的2個(gè)Messenger,一個(gè)是通過綁定服務(wù)端的獲取的,一個(gè)是自身創(chuàng)建給服務(wù)端的回調(diào).
AIDL
ADIL可以處理并發(fā)和跨進(jìn)程.
前面的Messenger的底層也是基于AIDL,但是在客戶端有多個(gè)消息同時(shí)發(fā)送到客戶端,如果按照Messenger的方式只能單獨(dú)的在消息隊(duì)列一個(gè)個(gè)處理,在處理這種場景時(shí)就更推薦使用AIDL進(jìn)行解決.
- 服務(wù)端

創(chuàng)建一個(gè)AIDL文件,結(jié)尾為.aidl
AIDL的數(shù)據(jù)類型
- 基本的數(shù)據(jù)類型
- HashMap,ArrayList,實(shí)現(xiàn)Parcelable的對象
- AIDL接口
如果AIDL中使用了自定義的Parcelable,必須建一個(gè)同名的AIDL文件
public class AIDLService extends Service {
private static final String TAG = "AIDLService";
public AIDLService() {
}
@Override
public void onCreate() {
Log.e(TAG, "onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy");
super.onDestroy();
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind");
return super.onUnbind(intent);
}
@Override
public void onRebind(Intent intent) {
super.onRebind(intent);
Log.e(TAG, "onRebind");
}
@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.e(TAG, "onTaskRemoved");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind");
return binder;
}
private Binder binder = new TestAIDL.Stub() {
@Override
public String reply(String s) throws RemoteException {
if(s.equals("你愛我嗎")){
return "我愛你";
}else {
return "沒有你愛我,我怎么愛你";
}
}
};
}
- 客戶端
public class AIDLActivity extends AppCompatActivity {
private static final String TAG = AIDLActivity.class.getSimpleName();
private Button button;
private TestAIDL testAIDL;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidl);
//綁定AIDL服務(wù)
bindService();
button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
String s = testAIDL.reply("你愛我嗎");
Log.d(TAG,"你愛我嗎");
Log.d(TAG,s);
Toast.makeText(AIDLActivity.this, "你愛我嗎", Toast.LENGTH_SHORT).show();
Toast.makeText(AIDLActivity.this, s, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
unBindServcie();
}
private void unBindServcie() {
unbindService(mServiceConnection);
}
private void bindService() {
Intent mIntent = new Intent(this, AIDLService.class);
bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
Log.e(TAG, "bindService invoked !");
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
testAIDL = TestAIDL.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
testAIDL = null;
}
};
}
- 圖示

和Messenger類似,綁定服務(wù),獲取aidl對象,接口回調(diào)得到相應(yīng)的服務(wù)響應(yīng)信息.
源碼中可以看到AIDL.Stub屬于Binder子類,所以AIDL也是基于Binder來完成的
ContentProvider
ContentProvider和Messenger一樣底層也是基于AIDL Binder,和Messenger一樣在系統(tǒng)都做了一定程度封裝,便于上層的調(diào)用.最常見的便是我們獲取通訊錄使用ContentProvider
簡單實(shí)現(xiàn)一個(gè)ContentProvider的聯(lián)系人增刪改查的例子.
- 數(shù)據(jù)庫
public class DBOpenHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "contacts.db";
public static final String CONTACTS_TABLE_NAME = "contacts";
private static final String CREATE_CONTACTS_TABLE = "CREATE TABLE IF NOT EXISTS "
+ CONTACTS_TABLE_NAME + " (phonenumber CHAR(11) PRIMARY KEY, name TEXT)";
public static final int DB_VESION = 1;
public DBOpenHelper(Context context) {
super(context, DB_NAME, null, DB_VESION);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(CREATE_CONTACTS_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
- ContentProvider
public class TestContentProvider extends ContentProvider {
private static final String TAG = TestContentProvider.class.getSimpleName();
private static final String AUTHORITY = "com.allure.study.interprocesscommunication.contentprovider";
public static final String CONTACTS_URI = "content://" + AUTHORITY + "/" + DBOpenHelper.CONTACTS_TABLE_NAME;
private static final int CONTACTS_TABLE_CODE = 0;
private UriMatcher uriMatcher;
private SQLiteDatabase sqLiteDatabase;
@Override
public boolean onCreate() {
Log.v(TAG, "ContactsProvider進(jìn)程Id " + android.os.Process.myPid());
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, DBOpenHelper.CONTACTS_TABLE_NAME, CONTACTS_TABLE_CODE);
sqLiteDatabase = new DBOpenHelper(getContext()).getWritableDatabase();
return false;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) {
String tableName = getTableName(uri);
if(tableName == null) {
throw new IllegalArgumentException("Uri錯(cuò)誤: " + uri);
}
Cursor cursor = sqLiteDatabase.query(tableName, strings, s, strings1, s1, null, null);
return cursor;
}
/**
* @param uri
* @return
*/
@Nullable
@Override
public String getType(Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues contentValues) {
String tableName = getTableName(uri);
if(tableName == null) {
throw new IllegalArgumentException("Erro Uri: " + uri);
}
sqLiteDatabase.insert(tableName, null, contentValues);
getContext().getContentResolver().notifyChange(uri, null);
return null;
}
@Override
public int delete(Uri uri, String s, String[] strings) {
String tableName = getTableName(uri);
if(tableName == null) {
throw new IllegalArgumentException("Erro Uri: " + uri);
}
int count = sqLiteDatabase.delete(tableName, s, strings);
if(count > 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return 0;
}
@Override
public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {
return 0;
}
private String getTableName(Uri uri) {
String tableName = null;
switch (uriMatcher.match(uri)) {
case CONTACTS_TABLE_CODE:
tableName = DBOpenHelper.CONTACTS_TABLE_NAME;
break;
}
return tableName;
}
}
由于ContentProvider屬于四大組件因此我們在清單文件中需要對其進(jìn)行注冊
<!--ContentProvider-->
<provider
android:authorities="com.allure.study.interprocesscommunication.contentprovider"
android:name=".interprocesscommunication.contentprovider.TestContentProvider" />
** authorities和TestContentProvider類里的AUTHORITY徐亞保持一致**
** name代表ContentProvider類**
- Activity 調(diào)用
ublic class ContentProviderActivity extends AppCompatActivity {
private static final String TAG = ContentProviderActivity.class.getSimpleName();
private Uri uri;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content_provider);
Log.v(TAG, "Activity進(jìn)程Id " + android.os.Process.myPid());
uri = Uri.parse(TestContentProvider.CONTACTS_URI);
}
public void insert(View v) {
ContentValues values = new ContentValues();
values.put("phoneNumber", "15000000001");
values.put("name", "Jacye");
getContentResolver().insert(uri, values);
Log.v(TAG, "插入了 " + "Jacye " + "電話號碼: 15000000001");
}
public void delete(View v) {
getContentResolver().delete(uri, "name=?", new String[]{"Jacye"});
}
public void update(View v) {
}
public void query(View v) {
String[] colum = new String[]{"phoneNumber", "name"};
Cursor cursor = getContentResolver().query(uri, colum, null, null, null);
while (cursor.moveToNext()) {
String phoneNumber = cursor.getString(0);
String name = cursor.getString(1);
Log.v(TAG, "獲取到聯(lián)系人 " + phoneNumber + " " + name);
}
cursor.close();
}
}
顯示
09-08 05:04:40.978 31726-31726/com.allure.study V/ContentProviderActivity: 插入了 Jacye 電話號碼: 13333333333
09-08 05:04:42.870 31726-31726/com.allure.study V/ContentProviderActivity: 獲取到聯(lián)系人 13333333333 Jacye
總結(jié)
到此,Android中常用的IPC方式就已經(jīng)實(shí)現(xiàn)了,當(dāng)然還有其他的實(shí)現(xiàn)方式,比如說文件共享,Scoket通信等,在這里只講了Android 常用的.
- Messenger適用于單一無并發(fā)的場景,也就是說同一個(gè)app的不同進(jìn)程
- AIDL多用于并發(fā)跨進(jìn)程的場景(比如說2個(gè)app之間的交互),穩(wěn)定快速高效是他的優(yōu)點(diǎn),但是在通信約束上需要客戶端服務(wù)端都把AIDL加入自身項(xiàng)目。
- contentprovider多用于跨進(jìn)程和數(shù)據(jù)共享方面,相比較于AIDL來說更輕便