• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            攀升·Uranus


            Something Different,Something New
            數據加載中……

            (轉) AIDL --- Android中的遠程接口

            AIDL --- Android中的遠程接口
            http://labs.chinamobile.com/community/my_blog/517/4850

                在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);

                    }

                };

            }

            posted on 2009-08-12 17:17 攀升 閱讀(1798) 評論(0)  編輯 收藏 引用 所屬分類: Android

            香蕉久久一区二区不卡无毒影院| 久久AⅤ人妻少妇嫩草影院| 亚洲国产精品无码久久青草| 欧美午夜精品久久久久久浪潮| 久久精品国产久精国产一老狼| 久久亚洲精品成人AV| 99久久国产免费福利| 久久香综合精品久久伊人| 久久精品视频网| 国产精品久久久久久久人人看| 久久精品国产91久久麻豆自制| 青青青青久久精品国产h久久精品五福影院1421 | 99精品久久精品| 亚洲七七久久精品中文国产 | 久久久久亚洲精品男人的天堂| A级毛片无码久久精品免费| 久久美女人爽女人爽| 麻豆精品久久久久久久99蜜桃| 久久免费小视频| 精品永久久福利一区二区| 亚洲人成无码www久久久| 久久香蕉国产线看观看乱码| 欧洲精品久久久av无码电影| 亚洲精品视频久久久| 色综合久久88色综合天天| 久久精品国产亚洲AV香蕉| 久久成人小视频| 国产精品久久久久a影院| 久久天天躁狠狠躁夜夜不卡| 伊人色综合久久| 91久久福利国产成人精品| 久久er国产精品免费观看2| 久久精品aⅴ无码中文字字幕不卡| 欧美久久亚洲精品| 婷婷久久综合九色综合九七| 久久久这里有精品中文字幕| 伊人久久大香线蕉影院95| 久久se精品一区精品二区国产| 94久久国产乱子伦精品免费| 国产精品免费久久久久影院| 国产成人久久777777|