Android開發高級進階——多進程間通訊

一. 什麼是多進程?


多進程就是多個進程的意思,那麼什麼是進程呢?java

當一個應用在開始運行時,系統會爲它建立一個進程,一個應用默認只有一個進程,這個進程(主進程)的名稱就是應用的包名。android

進程的特色:緩存

  • 進程是系統資源和分配的基本單位,而線程是調度的基本單位。
  • 每一個進程都有本身獨立的資源和內存空間
  • 其它進程不能任意訪問當前進程的內存和資源
  • 系統給每一個進程分配的內存會有限制

根據上邊的引言和進程的特色能夠看出,使用多進程的場景爲:須要使apk所使用的內存限制擴大。安全

二. 進程的等級


按優先級能夠分爲五類,優先級從高到低排列:多線程

Android進程分類
  1. 前臺進程:該進程包含正在與用戶進行交互的界面組件,好比一個Activity。在接收關鍵生命週期方法時會讓一個進程臨時提高爲前臺進程,包括任何服務的生命週期方法onCreate()和onDestroy()和任何廣播接收器onReceive()方法。這樣作確保了這些組件的操做是有效的原子操做,每一個組件都能執行完成而不被殺掉。
  2. 可見進程:該進程中的組件雖然沒有和用戶交互,可是仍然能夠被看到。activity可見的時候不必定在前臺。一個簡單的例子是前臺的 activity 使用對話框啓動了一個新的 activity 或者一個透明 activity 。另外一個例子是當調用運行時權限對話框時(事實上它就是一個 activity!)。
  3. 服務進程:該進程包含在執行後臺操做的服務組件,好比播放音樂的Service。對於許多在後臺作處理(如加載數據)而沒有當即成爲前臺服務的應用都屬於這種狀況。
    請特別注意從onStartCommand()返回的常量,若是服務因爲內存壓力被殺掉,它表示控制什麼發生什麼:
    START_STICKY表示但願系統可用的時候自動重啓服務,但不關心是否能得到最後一次的 Intent (例如,能夠重建本身的狀態或者控制本身的 start/stop 生命週期)。
    START_REDELIVER_INTENT是爲那些在被殺死以後重啓時從新得到 Intent 的服務的,直到用傳遞給 onStartCommand() 方法的 startId 參數調用stopSelf()爲止。這裏會使用 Intent 和 startId 做爲隊列完成工做。
    START_NOT_STICKY用於那些殺掉也不要緊的服務。這適合那些管理週期性任務的服務,它們只是等待下一個時間窗口工做。
  4. 後臺進程:該進程包含的組件沒有與用戶交互,用戶也看不到 Service。在通常操做場景下,設備上的許多內存就是用在這上面的,使能夠從新回到以前打開過的某個 activity 。
  5. 空進程:沒有任何界面組件、服務組件,或觸發器組件,只是出於緩存的目的而被保留(爲了更加有效地使用內存而不是徹底釋放掉),只要 Android 須要能夠隨時殺掉它們。

三. 多進程的建立


Android多進程建立很簡單,只須要在AndroidManifest.xml的聲明四大組件的標籤中增長」android:process」屬性便可。命名以後,就成了一個單獨的進程。app

process分私有進程和全局進程:ide

  • 私有進程的名稱前面有冒號,例如:
<service android:name=".MusicService" android:process=":musicservice"/> 
  • 全局進程的名稱前面沒有冒號,例如:
<service android:name=".MusicService" android:process="com.trampcr.musicdemo.service"/> 

爲了節省系統內存,在退出該Activity的時候能夠將其殺掉(若是沒有人爲殺掉該進程,在程序徹底退出時該進程會被系統殺掉)。ui

多進程被建立好了,應用運行時就會對進程進行初始化,若是一個application中有多個進程,在進行全局初始化時,多進程會被初始化屢次。this

解決辦法:判斷當前進程,而後作相應的初始化操做。spa

四. 多進程間的通訊IPC


IPC:InterProcess Communication,即進程間通訊。

咱們知道,同一個進程的多個線程是共享該進程的全部資源,但多個進程間內存是不可見的,也就是說多個進程間內存是不共享的。那麼進程間是如何進行通訊的呢?

Android中提供了三種方法:

  • 系統實現。
  • AIDL(Android Interface Definition Language,Android接口定義語言):大部分應用程序不該該使用AIDL去建立一個綁定服務,由於它須要多線程能力,並可能致使一個更復雜的實現。
  • Messenger:利用Handler實現。(適用於多進程、單線程,不須要考慮線程安全),其底層基於AIDL。

使用Messenger

