Android跨進程通訊

  • Bundle
  • 文件共享
  • ContentProvider
  • Socket
  • Messenger
  • AIDL

Bundle

先看下撥打電話的代碼java

Uri uri = Uri.parse("smsto:10086");
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
Bundle bundle = new Bundle();
bundle.putString("sms_body", "SMS Text");
intent.putExtras(bundle);
//  intent.putExtra("sms_body", "SMS Text");
startActivity(intent);
複製代碼

可見,經過將數據存儲在Intent的Bundle中,能夠在不一樣進程/APP間傳遞數據。android

文件共享

經過將數據寫入到一個文件中,不一樣進程能夠對這個文件進行讀取訪問,來達到跨進程通訊目的。 不過,多進程同時訪問一個文件,存在併發和IO性能低的問題。數據庫

ContentProvider

Android四大組件之一,提供訪問數據的統一格式。數據來源能夠是文件、數據庫。 能夠對外提供訪問的接口,實現跨進程/APP訪問。編程

private void readContacts() {
    //用於查詢電話號碼的URI
    Uri phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
    // 查詢的字段
    String[] projection = {
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,//通信錄姓名
            ContactsContract.CommonDataKinds.Phone.DATA1, "sort_key",//通信錄手機號
            };
    Cursor cursor = getContentResolver().query(phoneUri, projection, null, null, null);
    while ((cursor.moveToNext())) {
        String name = cursor.getString(0);
        String phone = cursor.getString(1);
    }
}
複製代碼

Socket

Socket主要分爲兩種bash

  • StreamSocket:基於TCP協議的封裝,以流的方式提供數據交互服務,提供了穩定的雙向通訊,經過「三次握手」創建鏈接,傳輸數據具備較高的穩定性。 Java中客戶端使用Socket類,服務器端使用ServerSocket類。
  • DatagramSocket:基於UDP協議的封裝,以數據報文的方式提供數據交互服務,提供了不穩定的單向通訊,具備更好的執行效率,因爲基於無鏈接的方式,傳輸數據不穩定,不保證數據的完整性。 Java中使用DatagramPacket類,表示數據報包;DatagramSocket類,進行端到端通訊。

Messager

底層也是經過封裝AIDL來實現的,因此使用的方式和AIDL基本相似。服務器

  1. 在服務端進程Service中建立Messenger對象,用來接收客戶端發來的Message數據,和獲取客戶端Messenger對象,並給客戶端發Message數據。
  2. 建立客戶端Messenger對象,用來接收服務端數據。
  3. 客戶端綁定服務端服務,並獲取服務端Messenger對象,用來給服務端發Message數據。
  4. 經過服務端Messenger發消息,將客戶端Messenger對象,添加到Message.replyTo。
public class MsgerService extends Service {
    private Messenger mServerMessenger = new Messenger(new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            // 接收客戶端發過來的消息
            switch (msg.what) {
                case 1000:

                    Toast.makeText(getBaseContext(), "" + msg.arg1, Toast.LENGTH_SHORT).show();

                    Message cMsg = Message.obtain();
                    cMsg.what = msg.what;
                    Bundle bundle = new Bundle();
                    bundle.putString("name", "Jim");
                    cMsg.obj = bundle;

                    // 獲取客戶端的Messenger對象,須要客戶端在發送消息時設置
                    Messenger cMsger = msg.replyTo;
                    try {
                        // 給客戶端發送消息
                        cMsger.send(cMsg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
            }
        }
    });
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mServerMessenger.getBinder();
    }
}
複製代碼
public class ClientActivity extends Activity {
    private TextView mNameTxt;

