一、概念
ipC:inter-PRocess Communication,進程間通信或者跨進程通信。例如:Bundle、文件共享、基于Binder的AIDL和Messenger、ContentProvider、Socket等1、線程:CPU調(diào)度的最小單位進程:一個執(zhí)行單元,一般指一個程序或應(yīng)用。一個進程可包含多個線程。2、應(yīng)用場景:一個應(yīng)用采用多線程,兩個應(yīng)用間通信。3、開始多進程(1)給四大組件在清單文件中指定Android:process屬性,開啟多進程。 默認進程的進程名是包名。 系統(tǒng)為每個應(yīng)用分配一個唯一UID,UID相同的應(yīng)用才能共享數(shù)據(jù)。 (擁有獨立虛擬機,application,內(nèi)存空間)(2)通過JNI在native層fork一個新的進程通過adb shell ps | grep 包名 查看一個包名下所存在的進程信息4、多進程的問題:每個進程分配獨立的虛擬機,不同虛擬機在內(nèi)存分配上有不同地址空間,所以在訪問同一個類對象產(chǎn)生多個副本。如果多進程之間通過內(nèi)存同享數(shù)據(jù)會同享失敗。(1)靜態(tài)成員和單例模式失效(2)線程同步機制失效 (不在同一內(nèi)存,無法鎖住同一對象)(3)SharedPreferences可靠性下降(sp不支持兩個進程同時執(zhí)行寫操作)(4)Application多次創(chuàng)建(同一進程、同一虛擬機、同一Application)5、Android中的IPC方式:(1)、使用Bundle :Activity、Service和Receive都支持Intent中傳遞Bundle數(shù)據(jù),由于Bundle實現(xiàn)了Parcelable接口,可在不同進程中進行通信。(2)、使用文件共享(但是兩個線程同時操作可能會出問題,sharedPrefrences有緩存策略,讀寫不可靠)(3)、使用Messenger : 不同進程中傳遞Message對象,底層實現(xiàn)是AIDL(4)、使用AIDL:(5)、使用ContentProvider: 不同應(yīng)用中進行數(shù)據(jù)共享,底層實現(xiàn)是Binder(6)、Socket:通過網(wǎng)絡(luò)傳輸字實現(xiàn)實時通信Messenger和AIDL區(qū)別:Messenger以串行方式處理消息,如果有大量的并發(fā)請求,只能一個個處理,不適合使用Messenger。AIDL可以跨進程調(diào)用方法,Messenger只能傳遞消息二、序列化序列化,表示將一個對象轉(zhuǎn)換成可存儲或可傳輸?shù)臓顟B(tài)。序列化后的對象可以在網(wǎng)絡(luò)上進行傳輸,也可以存儲到本地。通過Intent和Binder傳輸數(shù)據(jù)時需要使用序列化(內(nèi)存和內(nèi)存之間傳輸?shù)臄?shù)據(jù)需要序列化以后的行式) 1、Serializable接口:序列化接口聲明一個serialVersionUID。在反序列過程中,會對兩個UID進行對比,如果一致才可以進行反序列化。如果不聲明UID,在反序列時,當前類發(fā)生改變(增加或刪除了變量),會反序列化失敗。注:靜態(tài)成員變量屬于類,不會對象,不會參與序列化。用transient關(guān)鍵字標記的變量不參與序列化。原理:將一個對象轉(zhuǎn)換成可存儲可傳輸?shù)臓顟B(tài)。 2、Parcelable接口:實現(xiàn)這個接口,可以通過Intent和Binder進行傳遞。實現(xiàn)Parceable接口,重寫describeContents和writeToPracel()兩個方法。還需要提供一個CREATOR的常量,重寫createFromParcel()和newArray()兩個方法。 原理: 將一個完整的對象進行分解,分解的每一個部分都是Intent所支持的數(shù)據(jù)類型。在序列化過程中需要實現(xiàn)序列化、反序列化和內(nèi)容描述public class PicEntity implements Parcelable { public String picURL; public String middlePicURL; public String smallPicURL; //從序列化后得對象中創(chuàng)建原始對象 protected PicEntity(Parcel in) { picURL = in.readString(); middlePicURL = in.readString(); smallPicURL = in.readString(); } //反序列化的過程 public static final Creator<PicEntity> CREATOR = new Creator<PicEntity>() { //從序列化后的對象返回原始對象 @Override public PicEntity createFromParcel(Parcel in) { return new PicEntity(in); } //創(chuàng)建指定長度的原始對象數(shù)組 @Override public PicEntity[] newArray(int size) { return new PicEntity[size]; } }; //返回當前對象的內(nèi)容描述 @Override public int describeContents() { return 0; } //序列化的過程 @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(picURL); dest.writeString(middlePicURL); dest.writeString(smallPicURL); }}Intent、Bundle、Bitmap都是直接序列化的。List和Map也可序列化,里面的每個元素都是可序列化的。3、區(qū)別Serializable 是java序列化接口,將整個對象序列化,簡單開銷大,序列化和反序列化需要大量I/O操作。Parcelable是Android序列化方式,適合Android平臺。將對象的每個部分序列化,效率高,使用麻煩。三、BinderBinder類,實現(xiàn)了IBinder接口。主要是AIDL(多線程,多并發(fā)訪問)和Messenger(底層還是AIDL,單線程處理)作用:跨進程通信的一種方式(1)客戶端和服務(wù)端進行通信的媒介,bindService時,服務(wù)端返回一個Binder對象,客戶端客戶獲取數(shù)據(jù)。(2)ServiceManager連接 各種Manager(ActivityManager、WindowManager等)和對應(yīng)ManagerService的橋梁。四、Messenger信使,可以在不同的進程中傳遞Message對象,在Message中放入要傳遞的數(shù)據(jù)特點:對AIDL做了封裝,一次只能處理一個請求。流程圖:
使用步驟:1、服務(wù)端public class MessengerService extends Service { private static String TAG = "MessengerService"; private Messenger messenger = new Messenger(new MessageHandler()); @Override public void onCreate() { super.onCreate(); } @Nullable @Override public IBinder onBind(Intent intent) { //返回這個messenger對象底層的Binder return messenger.getBinder(); } //處理服務(wù)端發(fā)送來的數(shù)據(jù) private static class MessageHandler extends Handler{ @Override public void handleMessage(Message msg) { String myText = msg.getData().getString("msg"); LogUtil.i(TAG,"收到的消息:"+myText); //回復消息 Messenger client = msg.replyTo; Message replyMessage = Message.obtain(null,2); Bundle bundle = new Bundle(); bundle.putString("reply","收到了消息了啊"); replyMessage.setData(bundle); try { //做出回復 client.send(replyMessage); }catch (RemoteException e){ e.printStackTrace(); } } }}清單文件配置:<service android:name=".service.MessengerService" android:process=":remote" ></service>2、客戶端/** * * 用戶端 */public class MainActivity extends BaseActivity{ private Messenger messenger; @Override protected int getContentViewID() { return R.layout.activity_main; } @Override public void initView() { super.initView(); Intent intent = new Intent(this, MessengerService.class); bindService(intent,connection,BIND_AUTO_CREATE); } private Messenger replyMessenger = new Messenger(new MessageHandler()); private static class MessageHandler extends Handler { @Override public void handleMessage(Message msg) { String myText = msg.getData().getString("reply"); LogUtil.i(TAG,"客戶端收到的消息:"+myText); } } private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //綁定成功后,用服務(wù)端返回的IBinder來創(chuàng)建一個Messenger //通過這個Messenger向服務(wù)端發(fā)消息 messenger = new Messenger(service); Message message = Message.obtain(null,1); Bundle bundle = new Bundle(); bundle.putString("msg","ssssss"); message.setData(bundle); //客戶端接收到服務(wù)端回復的消息 message.replyTo = replyMessenger; try { //發(fā)送消息 messenger.send(message); }catch (RemoteException e){ e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { LogUtil.i("鏈接斷開"); } }; @Override protected void onDestroy() { super.onDestroy(); unbindService(connection); }}五、AIDL:1、創(chuàng)建實體類,實現(xiàn)Parcelablepublic class Book implements Parcelable { public int bookId; public String bookName; public Book(int bookId,String bookName){ this.bookId=bookId; this.bookName = bookName; } protected Book(Parcel in) { bookId = in.readInt(); bookName = in.readString(); } @Override public String toString() { return "["+bookId+"---"+bookName+"]"; } public static final Creator<Book> CREATOR = new Creator<Book>() { @Override public Book createFromParcel(Parcel in) { return new Book(in); } @Override public Book[] newArray(int size) { return new Book[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(bookName); dest.writeInt(bookId); }}2、AIDL接口的實現(xiàn):(1)AIDL文件支持的數(shù)據(jù)類型基本數(shù)據(jù)類型(int、long、char、boolean、double等)String和CharSequenceArrayList : 里面的元素必須能被AIDL支持HashMapParcelable:實現(xiàn)了Parcelable接口的對象注:其中Parcelable對象和AIDL對象顯式import進來創(chuàng)建一個AIDL文件,將需要給客戶端調(diào)用的接口在AIDL文件中聲明// IBookManager.aidlpackage com.example.hejian.demo2.aidl;//導入所需要使用的非默認支持數(shù)據(jù)類型的包import com.example.hejian.demo2.aidl.Book;interface IBookManager{List<Book> getBookList();void add(in Book book);}(2)如果有自定義Parcelable對象,必須建一個同名的AIDL文件// Book.aidl//這個文件的作用是引入了一個序列化對象 Book 供其他的AIDL文件使用//注意:Book.aidl與Book.java的包名應(yīng)當是一樣的package com.example.hejian.demo2.aidl;parcelable Book;3、服務(wù)端創(chuàng)建一個Service,在Service中實現(xiàn)這個AIDL接口。注:AIDL方法是在服務(wù)端的Binder線程池中執(zhí)行,可能出現(xiàn)并發(fā)訪問的情況(可使用CopyOnWriteArrayList進行并發(fā)訪問)4、綁定服務(wù)端的Service,通過服務(wù)器返回的Binder對象轉(zhuǎn)成AIDL接口所需類型。5、專門刪除跨進程的listener的接口RemoteCallbackList。客戶端進程終止,自動移除客戶端注冊的listener原理:內(nèi)部有一個map專門保存所有的AIDL回調(diào),map的key時IBinder類型,value是Callback類型(真正的遠程listener)他們底層的Binder對象是同一個,將相同的key的listener刪除掉就可。// IOnNewBookArrivedListener.aidlpackage com.example.hejian.aidldemo;// Declare any non-default types here with import statementsimport com.example.hejian.aidldemo.Book;//新書到了的監(jiān)聽interface IOnNewBookArrivedListener { void onNewBookArrived(in Book newBook);}服務(wù)端Service:/** * 服務(wù)端 */public class AIDLService extends Service { private CopyOnWriteArrayList<Book> mBooks = new CopyOnWriteArrayList<>(); public final String TAG = this.getClass().getSimpleName(); private RemoteCallbackList<IOnNewBookArrivedListener> backListener = new RemoteCallbackList<>(); @Override public void onCreate() { super.onCreate(); mBooks.add(new Book(13,"思維")); mBooks.add(new Book(23,"思維1")); } private Binder binder= new IBookManager.Stub(){ @Override public List<Book> getBookList() throws RemoteException { Log.e(TAG, "獲取到服務(wù)端list : " + mBooks.toString()); return mBooks; } @Override public void add(Book book) throws RemoteException { mBooks.add(book); //通過監(jiān)聽通知所有的客戶端 final int N = backListener.beginBroadcast(); for (int i=0;i<N;i++){ IOnNewBookArrivedListener listener = backListener.getBroadcastItem(i); listener.onNewBookArrived(book); } backListener.finishBroadcast(); Log.e(TAG, "增加一本以后,服務(wù)端list : " + mBooks.toString()); } @Override public void registListener(IOnNewBookArrivedListener listener) throws RemoteException { backListener.register(listener); } @Override public void unregistListener(IOnNewBookArrivedListener listener) throws RemoteException { backListener.unregister(listener); } }; @Nullable @Override public IBinder onBind(Intent intent) { return binder; }}用戶端:public class MainActivity extends AppCompatActivity { //由AIDL文件生成的Java類 private IBookManager mBookManager = null; //包含Book對象的list private List<Book> mBooks = new ArrayList<>(); private static String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = (Button)findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { try { if (mBookManager!=null){ mBooks.add(new Book(23,"新增的")); mBookManager.add(new Book(23,"新增的")); } } catch (RemoteException e) { e.printStackTrace(); } Log.e(TAG, "增加一本以后,客戶端list : "+mBooks.toString()); } }); } @Override protected void onResume() { super.onResume(); Intent intent = new Intent(this, AIDLService.class); bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); } private final ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e(TAG, "service connected"); //將服務(wù)端返回的Binder對象轉(zhuǎn)成AIDL接口,然后通過接口掉方法 mBookManager = IBookManager.Stub.asInterface(service); if (mBookManager != null) { try { mBookManager.registListener(listener); mBooks = mBookManager.getBookList(); Log.e(TAG, "獲取客戶端list:"+mBooks.toString()); } catch (RemoteException e) { e.printStackTrace(); } } } @Override public void onServiceDisconnected(ComponentName name) { Log.e(TAG, "service disconnected"); } }; private IOnNewBookArrivedListener listener = new IOnNewBookArrivedListener.Stub() { @Override public void onNewBookArrived(Book newBook) throws RemoteException { Log.e(TAG,"監(jiān)聽到服務(wù)器加了一個書:"+newBook.toString()); } }; @Override protected void onDestroy() { super.onDestroy(); unbindService(mServiceConnection); }}6、Binder死亡監(jiān)聽(1)設(shè)置DeathRecipient監(jiān)聽,在binderDied方法中重連遠程服務(wù)(在Binder線程池中被回調(diào))(2)在onServiceDisconnected中重連遠程服務(wù)7、遠程服務(wù)的權(quán)限驗證(1)例如在清單文件聲明權(quán)限,在Service的onBind方法中做權(quán)限驗證(2)在服務(wù)端onTransact方法驗證(3)獲取Uid和Pid,驗證客戶端包名等注意:由于客戶端onServiceConnected和onServiceDisConnected方法運行在UI線程,不能直接進行耗時操作服務(wù)端本身運行在Binder線程池中,可以執(zhí)行大量的耗時操作。注:開發(fā)藝術(shù)探索筆記整理
新聞熱點
疑難解答