Android學習筆記--遠程服務的使用,android學習筆記--

來源:互聯網
上載者:User

Android學習筆記--遠程服務的使用,android學習筆記--
1、AIDL和Binder

    Android系統四大組件Activity, Content Provider, Broadcast和Service均可以進行跨進程資料轉送。

    Activity可以隱式調用其他進程的Activity; Content Provier可以跨進程訪問其他應用中的資料;Broadcast通過廣播的方式與其他應用進行通訊;Service則是通過Binder實現RPC

    Binder的實現機制很複雜,在這裡不展開敘述,只需要知道它是C/S模式實現RPC(Remote Procedure Call Protocol)——遠端程序呼叫協議。例如應用程式A提供實現了加減乘除的操作,並對外提供的操作介面,其他應用程式就可以遠程調用應     用程式A提供的介面實現運算,而不需要自己實現;

    那麼AIDL是什麼呢,AIDL是AndroidInterface definition language的縮寫,是android介面定義語言。把Binder比作一個管道,AIDL則定義了該管道中傳輸資料的格式。

    下面我們以執行個體講解如何使用AIDL實現遠程服務的調用

2、服務端的實現

    1、在Eclipse中建立Android工程,工程命名為Service。在Service工程的src目錄上右鍵建立包,起名為com.example.aild;在建立的包中增加普通檔案,命名為IRemoteService.aidl,標明該服務對外提供getPid()和basicTypes()兩個介面;

package com.example.aidl;interface IRemoteService {    /** Request the process ID of this service, to do evil things with it. */    int getPid();     /** Demonstrates some basic types that you can use as parameters     * and return values in AIDL.     */    int basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,            double aDouble, String aString);}

    aidl檔案完成後,在gen目錄下會自動產生com.example.aild包和IRemoteService.java檔案,我們不需要進行任何修改,完成後,Service目錄結構如下

package com.example.service;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.Process;import android.util.Log;import com.example.aidl.IRemoteService;public class AIDLService extends Service { private String TAG = "REMOTESERVICE"; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub Log.d(TAG, "DDService onBind"); return mBinder; } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); Log.d(TAG, "DDService onCreate........" + "Thread: " + Thread.currentThread().getName()); } /*與本地服務不同,此處建立Stub類型的Binder*/ private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { public int getPid(){ Log.d(TAG, "Thread: " + Thread.currentThread().getName()); /*返回給調用者當前的線程編號*/ return (int) Thread.currentThread().getId(); } public int basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) { Log.d(TAG, "Thread: " + Thread.currentThread().getName()); Log.d(TAG, "basicTypes aDouble: " + aDouble +" anInt: " + anInt+" aBoolean " + aBoolean+" aString " + aString); /*返回給調用者當前的線程編號*/ return (int) Thread.currentThread().getId(); } };}

可以看到,與本地服務不同的是,我們在onBind()中返回的是IRemoteService.Stub類型的變數,Stub類實際上是繼承自Binder,並且定義了我們在AIDL中定義的介面;需要我們實現這些介面,即getPid()和basicTypes();

    3、在AndroidMainfest.xml中聲明該服務

<service android:name=".AIDLService"                  android:process=":xlzh" >            <intent-filter>                <action android:name="com.example.aidl" />                <category android:name="android.intent.category.DEFAULT" />            </intent-filter></service>

在Serivce的屬性中增加了android:process,其中冒號後可自己隨意填寫。其含義請自行google。

OK,到此為止,服務端的工作已經全部結束了。接下來我們說下用戶端如何使用服務端提供的介面

3、用戶端的實現

1、在Eclipse中建立工程,名稱為Client;然後把Server工程中的com.example.aidl包整個拷貝到Client工程的src目錄下;工程結構如下所示

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/binderButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="bind" /> <Button android:id="@+id/unbinderButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="unbind" /></LinearLayout>

3、在Acitivity中使用遠程服務,MainActivity.java內容如下

package com.example.client;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;import android.view.View;import android.widget.Button;import com.example.aidl.IRemoteService; public class MainActivity extends Activity {        private String TAG = "com.example.aidl";    private IRemoteService remoteService;    private Button mBindButton;    private Button mUnbindButton;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mBindButton = (Button)findViewById(R.id.binderButton);        mBindButton.setOnClickListener(new View.OnClickListener() {                        @Override            public void onClick(View v) {                // TODO Auto-generated method stub                Log.d(TAG, "Bind Service");                //Intent intent = new Intent(IRemoteService.class.getName());                /*建立Intent,指定Service的AndroidMainfest.xml中聲明的Action名稱*/                Intent intent = new Intent("com.example.aidl");                /*在Android5.0以後,不允許隱式調用服務,故再次指定服務所在包名*/                intent.setPackage("com.example.service");                /*綁定服務*/                bindService(intent, conn, Context.BIND_AUTO_CREATE);            }        });                mUnbindButton = (Button)findViewById(R.id.unbinderButton);        mUnbindButton.setOnClickListener(new View.OnClickListener() {                        @Override            public void onClick(View v) {                // TODO Auto-generated method stub                Log.d(TAG, "UnBind Service");                /*解除綁定服務*/                unbindService(conn);            }        });    }         ServiceConnection conn = new ServiceConnection() {                 @Override        public void onServiceDisconnected(ComponentName name) {            Log.d(TAG, "UnBind Service success!");        }                 @Override        public void onServiceConnected(ComponentName name, IBinder service) {            Log.d(TAG, "Bind Service success!");            /*擷取服務端handle*/            remoteService = IRemoteService.Stub.asInterface(service);            try {                int pid1 = remoteService.getPid();                int pid2 = remoteService.basicTypes(12, 1223, true, 12.2f, 12.3, "我們的愛,我明白");                /*列印帶有getPid介面和basicTypes介面時服務端的線程號*/                Log.d(TAG, "remoteService.getPid(): " + pid1 + " remoteService.basicTypes(): " + pid2);            } catch (RemoteException e) {                e.printStackTrace();            }        }    };             @Override    protected void onDestroy() {        super.onDestroy();        /*正規做法是設定標記位,標誌服務是否已經unbind,來決定是否調用unbindService         * 此處,簡便行事,預設此時服務已經unbind
*/        //unbindService(conn);    }}
4、注意事項

1、Android5.0以後,不允許隱式調用服務,所以必須制定要調用的服務所在的包名(調了一下午才調通)

2、通過用戶端的列印結果,可以知道當調用getpid和basicTypes的介面時,伺服器端處理用戶端調用的線程是不一樣的。具體原因需要深入學習下Binder的機制

3、與本地服務的不同在於,伺服器端返回的是繼承自Binder的Stub類型的Binder,用戶端擷取伺服器端的handle時使用了Stub的asInterface介面。另外伺服器端需要在AndroidMainfest.xml中聲明服務時指定android:process屬性。

4、AIDL中支援以下的資料類型

    Java 的原生類型
    String 和CharSequence
    List 和 Map ,List和Map 對象的元素必須是AIDL支援的資料類型;  以上三種類型都不需要匯入(import)
    AIDL 自動產生的介面  需要匯入(import)
    實現android.os.Parcelable 介面的類.  需要匯入(import)。

5、總結

使用遠程服務流程總結如下;

1、定義AIDL檔案,聲明該服務需要向外提供的介面

2、在伺服器中實現AIDL中定義的介面

3、在AndroidMainfest.xml中聲明遠程服務

4、用戶端中拷貝服務端的AIDL檔案

5、用戶端中指定伺服器的服務名稱和所在包,進行綁定

6、用戶端使用Stub.asInterface介面擷取伺服器的hander,調用服務提供的介面

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.