    /**
     * 客戶端Messenger對象,用來接收服務端數據
     */
    private Messenger mClientMessenger = new Messenger(new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 1000:
                    // 接收服務端數據
                    Bundle bundle = (Bundle) msg.obj;
                    mNameTxt.setText(bundle.getString("name"));
                    break;
            }
        }
    });

    /**
     * 服務端Messenger對象,創建鏈接時獲取,用來給服務端發消息
     */
    private Messenger mServerMessenger;
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 獲取服務端Messenger對象
            mServerMessenger = new Messenger(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mServerMessenger = null;
        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_common);

        mNameTxt = (TextView) findViewById(R.id.name);

        // 綁定遠端服務
        Intent intent = new Intent(this, MsgerService.class);
        bindService(intent, mConnection, BIND_AUTO_CREATE);

        findViewById(R.id.bind).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                int number = (int) (Math.random() * 100);
                Message msg = Message.obtain();
                msg.what = 1000;
                msg.arg1 = number;
                msg.replyTo = mClientMessenger;

                // 給服務端發送消息
                if (mServerMessenger != null) {
                    try {
                        mServerMessenger.send(msg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }
}
複製代碼

AIDL

AIDL(Android Interface Definition Language)指的就是接口定義語言,經過它可讓客戶端與服務端在進程間使用共同承認的編程接口來進行通訊 AIDL使用的步驟相對較多,主要總結爲三個基本步驟:併發

  • 建立AIDL接口dom

  • 根據AIDL建立遠程Service服務ide

  • 綁定遠程Service服務性能

(1)建立AIDL接口

定義aidl接口文件

在Android Studio中已經集成好了這個文件的建立方式,直接右擊工程,點擊New -> AIDL -> AIDL File,而後輸入接口的名稱就好,將會在src/main目錄下建立一個與java目錄平級,且裏面的包名與java目錄裏的包名一致,後綴爲.aidl的文件

// Declare any non-default types here with import statements

interface IMyAidlTest {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}
複製代碼

上面這個文件是Android Studio自動建立的模版文件,裏面的basicTypes方法不須要使用到能夠刪掉。 AIDL對數據類型的支持包括Java中的全部基本數據類型,還有String、CharSequence、List、Map。

自定義AIDL的數據類型

在AIDL提供的默認數據類型沒法知足需求的狀況下,就須要自定義數據類型了 好比咱們有個Product類,須要用來傳遞數據,那麼這個類必需要實現Parcelable接口,並在AIDL中新建一個相同類名的aidl文件進行聲明,而且這個aidl文件所在的路徑必需要和java文件裏的實體類路徑保持一致,如如下文件Product.aidl

package demo.csdn.zhuwentao.bean;

parcelable Product;
複製代碼

而後在IMyAidlTest.aidl中使用import導入進來,除了AIDL默認支持的數據類型外,其它自定義的類型都須要經過此方法導入進來,包名路徑須要精確到類名。

interface IMyAidlTest {
    void addProduct(in Product person);
    List<Product> getProductList();
}
複製代碼

這裏的方法只做爲接口聲明的做用,以上定義的接口最終會在Service服務裏實現具體的操做邏輯。

根據aidl文件生成java接口文件

這個步驟Android Studio已經幫咱們集成好了,只須要點擊 Build -> Make Project,或者點擊AS上的那個小錘子圖標就能夠,構建完後將會自動根據咱們定義的IMyAidlTest.aidl文件生成IMyAidlTest.java接口類,能夠在build/generated/source/aidl/debug/路徑下找到這個類。

(2)根據AIDL建立遠程Service服務

上一步中建立好的IMyAidlTest.java接口文件,須要使用Service來進行綁定,這裏就須要咱們新建一個Service服務。

/**
 * 根據AIDL建立遠程Service服務端
 */
public class MyAidlService extends Service {

    private List<Product> mProducts;
    public MyAidlService() {
    }

    private IBinder mIBinder = new IMyAidlTest.Stub() {

        @Override
        public void addProduct(Product product) throws RemoteException {
            mProducts.add(product);
        }

        @Override
        public List<Product> getProductList() throws RemoteException {
            return mProducts;
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        mProducts = new ArrayList<>();
        return mIBinder;
    }
}
複製代碼

mIBinder對象實例化了IMyAidlTest.Stub,並在回調接口中實現了最終的處理邏輯 當與客戶端綁定時,會觸發onBind()方法,並返回一個Binder對象給客戶端使用,客戶端就能夠經過這個類調用服務裏實現好的接口方法 記得要在配置文件中加入聲明,並使用android:process屬性指定其運行在新的進程中。

<service
    android:name=".MyAidlService"
    android:process=":process"/>
複製代碼

配置好以上步驟後,跨進程通訊的服務端就配置好了

(3)綁定遠程Service服務

跨進程通訊服務端實現好了後,就能夠在客戶端中開始調用它了,首先在Activity中先建立好服務鏈接對象

private IMyAidlTest mAidlTest;

private ServiceConnection mServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mAidlTest = IMyAidlTest.Stub.asInterface(service);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        mAidlTest = null;
    }
};
複製代碼

再經過Intent的bindService來綁定Service服務,創建起鏈接

Intent intent = new Intent(getApplicationContext(), MyAidlService.class);
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
複製代碼

啓動成功後,onServiceConnected方法將會在創建鏈接時被回調,回調時將生成一個接口實現mAidlTest對象,這個對象就是咱們進行跨進程操做調用對象 接下來就是經過這個mAidlTest對象來操做AIDL方法就行了。

private void addProduct(String name, int price) {
    Product pro = new Product();
    pro.mName = name;
    pro.mPrice = price;

    try {
        // 經過mAidlTest調用AIDL方法
        mAidlTest.addProduct(pro);
        List<Product> proLists = mAidlTest.getProductList();

        mAIDLTv.setText(proLists.toString());
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}
複製代碼

以上就是AIDL使用的基本步驟了。

參考:www.jianshu.com/p/b17f1276e…

相關文章
相關標籤/搜索