Android進程間通訊--消息機制及IPC機制實現

1、概念及說明
Android爲了屏蔽進程的概念,利用不一樣的組件[Activity、Service]來表示進程之間的通訊!
組件間通訊的核心機制是Intent,經過Intent能夠開啓一個Activity或Service,不論這個Activity或Service是屬於當前應用仍是其它應用的!
                                                  
                              本文若有bug,請指出啊!!你們一同進步!!
                                                             謝謝!!

Intent包含兩部分:
一、目的[action]--要往哪裏去
二、內容[category、data]--路上帶了些啥,區分性數據或內容性數據
Intent類型:
一、顯式--直接指定消息目的地,只適合同一進程內的不一樣組件之間通訊
new Intent(this,Target.class)
二、隱式--AndroidMainifest.xml中註冊,通常用於跨進程通訊
new Intent(String action)
 
2、實現-Intent簡單進程間通訊
顯式的Intent較爲簡單!
 
如何實現隱式Intent呢?
在AndroidManifest.xml文件中定義<activity>
說明:
一、一個<activity>包括:
零個或多個<intent-filter>

它主要是做爲匹配的標準,可否匹配成功由<action>、<category>、<data>三個tag共同決定的。
 
二、一個<intent-filter>包括:
一個或多個 <action>
零個或多個 <category> 
指定<activity>的分類特徵
eg:
<category android:name="android.intent.category.LAUNCHER" />
--說明該<activity>是該project運行的第一個界面

<category android:name="android.intent.category.HOME" />
--說明該<activity>能夠做爲Launcher的,即系統操做界面

<category android:name="android.intent.category.DEFAULT" />
 --缺省狀況