如需讓服務與遠程進程通訊,則可以使用Messenger爲服務提供接口。
定義一個MessengerService繼承自Service,並在AndroidManifest.xml中聲明並給一個進程名,使該服務成爲一個單獨的進程。代碼以下:

MessengerService.java

public class MessengerService extends Service{ class IncomingHandler extends Handler{ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 0: Toast.makeText(getApplicationContext(), "hello, trampcr", Toast.LENGTH_SHORT).show(); break; } } } Messenger mMessenger = new Messenger(new IncomingHandler()); @Nullable @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); return mMessenger.getBinder(); } } 

AndroidManifest.xml文件的配置以下:

<service android:name=".MessengerService" android:process="com.trampcr.messenger.service"/> 

MessengerActivity.java

public class MessengerActivity extends Activity{ private boolean mBound; private Messenger mMessenger; private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mMessenger = new Messenger(service); mBound = true; } @Override public void onServiceDisconnected(ComponentName name) { mMessenger = null; mBound = false; } }; public void sayHello(View v){ if(!mBound){ return; } Message msg = Message.obtain(null, 0 , 0, 0); try { mMessenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_messenger); } @Override protected void onStart() { super.onStart(); Intent intent = new Intent(MessengerActivity.this, MessengerService.class); bindService(intent, mServiceConnection, BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); if(mBound){ unbindService(mServiceConnection); mBound = false; } } } 

經過以上代碼,能夠看到Messenger的使用方法:

  1. 服務實現一個Handler,由其接收來自客戶端的每一個調用的回調。
  2. Handler用於建立Messenger對象(對Handler的引用)。
  3. Messenger建立一個IBinder,服務經過onBind()使其返回客戶端。
  4. 客戶端使用IBinder將Messenger(引用服務的Handler)實例化,而後使用後者將Message對象發送給服務。
  5. 服務在其Handler中(具體地講,是在handleMessage()方法中)接收每一個Message。

這樣,客戶端並無調用服務的「方法」。而客戶端傳遞的「消息」(Message對象)是服務在其Handler中接收的。

以上代碼實現的應用,剛打開會彈出一個binding,binding表示打開應用Activity就經過Messenger鏈接了一個服務進程,而後點擊say hello會彈出hello,trampcr,這表示了Activity經過Messenger將Message發送給了服務進程。以下圖:

MessengerService進程與MessengerActivity之間的通訊

使用AIDL

AIDL是一種接口描述語言,一般用於進程間通訊。

使用AIDL的步驟:

  1. 建立AIDL,在main下新建一個文件夾aidl,而後在aidl下新建AIDL文件,這時系統會自動爲該文件建立一個包名。
    aidl文件中會有一個默認的basicType方法,咱們爲它增長一個getName方法。代碼以下:
interface IMyAidlInterface { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); String getName(String nickName); } 

以上是咱們本身建立的aidl文件,系統還會自動生成aidl代碼,所在位置爲:build/generated/source/aidl下debug和release,可是此時debug下沒有任何東西,能夠rebuild或運行一下程序,再次打開debug,發現生成了一個包和一個aidl文件。

  1. 在java下新建一個類AIDLService繼承自Service。代碼以下:
public class AIDLService extends Service { IMyAidlInterface.Stub mStub = new IMyAidlInterface.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public String getName(String nickName) throws RemoteException { return "aidl " + nickName; } }; @Nullable @Override public IBinder onBind(Intent intent) { return mStub; } } 
  1. 在AndroidManifest.xml中註冊,並給一個進程名,是該服務成爲一個獨立的進程。
<service android:name=".AIDLService" android:process="com.aidl.test.service"/> 
  1. 在MainActivity中進行與AIDLService之間的進程間通訊。代碼以下:
public class MainActivity extends AppCompatActivity { private Button mBtnAidl; private IMyAidlInterface mIMyAidlInterface; ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBtnAidl = (Button) findViewById(R.id.btn_aidl); bindService(new Intent(MainActivity.this, AIDLService.class), mServiceConnection, BIND_AUTO_CREATE); mBtnAidl.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(mIMyAidlInterface != null){ try { String name = mIMyAidlInterface.getName("I'm nick"); Toast.makeText(MainActivity.this, "name = " + name, Toast.LENGTH_SHORT).show(); } catch (RemoteException e) { e.printStackTrace(); } } } }); } } 

在Activity中利用bindService與AIDLService進行鏈接,經過IMyAidlInterface實例與AIDLService進程進行通訊,以下圖所示:

AIDLService進程與MainActivity之間的通訊.gif

五.序列化插件


Parcelable code generate:自動生成實現了Parcelable接口的對象。

做者:trampcr連接:https://www.jianshu.com/p/ce1e35c84134來源:簡書著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
相關文章
相關標籤/搜索