標籤:
一、基於訊息的通訊機制 Intent ---boudle ,extra
Android為了屏蔽進程的概念,利用不同的組件[Activity、Service]來表示進程之間的通訊!
組件間通訊的核心機制是Intent,通過Intent可以開啟一個Activity或Service,不論這個Activity或Service是屬於當前應用還是其它應用的!
Intent包含兩部分:
1、目的[action]--要往哪裡去
2、內容[category、data]--路上帶了些啥,區分性資料或內容性資料
Intent類型:
1、顯式--直接指定訊息目的地,只適合約一進程內的不同組件之間通訊
new Intent(this,Target.class)
2、隱式--AndroidMainifest.xml中註冊,一般用於跨進程通訊
new Intent(String action)
實現-Intent簡單處理序間通訊
顯式的Intent較為簡單!
如何?隱式Intent呢?
在AndroidManifest.xml檔案中定義<activity>
說明:
1、一個<activity>包括:
零個或多個<intent-filter>
它主要是作為匹配的標準,能否匹配成功由<action>、<category>、<data>三個tag共同決定的。
2、一個<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" />
3、一個Intent對應多種匹配結果的處理說明
一個intent有多個可匹配的處理組件,系統如何處理?
分響應訊息的組件類型:
1)如果是service那麼這些service都可以啟動並處理訊息。
2)如果是Activity則會彈出一個對話方塊讓使用者進行選擇。
4、安全性問題
如果不同進程間的組件可以通過隱式訊息互相通訊,那程式不是可以輕易調用到其他的程式或者系統中的一些敏感程式的組件,這樣會不會很不安全呢?
其實Android在安全方面有一個統一,完備和輕便的安全性原則模型。
簡單一點說就是:使用權限設定問題
我們可以自己定義permission,然後在需要的組件處設定該permission,那麼使用者要想該組件,必須要配置該permission,否則訪問失敗的!
eg:
1、定義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"
/>
2、配置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>
3、使用permission
<uses-permission android:name="com.myq.android.permission.DATETIME_SERVICE"/>
二.基於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
1、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;
}
2、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;
}
}
3、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返回。
四、附件及說明
1、
附件是我測試所用的demo,我用的系統是ubuntu9,Android2.2版本
準系統:
可以根據使用者選擇的不同輸出格式輸出當前系統的時間。
2、
運行順序:
先運行Server端:MultiProcessTest
再運行Client端:MultiProcessTestClient
3、
注意點:
Server和Client端的AIDL檔案必須要位於同package下,否則會出錯
安全性問題實現,許可權控制--定義、配置、使用
非同步處理問題--Handler
android 應用程式Activity之間資料傳遞與共用的幾種途徑