零個或一個 <data>
-- 指定攜帶的數據的類型,使用MIME類型描述方式來描述
eg:
<data android:mimeType="video/mpeg" />
video/mpeg表示編碼格式爲mpeg的視頻,
也可使用通配符video/*表示任意格式的視頻文件類型;
 
在查詢ContentProvider時,可使用
<data android:mimeType="vnd.android.cursor.dir/vnd.myq.note" />
查詢上來的數據是多個記錄
<data android:mimeType="vnd.android.cursor.item/vnd.myq.note" />
查詢上來的數據是單個記錄
如上設置,要重寫SQLiteOpenHelper的getType(Uri uri)方法
eg:
 @Override
 public String getType(Uri uri) {
  final int match = sUriMatcher.match(uri) ;
  switch(match)
  {
  case NOTES :
  case LIVE_FOLDER_NOTES:
   return "vnd.android.cursor.dir/vnd.myq.note" ;
   
  case NOTES_ID :
   return "vnd.android.cursor.item/vnd.myq.note" ;
   
  default:
   throw new IllegalArgumentException("invalid uri : " + uri) ;
  }
 }
 
數據的URI由scheme(協議),host,port,path四部分:scheme://host:port/path
<data android:scheme=" http://localhost:8080/test.jsp" />

三、一個Intent對應多種匹配結果的處理說明
 一個intent有多個可匹配的處理組件,系統如何處理?
分響應消息的組件類型:
1)若是是service那麼這些service均可以啓動並處理消息。
2)若是是Activity則會彈出一個對話框讓用戶進行選擇。
 
四、安全性問題
 若是不一樣進程間的組件能夠經過隱式消息互相通訊,那程序不是能夠輕易調用到其餘的程序或者系統中的一些敏感程序的組件,這樣會不會很不安全呢?
其實Android在安全方面有一個統一,完備和輕便的安全策略模型。

簡單一點說就是:權限設置問題
咱們能夠本身定義permission,而後在須要的組件處設置該permission,那麼用戶要想該組件,必需要配置該permission,不然訪問失敗的!

eg:
一、定義permission
<permission-group android:name="android.permission-group.MYQ_INFO"/>
<permission
     android:name="com.myq.android.permission.DATETIME_SERVICE"
     android:permissionGroup="android.permission-group.MYQ_INFO"
     android:protectionLevel="normal"
     />
 
二、配置permission
<service android:name=".DateTimeService" android:permission="com.myq.android.permission.DATETIME_SERVICE">
   <intent-filter>
 <action android:name="com.myq.android.MultiProcessTest.DATETIMESERVICE_ACTION" />
   </intent-filter>
</service>
 
三、使用permission
<uses-permission android:name="com.myq.android.permission.DATETIME_SERVICE"/>
 
3、IPC機制
有了Intent這種基於消息的進程內或進程間通訊模型,咱們就能夠經過Intent去開啓一個Service,能夠經過Intent跳轉到另外一個Activity,不論上面的Service或Activity是在當前進程仍是其它進程內即不管是當前應用仍是其它應用的Service或Activity,經過消息機制均可以進行通訊!

可是經過消息機制實現的進程間通訊,有一個弊端就是,若是咱們的Activity與Service之間的交往不是簡單的Activity開啓Service操做,而是要隨時發一些控制請求,那麼必須就要保證Activity在Service的運行過程當中隨時能夠鏈接到Service。

eg:音樂播放程序
後臺的播放服務每每獨立運行,以方便在使用其餘程序界面時也能聽到音樂。同時這個後臺播放服務也會定義一個控制接口,好比播放,暫停,快進等方法,任什麼時候候播放程序的界面均可以鏈接到播放服務,而後經過這組控制接口方法對其控制。
 
如上的需求僅僅經過Intent去開啓Service就沒法知足了!從而Android的顯得稍微笨重的IPC機制就出現了,然而它的出現只適用於Activity與Service之間的通訊,相似於遠程方法調用,就像是C/S模式的訪問,經過定義AIDL接口文件來定義一個IPC接口,Server端實現IPC接口,Client端調用IPC接口的本地代理。

因爲IPC調用是同步的,若是一個IPC服務須要超過幾毫秒的時間才能完成的話,你應該避免在Activity的主線程中調用,不然IPC調用會掛起應用程序致使界面失去響應。在 這種狀況下,應該考慮單起一個線程來處理IPC訪問。

兩個進程間IPC看起來就象是一個進程進入另外一個進程執行代碼而後帶着執行的結果返回。

IPC機制鼓勵咱們「儘可能利用已有功能,利用IPC和包含已有功能的程序協做完成一個完整的項目」
 
IPC實現demo:
個人
project -- MultiProcessTest
package -- com.myq.android.MultiProcessTest
 
一、AIDL文件,我是放在package下,
文件名稱爲:
IDateTimeService.aidl
文件內容爲:
package com.myq.android.MultiProcessTest ;
interface IDateTimeService
{
 String getCurrentDateTime(in String format) ;
}
 
若是正確配置,會在gen下,生成同名的java文件
簡單摘要:
//咱們須要實現的類Stub
public interface IDateTimeService extends android.os.IInterface
{
...
public static abstract class Stub
extends android.os.Binder
implements com.myq.android.MultiProcessTest.IDateTimeService
{
 ...
//獲取實例的方法asInterface
public static com.myq.android.MultiProcessTest.IDateTimeService asInterface(android.os.IBinder obj)
{
  ...
}
 ...
}
//咱們本身的業務方法,須要實現的
public java.lang.String getCurrentDateTime(java.lang.String format) throws android.os.RemoteException;
}
 
二、Service中實現IDateTimeService.Stub
eg:
package com.myq.android.MultiProcessTest;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
 
public class DateTimeService extends Service {
 
 public static final String DATETIME_SERVICE_ACTION = "com.myq.android.MultiProcessTest.DATETIMESERVICE_ACTION" ;
 
 private static final String TAG = "--------DateTimeService-------" ;
 
 private  SimpleDateFormat sdf ;
 
 private final IDateTimeService.Stub stub = new IDateTimeService.Stub()
 {
  
  public String getCurrentDateTime(String format) throws RemoteException {
   return getCurrentDateTimeString(format) ;
  }
 } ;
 
 private synchronized String getCurrentDateTimeString(String format)
 {
     sdf = new SimpleDateFormat(format) ;
     final String temp = sdf.format(new Date()) ;
   Log.i(TAG,"getCurrentDateTimeString--" + Thread.currentThread() + "--" + temp) ;
   return temp ;
 }
 
 public IBinder onBind(Intent arg0)
 {
  Log.i(TAG, "onBind--" + Thread.currentThread()) ;
  return stub;
 }
}

三、Client端代碼實現
private ServiceConnection mServiceConn = new ServiceConnection()
 {
  
  public void onServiceConnected(ComponentName name, IBinder service) {
   mDateTimeService = IDateTimeService.Stub.asInterface(service) ;
  }
  
  public void onServiceDisconnected(ComponentName name) {
   mDateTimeService = null ;
  }
 } ;
 
說明:
網上的好多資料都沒有涉及IPC調用的AIDL的具體說明!
它本質上是Server端和Client端都具備相同的AIDL文件,要位於相同的包下,即package的包名藥同樣,而後才能正確的經過proxy訪問,不然client與server的aidl文件處於不一樣package會出錯的。
 
aidl模型以下:
                |<--------------------aidl---------------------->|
 client端-->proxy  ----------parcel數據包-------- stub<---server端
從而proxy+parcel+stub構成了aidl.
只不過,proxy運行在客戶進程,而stub運行在服務端進程。
當你經過aidl去訪問服務端時,客戶端會阻塞在proxy,服務端處理完後,通知proxy返回。
 
4、附件及說明
一、
附件是我測試所用的demo,我用的系統是ubuntu9,Android2.2版本
基本功能:
能夠根據用戶選擇的不一樣輸出格式輸出當前系統的時間。
二、
運行順序:
先運行Server端:MultiProcessTest
再運行Client端:MultiProcessTestClient
 
三、
注意點:
Server和Client端的AIDL文件必需要位於同package下,不然會出錯
安全性問題實現,權限控制--定義、配置、使用
異步處理問題--Handler
 
 

本文出自 「苗運齊的博客」 博客,請務必保留此出處http://myqdroid.blog.51cto.com/2057579/394189java

相關文章
相關標籤/搜索