<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    小菜毛毛技術分享

    與大家共同成長

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      164 Posts :: 141 Stories :: 94 Comments :: 0 Trackbacks
    http://blog.chinaunix.net/u3/90876/showart_2200991.html
    在Android中, 每個應用程序都可以有自己的進程. 在寫UI應用的時候, 經常要用到Service. 在不同的進程中, 怎樣傳遞對象呢? 顯然, Java中不允許跨進程內存共享. 因此傳遞對象, 只能把對象拆分成操作系統能理解的簡單形式, 以達到跨界對象訪問的目的. 在J2EE中,采用RMI的方式, 可以通過序列化傳遞對象. 在Android中, 則采用AIDL的方式. 理論上AIDL可以傳遞Bundle,實際上做起來卻比較麻煩. 

    AIDL(AndRoid接口描述語言)是一種借口描述語言; 編譯器可以通過aidl文件生成一段代碼,通過預先定義的接口達到兩個進程內部通信進程的目的. 如果需要在一個Activity中, 訪問另一個Service中的某個對象, 需要先將對象轉化成AIDL可識別的參數(可能是多個參數), 然后使用AIDL來傳遞這些參數, 在消息的接收端, 使用這些參數組裝成自己需要的對象. 

    AIDL的IPC的機制和COM或CORBA類似, 是基于接口的,但它是輕量級的。它使用代理類在客戶端和實現層間傳遞值. 如果要使用AIDL, 需要完成2件事情: 1. 引入AIDL的相關類.; 2. 調用aidl產生的class. 

    具體實現步驟如下: 

    1、創建AIDL文件, 在這個文件里面定義接口, 該接口定義了可供客戶端訪問的方法和屬性。 如: ITaskBinder.adil 

    package com.cmcc.demo; 

    import com.cmcc.demo.ITaskCallback; 

    interface ITaskBinder { 

    boolean isTaskRunning(); 
    void stopRunningTask(); 
    void registerCallback(ITaskCallback cb); 
    void unregisterCallback(ITaskCallback cb); }


    其中: ITaskCallback在文件ITaskCallback.aidl中定義: 

    package com.cmcc.demo; 

    interface ITaskCallback { 
    void actionPerformed(int actionId); }


    注意: 理論上, 參數可以傳遞基本數據類型和String, 還有就是Bundle的派生類, 不過在Eclipse中,目前的ADT不支持Bundle做為參數, 據說用Ant編譯可以, 我沒做嘗試. 

    2、編譯AIDL文件, 用Ant的話, 可能需要手動, 使用Eclipse plugin的話,可以根據adil文件自動生產java文件并編譯, 不需要人為介入. 

    3、在Java文件中, 實現AIDL中定義的接口. 編譯器會根據AIDL接口, 產生一個JAVA接口。這個接口有一個名為Stub的內部抽象類,它繼承擴展了接口并實現了遠程調用需要的幾個方法。接下來就需要自己去實現自定義的幾個接口了. 
    ITaskBinder.aidl中接口的實現, 在MyService.java中接口以內嵌類的方式實現: 

    private final ITaskBinder.Stub mBinder = new ITaskBinder.Stub() { 
    public void stopRunningTask() { //@TODO } 

    public boolean isTaskRunning() { //@TODO return false; } 

    public void registerCallback(ITaskCallback cb) { if (cb != null) mCallbacks.register(cb); } public void unregisterCallback(ITaskCallback cb) { if(cb != null) mCallbacks.unregister(cb); } }; 


    在MyActivity.java中ITaskCallback.aidl接口實現: 

    private ITaskCallback mCallback = new ITaskCallback.Stub() { 
    public void actionPerformed(int id) { //TODO printf("callback id=" + id); } }; 


    4、向客戶端提供接口ITaskBinder, 如果寫的是service,擴展該Service并重載onBind ()方法來返回一個實現上述接口的類的實例。這個地方返回的mBinder,就是上面通過內嵌了定義的那個. (MyService.java) 
    public IBinder onBind(Intent t) { printf("service on bind"); return mBinder; } 
    在Activity中, 可以通過Binder定義的接口, 來進行遠程調用. 

    5、在服務器端回調客戶端的函數. 前提是當客戶端獲取的IBinder接口的時候,要去注冊回調函數, 只有這樣, 服務器端才知道該調用那些函數在:MyService.java中: 

    void callback(int val) {

    final int N = mCallbacks.beginBroadcast();

    for (int i=0; i<N; i++) {

    try {

    mCallbacks.getBroadcastItem(i).actionPerformed(val);

    } catch (RemoteException e) {

    // The RemoteCallbackList will take care of removing

    // the dead object for us.

    }

    }

    mCallbacks.finishBroadcast();

    }



    AIDL的創建方法: 
    AIDL語法很簡單,可以用來聲明一個帶一個或多個方法的接口,也可以傳遞參數和返回值。由于遠程調用的需要, 這些參數和返回值并不是任何類型.下面是些AIDL支持的數據類型: 
    1. 不需要import聲明的簡單Java編程語言類型(int,boolean等) 
    2. String, CharSequence不需要特殊聲明 

    3. List, Map和Parcelables類型, 這些類型內所包含的數據成員也只能是簡單數據類型, String等其他比支持的類型. 
    ( 
    (另外: 我沒嘗試Parcelables, 在Eclipse+ADT下編譯不過, 或許以后會有所支持). 
    下面是AIDL語法: 
    // 文件名: SomeClass.aidl // 文件可以有注釋, 跟java的一樣 // 在package以前的注釋, 將會被忽略. // 函數和變量以前的注釋, 都會被加入到生產java代碼中. package com.cmcc.demo; 
    // import 引入語句 import com.cmcc.demo.ITaskCallback; 

    interface ITaskBinder { 
    //函數跟java一樣, 可以有0到多個參數 ,可以有一個返回值 boolean isTaskRunning(); 
    void stopRunningTask(); //參數可以是另外的一個aidl定義的接口 void registerCallback(ITaskCallback cb); 
    void unregisterCallback(ITaskCallback cb); 
    //參數可以是String, 可以用in表入輸入類型, out表示輸出類型. 
    int getCustomerList(in String branch, out String customerList); 
    } 

    實現接口時有幾個原則: 
    .拋出的異常不要返回給調用者. 跨進程拋異常處理是不可取的. 
    .IPC調用是同步的。如果你知道一個IPC服務需要超過幾毫秒的時間才能完成地話,你應該避免在Activity的主線程中調用。 也就是IPC調用會掛起應用程序導致界面失去響應. 這種情況應該考慮單起一個線程來處理. 
    .不能在AIDL接口中聲明靜態屬性。 

    IPC的調用步驟: 
    1. 聲明一個接口類型的變量,該接口類型在.aidl文件中定義。 
    2. 實現ServiceConnection。 
    3. 調用ApplicationContext.bindService(),并在ServiceConnection實現中進行傳遞. 
    4. 在ServiceConnection.onServiceConnected()實現中,你會接收一個IBinder實例(被調用的Service). 調用 YourInterfaceName.Stub.asInterface((IBinder)service)將參數轉換為YourInterface類型。 
    5. 調用接口中定義的方法。 你總要檢測到DeadObjectException異常,該異常在連接斷開時被拋出。它只會被遠程方法拋出。 
    6. 斷開連接,調用接口實例中的ApplicationContext.unbindService() 


    整個源碼程序如下所示: 
    1. ITaskCallback.aidl 

    package com.cmcc.demo; 

    interface ITaskCallback { 
    void actionPerformed(int actionId); } 


    2. ITaskBinder.aidl 

    package com.cmcc.demo; 

    import com.cmcc.demo.ITaskCallback; 

    interface ITaskBinder { 

    boolean isTaskRunning(); 
    void stopRunningTask(); 
    void registerCallback(ITaskCallback cb); 
    void unregisterCallback(ITaskCallback cb); }


    3. MyService.java 

    package com.cmcc.demo; 

    import android.app.Service; 
    import android.content.Intent; 
    import android.os.IBinder; 
    import android.os.RemoteCallbackList; 
    import android.os.RemoteException; 
    import android.util.Log; 

    public class MyService extends Service { 

    @Override public void onCreate() { printf("service create"); } 
    @Override public void onStart(Intent intent, int startId) { printf("service start id=" + startId); callback(startId); } 
    @Override public IBinder onBind(Intent t) { printf("service on bind"); return mBinder; } 
    @Override public void onDestroy() { printf("service on destroy"); super.onDestroy(); } 
    @Override public boolean onUnbind(Intent intent) { printf("service on unbind"); return super.onUnbind(intent); } 
    public void onRebind(Intent intent) { printf("service on rebind"); super.onRebind(intent); } 
    private void printf(String str) { Log.e("TAG", "###################------ " + str + "------"); } 
    void callback(int val) { final int N = mCallbacks.beginBroadcast(); for (int i=0; i<N; i++) { try {mCallbacks.getBroadcastItem(i).actionPerformed(val); } catch (RemoteException e) { // The RemoteCallbackList will take care of removing // the dead object for us. } } mCallbacks.finishBroadcast(); } 

    private final ITaskBinder.Stub mBinder = new ITaskBinder.Stub() { public void stopRunningTask() { 
    } 
    public boolean isTaskRunning() { return false; } 
    public void registerCallback(ITaskCallback cb) { if (cb != null) mCallbacks.register(cb); } public void unregisterCallback(ITaskCallback cb) { if(cb != null) mCallbacks.unregister(cb); } }; 
    final RemoteCallbackList
    <itaskcallback>mCallbacks = new RemoteCallbackList
    <itaskcallback>(); } 


    4. MyActivity.java 

    package com.cmcc.demo; 

    import android.app.Activity; 
    import android.content.ComponentName; 
    import android.content.Context; 
    import android.content.Intent; 
    import android.content.ServiceConnection; 
    import android.graphics.Color; 
    import android.os.Bundle; 
    import android.os.IBinder; 
    import android.os.RemoteException; 
    import android.util.Log; 
    import android.view.View; 
    import android.view.ViewGroup; 
    import android.view.View.OnClickListener; 
    import android.widget.AbsoluteLayout; 
    import android.widget.Button; 
    import android.widget.LinearLayout; 
    import android.widget.RelativeLayout; 
    import android.widget.TextView; 

    import java.io.BufferedReader; 
    import java.io.File; 
    import java.io.FileOutputStream; 
    import java.io.FileReader; 
    import java.io.PrintWriter; 

    public class MyActivity extends Activity { 

    private Button btnOk; private Button btnCancel; 
    @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); 
    setContentView(R.layout.test_service); 
    btnOk = (Button)findViewById(R.id.btn_ok); btnCancel = (Button)findViewById(R.id.btn_cancel); 
    btnOk.setText("Start Service"); btnCancel.setTag("Stop Service"); 
    btnOk.setOnClickListener(new OnClickListener() { public void onClick(View v) { onOkClick(); } }); 
    btnCancel.setOnClickListener(new OnClickListener() { public void onClick(View v) { onCancelClick(); } }); } 
    void onOkClick() { Bundle args = new Bundle(); 
    Intent intent = new Intent(this, MyService.class); intent.putExtras(args); 
    //printf("send intent to start"); 

    //startService(intent); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); startService(intent); } 

    void onCancelClick() { Intent intent = new Intent(this, MyService.class); //printf("send intent to stop"); 

    unbindService(mConnection); //stopService(intent); } 

    private void printf(String str) { Log.e("TAG", "###################------ " + str + "------"); } 
    ITaskBinder mService; 
    private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) {mService = ITaskBinder.Stub.asInterface(service); try { mService.registerCallback(mCallback); } catch (RemoteException e) { } 
    } 
    public void onServiceDisconnected(ComponentName className) { mService = null; } }; 
    private ITaskCallback mCallback = new ITaskCallback.Stub() { public void actionPerformed(int id) { printf("callback id=" + id); } }; } 


    5. xml文件(略) 
    posted on 2010-11-19 15:41 小菜毛毛 閱讀(4094) 評論(0)  編輯  收藏 所屬分類: andriod
    主站蜘蛛池模板: 国产免费一级高清淫曰本片| 日韩亚洲国产高清免费视频| 狠狠热精品免费观看| 色www永久免费视频| 亚洲hairy多毛pics大全| 特级淫片国产免费高清视频| 亚洲av永久无码| 四虎永久在线精品免费观看地址| 亚洲av午夜电影在线观看 | 亚洲人成在线免费观看| 亚洲综合免费视频| 67194在线午夜亚洲| 亚洲福利电影一区二区?| 18禁美女裸体免费网站| 激情亚洲一区国产精品| 一本久久A久久免费精品不卡| 亚洲国产成人久久一区久久| 免费看成人AA片无码视频吃奶| 亚洲av一综合av一区| 四虎精品视频在线永久免费观看| 亚洲综合色7777情网站777| 精品免费国产一区二区三区| 一级特黄a大片免费| 亚洲an天堂an在线观看| 最新猫咪www免费人成| 色哟哟国产精品免费观看| 五月天网站亚洲小说| 巨胸喷奶水视频www网免费| 一个人晚上在线观看的免费视频 | 四虎影视在线看免费观看| 亚洲乱码无码永久不卡在线| 最近在线2018视频免费观看| 亚洲AV无码专区亚洲AV桃| 亚洲精品国产品国语在线| 97碰公开在线观看免费视频| 日本亚洲中午字幕乱码| 无码国产精品一区二区免费虚拟VR| 亚洲国产无线乱码在线观看| 亚洲午夜未满十八勿入网站2| 美女裸身网站免费看免费网站| 色吊丝免费观看网站|