• <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
            數(shù)據(jù)加載中……

            (轉(zhuǎn)) AIDL --- Android中的遠(yuǎn)程接口

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

                在Android中, 每個(gè)應(yīng)用程序都可以有自己的進(jìn)程. 在寫UI應(yīng)用的時(shí)候, 經(jīng)常要用到Service. 在不同的進(jìn)程中, 怎樣傳遞對(duì)象呢?  顯然, Java中不允許跨進(jìn)程內(nèi)存共享. 因此傳遞對(duì)象, 只能把對(duì)象拆分成操作系統(tǒng)能理解的簡(jiǎn)單形式, 以達(dá)到跨界對(duì)象訪問的目的. 在J2EE中,采用RMI的方式, 可以通過序列化傳遞對(duì)象. 在Android中, 則采用AIDL的方式. 理論上AIDL可以傳遞Bundle,實(shí)際上做起來卻比較麻煩.

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

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

            具體實(shí)現(xiàn)步驟如下:

            1、創(chuàng)建AIDL文件, 在這個(gè)文件里面定義接口, 該接口定義了可供客戶端訪問的方法和屬性。 如: 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);

            }

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

            2、編譯AIDL文件, 用Ant的話, 可能需要手動(dòng), 使用Eclipse plugin的話,可以根據(jù)adil文件自動(dòng)生產(chǎn)java文件并編譯, 不需要人為介入.

            3、在Java文件中, 實(shí)現(xiàn)AIDL中定義的接口. 編譯器會(huì)根據(jù)AIDL接口, 產(chǎn)生一個(gè)JAVA接口。這個(gè)接口有一個(gè)名為Stub的內(nèi)部抽象類,它繼承擴(kuò)展了接口并實(shí)現(xiàn)了遠(yuǎn)程調(diào)用需要的幾個(gè)方法。接下來就需要自己去實(shí)現(xiàn)自定義的幾個(gè)接口了.

            ITaskBinder.aidl中接口的實(shí)現(xiàn), 在MyService.java中接口以內(nèi)嵌類的方式實(shí)現(xiàn):

            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接口實(shí)現(xiàn):

            private ITaskCallback mCallback = new ITaskCallback.Stub() {

                    public void actionPerformed(int id) {

                       //TODO

                        printf("callback id=" + id);

                    }

            };

            4、向客戶端提供接口ITaskBinder, 如果寫的是service,擴(kuò)展該Service并重載onBind ()方法來返回一個(gè)實(shí)現(xiàn)上述接口的類的實(shí)例。這個(gè)地方返回的mBinder,就是上面通過內(nèi)嵌了定義的那個(gè). (MyService.java)

                public IBinder onBind(Intent t) {

                    printf("service on bind");

                    return mBinder;

            }

            在Activity中, 可以通過Binder定義的接口, 來進(jìn)行遠(yuǎn)程調(diào)用.

            5、在服務(wù)器端回調(diào)客戶端的函數(shù). 前提是當(dāng)客戶端獲取的IBinder接口的時(shí)候,要去注冊(cè)回調(diào)函數(shù), 只有這樣, 服務(wù)器端才知道該調(diào)用那些函數(shù)在: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的創(chuàng)建方法:

            AIDL語法很簡(jiǎn)單,可以用來聲明一個(gè)帶一個(gè)或多個(gè)方法的接口,也可以傳遞參數(shù)和返回值。 由于遠(yuǎn)程調(diào)用的需要, 這些參數(shù)和返回值并不是任何類型.下面是些AIDL支持的數(shù)據(jù)類型:

            1. 不需要import聲明的簡(jiǎn)單Java編程語言類型(int,boolean等)

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

            import com.cmcc.demo.ITaskCallback;

             

            interface ITaskBinder {

                //函數(shù)跟java一樣, 可以有0到多個(gè)參數(shù) ,可以有一個(gè)返回值

                boolean isTaskRunning();

                   

                void stopRunningTask();   

                //參數(shù)可以是另外的一個(gè)aidl定義的接口

                void registerCallback(ITaskCallback cb);   

              

            void unregisterCallback(ITaskCallback cb);

            //參數(shù)可以是String, 可以用in表入輸入類型, out表示輸出類型.

            int getCustomerList(in String branch, out String[] customerList);

             

            } 

            實(shí)現(xiàn)接口時(shí)有幾個(gè)原則:

            .拋出的異常不要返回給調(diào)用者. 跨進(jìn)程拋異常處理是不可取的.
            .IPC調(diào)用是同步的。如果你知道一個(gè)IPC服務(wù)需要超過幾毫秒的時(shí)間才能完成地話,你應(yīng)該避免在Activity的主線程中調(diào)用。 也就是IPC調(diào)用會(huì)掛起應(yīng)用程序?qū)е陆缑媸ロ憫?yīng). 這種情況應(yīng)該考慮單起一個(gè)線程來處理.
            .不能在AIDL接口中聲明靜態(tài)屬性。

            IPC的調(diào)用步驟:

             1. 聲明一個(gè)接口類型的變量,該接口類型在.aidl文件中定義。
             2. 實(shí)現(xiàn)ServiceConnection。
             3. 調(diào)用ApplicationContext.bindService(),并在ServiceConnection實(shí)現(xiàn)中進(jìn)行傳遞. 
             4. 在ServiceConnection.onServiceConnected()實(shí)現(xiàn)中,你會(huì)接收一個(gè)IBinder實(shí)例(被調(diào)用的Service). 調(diào)用
                YourInterfaceName.Stub.asInterface((IBinder)service)將參數(shù)轉(zhuǎn)換為YourInterface類型。
             5. 調(diào)用接口中定義的方法。 你總要檢測(cè)到DeadObjectException異常,該異常在連接斷開時(shí)被拋出。它只會(huì)被遠(yuǎn)程方法拋出。
             6. 斷開連接,調(diào)用接口實(shí)例中的ApplicationContext.unbindService()

             

            下面是整個(gè)程序:

            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 攀升 閱讀(1776) 評(píng)論(0)  編輯 收藏 引用 所屬分類: Android

            久久不见久久见免费视频7| 狠狠色丁香婷婷综合久久来来去| 久久午夜电影网| 久久九九精品99国产精品| 久久午夜福利无码1000合集| 久久WWW免费人成—看片| 99久久人人爽亚洲精品美女| 国产精品久久久久影院嫩草| 国产精品99久久精品| 亚洲国产成人久久精品影视| 91精品免费久久久久久久久| 91精品国产91久久| 蜜臀久久99精品久久久久久| 亚洲国产高清精品线久久 | 蜜臀av性久久久久蜜臀aⅴ麻豆| 99久久综合国产精品免费| 久久精品国产亚洲AV忘忧草18| 国产精品中文久久久久久久| 亚洲国产精品一区二区久久hs| 日韩精品久久久久久免费| 狠狠色丁香久久婷婷综合五月 | 国产成人无码精品久久久性色| 人人妻久久人人澡人人爽人人精品 | 中文成人久久久久影院免费观看| 国产精品乱码久久久久久软件 | 久久精品国产亚洲沈樵| 国产综合免费精品久久久| 欧美日韩中文字幕久久久不卡 | 日韩精品无码久久久久久| 久久综合久久综合久久| 久久亚洲国产精品123区| 亚洲综合伊人久久综合| 国产 亚洲 欧美 另类 久久| 亚洲国产成人精品无码久久久久久综合 | 偷窥少妇久久久久久久久| 97久久精品人妻人人搡人人玩| 久久国产香蕉视频| 久久一日本道色综合久久| 国内精品久久久久久久影视麻豆| 久久无码AV中文出轨人妻| 中文字幕一区二区三区久久网站 |