Android studio 下的aidl編程實現Android的誇處理序間通訊

來源:互聯網
上載者:User

標籤:

前言

Android中誇處理序間通訊方式有很多種方式,比如:aidl,Messenger,檔案分享權限設定,廣播(BroadCast),ContentProvider,Socket(網路通訊)。每種方式都有自己的使用情境和優缺點,接下來幾篇部落格我們一一學習他們是怎麼使用的。這篇部落客要是介紹Android studio下實現aidl編程。

AIDL的使用步驟

aidl遠程調用傳遞的參數和傳回值支援Java的基本類型(int long booen char byte等)和String,List,Map等。當然也支援一個自訂對象的傳遞,不過此時就需要做一些特別處理了,後續會介紹aidl傳遞對象怎麼處理。
有關aidl的相關概念這裡就不詳細解釋了,我們來看看在Android Studio下怎麼來實現aidl編程的。

服務端產生aidl檔案
建立一個MyAidlDemoServer工程,然後在main目錄下右鍵建立一個aidl目錄,然後在該目錄下建立一個IMyAidlInterface.aidl檔案,代碼如下:
// IMyAidlInterface.aidlpackage com.example.xjp.aidla;interface IMyAidlInterface {    int add(int arg1, int arg2);}

定義了一個IMyAidlInterface介面,介面裡面定義了一個add方法用於計算兩個數的和。然後Build當前工程,在app/build/generated/source/aidl/debug目錄下會產生一個與IMyAidlInterface.aidl檔案同樣包名的一個檔案,該檔案下面自動產生IMyAidlInterface檔案,該檔案裡面自動實現了一些方法用於遠程調用,IMyAidlInterface代碼如下:

/* * This file is auto-generated.  DO NOT MODIFY. * Original file: D:\\WorkPlace\\MyAidlDemoServer\\app\\src\\main\\aidl\\com\\example\\xjp\\aidla * \\IMyAidlInterface.aidl */package com.example.xjp.aidla;public interface IMyAidlInterface extends android.os.IInterface {    /**     * Local-side IPC implementation stub class.     */    public static abstract class Stub extends android.os.Binder implements com.example.xjp.aidla            .IMyAidlInterface {        private static final java.lang.String DESCRIPTOR = "com.example.xjp.aidla.IMyAidlInterface";        /**         * Construct the stub at attach it to the interface.         */        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }        /**         * Cast an IBinder object into an com.example.xjp.aidla.IMyAidlInterface interface,         * generating a proxy if needed.         */        public static com.example.xjp.aidla.IMyAidlInterface asInterface(android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.example.xjp.aidla.IMyAidlInterface))) {                return ((com.example.xjp.aidla.IMyAidlInterface) iin);            }            return new com.example.xjp.aidla.IMyAidlInterface.Stub.Proxy(obj);        }        @Override        public android.os.IBinder asBinder() {            return this;        }        @Override        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)                 throws android.os.RemoteException {            switch (code) {                case INTERFACE_TRANSACTION: {                    reply.writeString(DESCRIPTOR);                    return true;                }                case TRANSACTION_add: {                    data.enforceInterface(DESCRIPTOR);                    int _arg0;                    _arg0 = data.readInt();                    int _arg1;                    _arg1 = data.readInt();                    int _result = this.add(_arg0, _arg1);                    reply.writeNoException();                    reply.writeInt(_result);                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }        private static class Proxy implements com.example.xjp.aidla.IMyAidlInterface {            private android.os.IBinder mRemote;            Proxy(android.os.IBinder remote) {                mRemote = remote;            }            @Override            public android.os.IBinder asBinder() {                return mRemote;            }            public java.lang.String getInterfaceDescriptor() {                return DESCRIPTOR;            }            @Override            public int add(int arg1, int arg2) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                int _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    _data.writeInt(arg1);                    _data.writeInt(arg2);                    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);                    _reply.readException();                    _result = _reply.readInt();                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }        }        static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);    }    public int add(int arg1, int arg2) throws android.os.RemoteException;}

以上代碼都是AS自動產生的,如此一來,開發人員更加容易來實現AIDL跨處理序間通訊。如有對以上代碼感興趣者,可自行學習。

編寫遠程服務
建立MyServer類實現遠程服務代碼如下:
public class MyServer extends Service {    IMyAidlInterface.Stub mStub = new IMyAidlInterface.Stub() {        public int add(int arg1, int arg2) {            return arg1 + arg2;        }    };    @Override    public IBinder onBind(Intent intent) {        return mStub;    }}

服務代碼也很簡單,僅僅實現了IMyAidlInterface.Stub類中的 add方法,然後重寫了Service的onBind方法。

記得在AndroidManifest.xml中配置MyServer服務,代碼如下:

<?xml version="1.0" encoding="utf-8"?><manifest package="com.example.xjp.aidl"          xmlns:android="http://schemas.android.com/apk/res/android">    <application        android:allowBackup="true"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme">        <service            android:name="com.example.xjp.aidl.MyServer"            android:process=":remote">            <intent-filter>                <action android:name="com.xjp.myService"></action>            </intent-filter>        </service>    </application></manifest>

