很久沒有寫學習心得了,最近看了Android多進程相關的知識,是時候總結一下了,也方便之後本身溫習,我主要圍繞如下幾點展開:java
若是要用到ipc,那麼必須有多進程的存在,爲什麼要使用多進程呢,這裏給出兩點:android
當使用多進程傳遞數據的時候,爲了數據的一致性,咱們就必需要將對象序列化和反序列化,序列化不是Android中的新概念,在Java中就有,序列化有兩種方式Serializable和Parcelable接口。web
java序列化就是將實現了Serializable的對象轉換成字符序列形式保存在文件中,在須要的時候再將字符序列轉換爲對象恢復原來的結構,即反序列化。這樣咱們既然是字符序列,咱們就能夠很方便的傳輸了,好比intent,多進程,甚至網絡通訊等等。bash
//序列化操做1--FileOutputStream
ObjectOutputStream oos1 = new ObjectOutputStream(new FileOutputStream("worm.out"));
oos1.writeObject("Worm storage By FileOutputStream ");
oos1.writeObject(w);//必須全部引用的對象都實現序列化(本例終究是Data這個類),不然拋出有java.io.NotSerializableException:這個異常
oos1.close();
//反序列化操做1---FileInputStream
ObjectInputStream ois1 = new ObjectInputStream(new FileInputStream("worm.out"));
String s1 = (String)ois1.readObject();
Worm w1 = (Worm)ois1.readObject();
ois1.close();
System.out.println("反序列化操做1以後");
System.out.println(s1);
System.out.println("w1:"+w1);
複製代碼
public class Data implements Serializable {
private static final long serialVersionUID = 7247714666080613254L;
public int n;
public Data(int n) {
this.n = n;
}
public String toString(){
return Integer.toString(n);
}
}
複製代碼
以上就是對實現了Serializable的對象進行序列化和反序列化,能夠看出,序列化和反序列化就是將對象寫入文件和對文件進行讀取的過程,這也太明瞭了,就是這麼簡單,須要注意的是,全部的操做都是針對字節。網絡
序列化操縱以前
w=:a(853):b(119):c(802):d(788):e(199):f(881)
反序列化操做1以後
Worm storage By FileOutputStream
w1::a(853):b(119):c(802):d(788):e(199):f(881)
複製代碼
這裏說明一下,serialVersionUID,這個玩意咱們常常看到,它是幹嗎的,既然系統加入這個確定是有它的做用的啦,這個很重要,咱們進行序列化的時候也會寫入這個值,當在反序列化的時候咱們會對這個值作個比較,若是一致就能夠成功反序列化操做,不然就會拋異常。app
在Android中,出現了一種新的序列化方法,那就是使用Parcelable,使用它咱們就能夠很方便在intent,binder傳遞數據啦,使用方式很簡單。ide
public class FilterEntity implements Parcelable{
private String name;
private String chooseStr;
private boolean hasSelected;
public FilterEntity(String name, String chooseStr, boolean hasSelected) {
this.name = name;
this.chooseStr = chooseStr;
this.hasSelected = hasSelected;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getChooseStr() {
return chooseStr;
}
public void setChooseStr(String chooseStr) {
this.chooseStr = chooseStr;
}
public boolean isHasSelected() {
return hasSelected;
}
public void setHasSelected(boolean hasSelected) {
this.hasSelected = hasSelected;
}
@Override
public String toString() {
return "FilterEntity{" +
"name='" + name + '\'' + ", chooseStr='" + chooseStr + '\'' + ", hasSelected=" + hasSelected + '}'; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.name); dest.writeString(this.chooseStr); dest.writeByte(this.hasSelected ? (byte) 1 : (byte) 0); } public FilterEntity() { } protected FilterEntity(Parcel in) { this.name = in.readString(); this.chooseStr = in.readString(); this.hasSelected = in.readByte() != 0; } public static final Creator<FilterEntity> CREATOR = new Creator<FilterEntity>() { @Override public FilterEntity createFromParcel(Parcel source) { return new FilterEntity(source); } @Override public FilterEntity[] newArray(int size) { return new FilterEntity[size]; } }; } 複製代碼
Binder是一個很複雜的概念,咱們這裏主要是談談它的上層應用使用方式,Binder是進程之間通訊的橋樑,這裏給一個遠程service工具
public class BookManagerService extends Service {
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();
// private CopyOnWriteArrayList<IOnNewBookArriveListen> mListenList = new CopyOnWriteArrayList<IOnNewBookArriveListen>();
private RemoteCallbackList<IOnNewBookArriveListen> mListenList = new RemoteCallbackList<>();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
Log.d("wangchao0000", "getBookList: ");
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
//能夠作一些事,好比包驗證
return super.onTransact(code, data, reply, flags);
}
};
@Override
public void onCreate() {
super.onCreate();
Log.d("wangchao0000", "onCreate: ");
// mBookList.add(new Book(1, "開發藝術探索"));
// mBookList.add(new Book(2, "Flutter進階"));
ExecutorService executorService = Executors.newScheduledThreadPool(1);
((ScheduledExecutorService) executorService).scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Log.d("wangchao0000", "run: ");
int bookId = mBookList.size() + 1;
notifyNewBookArrived(new Book(bookId, "new book--" + bookId));
}
},0, 5, TimeUnit.SECONDS);
}
}
複製代碼
Manifest文件以下:學習
<service android:name=".service.BookManagerService"
android:process=":remote"
android:enabled="true"
android:exported="true"
/>
<activity android:name=".aidl.BookMnagerActivity"/>
複製代碼
這樣BookManagerService就運行在遠程服務了。接下來就看客戶端怎麼和遠程服務端怎麼去通訊了,咱們新建一個AIDL文件,這個接口文件中去聲明幾個咱們須要的方法。ui
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
複製代碼
系統會根據這個AIDL文件自動生成Binder類,這個類就是咱們的核心類,利用它客戶端和服務端就能夠通訊了哈,想起來就是興奮,咱們把這個類梳理一下就ok了。先上代碼:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: /Users/wangchao/code/TestProject/app/src/main/aidl/com/example/wangchao/testproject/IBookManager.aidl
*/
package com.example.wangchao.testproject;
// Declare any non-default types here with import statements
public interface IBookManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.wangchao.testproject.IBookManager
{
private static final java.lang.String DESCRIPTOR = "com.example.wangchao.testproject.IBookManager";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.wangchao.testproject.IBookManager interface,
* generating a proxy if needed.
*/
public static com.example.wangchao.testproject.IBookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.wangchao.testproject.IBookManager))) {
return ((com.example.wangchao.testproject.IBookManager)iin);
}
return new com.example.wangchao.testproject.IBookManager.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.example.wangchao.testproject.data.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(DESCRIPTOR);
com.example.wangchao.testproject.data.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.wangchao.testproject.data.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.wangchao.testproject.IBookManager
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public java.util.List<com.example.wangchao.testproject.data.Book> getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.wangchao.testproject.data.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.wangchao.testproject.data.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.example.wangchao.testproject.data.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
public java.util.List<com.example.wangchao.testproject.data.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.example.wangchao.testproject.data.Book book) throws android.os.RemoteException;
}
複製代碼
咋一眼看到這個代碼是否是很頭大,是的,我也很頭痛,系統自動生成的,不過咱們來梳理一下:這個類繼承類IInterface,一旦繼承了這個接口,系統就認爲它是AIDL:
/**
* Base class for Binder interfaces. When defining a new interface,
* you must derive it from IInterface.
*/
public interface IInterface
{
/**
* Retrieve the Binder object associated with this interface.
* You must use this instead of a plain cast, so that proxy objects
* can return the correct result.
*/
public IBinder asBinder();
}
複製代碼
沒啥啊,裏面就是隻有asBinder一個方法,該方法就是返回binder對象的。 接下來看看:
public java.util.List<com.example.wangchao.testproject.data.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.example.wangchao.testproject.data.Book book) throws android.os.RemoteException;
複製代碼
仔細一看,這不就是我們在AIDL文件中定義的那兩個方法嘛,這裏對它進行了聲明,看來在這個類中確定是要用到了。而後定義了幾個整型變量,用來告訴服務端目前客戶端是調用的哪個方法,否則服務端怎麼知道呢。 接着看,重點來了,就是那個stub,這個概念咱們並不陌生,它時常在service中出沒:
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
Log.d("wangchao0000", "getBookList: ");
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
//能夠作一些事,好比包驗證
return super.onTransact(code, data, reply, flags);
}
};
複製代碼
是吧,我沒說錯把。接下來咱們就分析分析了。 它是一個內部類,它就是一個Binder類,它實現了IInterface接口。這個類中有幾個重要的方法:
我們分別來分析他們的實現邏輯:
咱們先來看看asInterface方法,用來獲取服務端對象:
/**
* Cast an IBinder object into an com.example.wangchao.testproject.IBookManager interface,
* generating a proxy if needed.
*/
public static com.example.wangchao.testproject.IBookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.wangchao.testproject.IBookManager))) {
return ((com.example.wangchao.testproject.IBookManager)iin);
}
return new com.example.wangchao.testproject.IBookManager.Stub.Proxy(obj);
}
複製代碼
它是一個靜態方法,調用的地方是在客戶端,註釋寫得很清楚,若是客戶端和服務端在同一進程中,直接返回service對象,不然返回Proxy。事實上,既然寫這個類,那確定是不在一個進程了,那麼proxy就有用武之地了。
Proxy是stub的內部類,它實現了AIDL接口,Proxy對象是返回給客戶端的,客戶端拿到後去調用裏面 的方法:
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = IBookManager.Stub.asInterface(service);
try {
// Log.d("BookMnagerActivity", "query book list: -------" + Arrays.asList(list));
// list.add(new Book(3, "web進階"));
// Log.d("BookMnagerActivity", "query book list: -------" + Arrays.asList(bookManager.getBookList()));
bookManager.registerListen(onNewBookArriveListen);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
複製代碼
這個bookManager就是proxy的對象,這裏能夠經過斷點進去看。 咱們選一個方法去分析吧:
private static class Proxy implements com.example.wangchao.testproject.IBookManager
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public java.util.List<com.example.wangchao.testproject.data.Book> getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.wangchao.testproject.data.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.wangchao.testproject.data.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
複製代碼
當客戶端去調用getBookList方法的時候,它就執行到這裏,這裏聲明瞭_data, _reply, _result。調用過程以下:
前面說了,客戶端調用了服務端的transact方法,該方法屬於Binder的方法,在Binder線程池中
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
複製代碼
接下來看看,服務端幹了啥。
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.example.wangchao.testproject.data.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
return super.onTransact(code, data, reply, flags);
}
複製代碼
該方法中,它會去根據code去判斷調用哪一個方法,這個code就是以前聲明的那個id,哦,nice,原來這麼簡單:
proxy和onTransact不就是兩個相互應答的過程嘛。 這裏須要說明一下,
其實你們常常說的AIDL,有個啥用,它就是個工具而已,利用這個工具系統能夠幫咱們生成Binder類,但這個AIDL並非必須的,咱們能夠本身去寫Binder類。
相信你們對這個都不陌生,在Activity,Service使用intent傳遞數據的時候常常會用到,只要這個對象是已經序列化了的,它就能夠放到Bundle裏去傳輸,這不就是ipc了嘛。
這個很簡單,多個進程或者是應該去讀寫同一個文件,咱們把序列化的對象寫進去,另一個進程從這個文件從去讀取,而後再反序列化,就能夠很順利的拿到數據了。
上面將binder的時候已經分析過AIDL了,不懂的你們能夠專門去學學AIDL的使用,Messenger就是封裝了AIDL而已,沒啥好講的。
這玩意不就是Android四大組建之一嗎,對,就是它,它自然帶了IPC屬性,好比獲取聯繫人模塊裏面的數據。
好了,也寫了很多了,主要理解原理,至於怎麼使用不是這片文章的重點。