以上代碼給當前service設定了 android:process屬性為“:remote”,這個屬性有兩種賦值,一是:”:remote”,一是:”remote”,區別在於字串前面帶有”:”,後面的字串不一定是remote,開發人員可以隨意設定。

兩者代表不同意思,帶有”:”的表示該服務所在的進程是私人的,即只要有用戶端去啟動該服務,系統就會建立一個新的進程來運行該服務。

不帶有”:”的表示該服務所在的進程是共用的,即當前系統不管有幾個用戶端去啟動該服務,系統中只有一個進程來運行該服務。

用戶端

用戶端代碼相對簡單些,建立MyAidlDemoCustomer工程,然後直接把服務端的aidl目錄直接拷貝到用戶端的main目錄下。這麼一來用戶端的aidl就無需編寫了,直接和服務端的一模一樣。包括路徑的包名等。雖然你可以自己在用戶端在寫一遍aidl代碼,為了不出錯,請直接將服務端的aidl代碼直接拷貝過來。

用戶端調用代碼如下
package com.example.xjp.myaidldemocustomer;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.widget.ImageView;import android.widget.TextView;import com.example.xjp.aidla.IMyAidlInterface;public class MainActivity extends Activity {    IMyAidlInterface mStub;    TextView txt;    private ServiceConnection serviceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            Log.e("xjp", "the Connected====>" + System.currentTimeMillis());            mStub = IMyAidlInterface.Stub.asInterface(service);            if (mStub == null) {                Log.e("xjp", "the mStub is null");            } else {                try {                    int value = mStub.add(1, 8);                    txt.setText(value + "");                } catch (RemoteException e) {                    e.printStackTrace();                }            }        }        @Override        public void onServiceDisconnected(ComponentName name) {        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        txt = (TextView) findViewById(R.id.text);        Intent intent = new Intent();        //android 5.0以後直設定action不能啟動相應的服務,需要設定packageName或者Component。        intent.setAction("com.xjp.myService");        intent.setComponent(new ComponentName("com.example.xjp.aidl", "com.example.xjp.aidl.MyServer"));        //綁定服務        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);        Log.e("xjp", "the bindServer start..====>" + System.currentTimeMillis());    }    @Override    protected void onDestroy() {        //解除綁定服務        unbindService(serviceConnection);        super.onDestroy();    }}

如此一來,用戶端也寫好了。先安裝服務端,在安裝用戶端。進入用戶端之後實現了遠程調用Service。

AIDL跨進程傳遞Bitamp對象

以上是最簡單的 aidl跨進程傳遞java基本類型資料,最近在項目中遇到這麼個需求,跨進程傳遞bitmap圖片。當時看到這個需求就懵逼了,後來仔細分析其實是可以實現Android 利用Aidl實現跨進程傳遞 Bitmap對象。那麼該怎麼實現呢?

我們都知道Aidl支援跨進程傳遞 Java基礎資料型別 (Elementary Data Type)中包括byte這個類型,那麼思路是不是來了呢?我們可以在服務端將需要傳遞的圖片由bitmap轉換成 byte[]類型。代碼如下:

 public byte[] getBitmap() {        Bitmap bitmap = BitmapFactory.decodeResource(MyServer.this.getResources(), R.drawable.bg_top);        ByteArrayOutputStream baos = new ByteArrayOutputStream();        bitmap.compress(Bitmap.CompressFormat.PNG, 90, baos);//壓縮位元影像        return baos.toByteArray();//建立分配位元組數組    }

如此一來就將Bitmap對象轉換成byte[]類型了,現在aidl就可以跨進程傳遞byte[]類型資料。

在用戶端你只需要將遠程調用得到的byte[]類型轉換成Bitmap對象,然後顯示即可。用戶端代碼如下:

byte[] bytes = mStub.getBitmap();Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);img.setImageBitmap(bitmap);

是不是很簡單,其實Aidl傳遞圖片只是將Bitamp對象轉換成byte[]類型,然後由byte[]類型在轉換回Bitmap對象的一個過程。

  • 注意:在親測的過程中發現,利用aidl傳遞Bitamp對象是有一定的限制的,當Bitmap達到一定大小時是Aidl跨進程傳遞會失敗。所以,利用Aidl跨進程可以傳遞較小的圖片,至於多大可以根據你需求測試以免出錯。這也是由於Aidl跨進程傳遞資料是有限的,資料過大就不適合利用aidl誇進程傳遞了,應該用Socket傳遞。因為Aidl跨處理序間通訊是一個即時的,同步的的一個過程,即Aidl的遠程調用方法不能被阻塞,因此不能傳遞大資料。
總結

這是一個在AS下最簡單的一個AIDL編程:
1.服務端建立一個aidl目錄,然後在該目錄下建立一個.aidl為尾碼的介面類,該類定義遠程調用的介面方法。
2.build編譯之後會在app/build/generated/source/aidl/debug目錄下會產生aidl遠程實作類別,該類是AS自動產生的。
3.在AndroidManifest.xml下配置Service的action和process屬性。
4.將服務端的aidl目錄拷貝到用戶端相應的目錄下,然後編寫用戶端調用代碼,AS下簡單的aidl編程就ok了。

5.利用Aidl實現跨進程傳遞較小的Bitmap對象。

Android studio 下的aidl編程實現Android的誇處理序間通訊

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.