1. 程式人生 > >Android-bindService遠端服務(Aidl)-初步

Android-bindService遠端服務(Aidl)-初步

之前上一篇講解到本地服務,本地服務只能在自身APP中Activity訪問Service,呼叫Service裡面到方法等操作

如果想A應用訪問B應用裡面的方法,屬於跨程序呼叫,如果Android不特供這種跨程序間通訊等API,是不能實現的

Google Android 為了解決 A應用--->B應用 跨程序訪問通訊,提供了一種機制,就是IBInder,這種IBinder機制是Google工程師加入進去的,以前的Linux裡是沒有這個機制的

bindService 會返回IBinder介面,IBinder就是Google工程師在為了解決這種跨應用跨程序通訊,IBinder還需要結合Aidl才能實現遠端服務(跨程序跨應用通訊)

 

注意:⚠️以前本地服務是通過顯示意圖去繫結,現在遠端服務由於無法拿到另外應用的位元組碼,只能隱士意圖去繫結

 

Service2,作為服務端,需要把MyService暴露出去

    <!--
        android:process=":remote",代表在應用程式裡,當需要該service時,會自動建立新的程序。
        而如果是android:process="remote",沒有“:”分號的,則建立全域性程序,不同的應用程式共享該程序。
        -->
        <service android:name
=".service.MyService" android:exported="true" android:enabled="true" android:process=":remote"> <!-- 允許對外輸出 --> <!-- 想要其他應用程式可以訪問我的訪問,就必須要對外暴漏 --> <intent-filter> <action android:name
="liudeli.service2.service.MyService" /> </intent-filter> </service>

 

Service2,把邏輯都解除安裝MyService

package liudeli.service2.service;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;

import liudeli.service2.IMusician;
import liudeli.service2.service.inter.ISinger;

public class MyService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        // return new MyBinder(); 以前這種方式只適合本地服務(自身APP)
        return new MyBinderAidl();
    }

    /**
     * 以前本地服務的方式
     */
    /*class MyBinder extends Binder implements ISinger {

        *//**
         * 通過ID查詢歌手姓名
         *
         * @param id
         * @return
         *//*
        @Override
        public String querySingerNameByID(int id) {
            String result = null;
            switch (id) {
                case 1:
                    result = "黃家駒";
                    break;
                case 2:
                    result = "王傑";
                    break;
                case 3:
                    result = "陳百強";
                    break;
                default:
                    result = "張雨生";
                    break;
            }
            return result;
        }
    }*/

    /**
     * AIDL的方式,只有這種方式才能完成遠端服務
     */
    class MyBinderAidl extends IMusician.Stub {

        @Override
        public String querySingerNameByID(int id) throws RemoteException {
            String result = null;
            int result2 = 0;
            switch (id) {
                case 1:
                    result = "黃家駒";
                    result2 = 210000;
                    break;
                case 2:
                    result = "王傑";
                    result2 = 180000;
                    break;
                case 3:
                    result = "陳百強";
                    result2 = 200000;
                    break;
                default:
                    result = "張雨生";
                    result2 = 200090;
                    break;
            }
            return result;
        }
    }
}

 

Service2,以前本地服務介面的定義:

package liudeli.service2.service.inter;

import java.lang.String;

public interface ISinger {

    /**
     * 通過ID查詢歌手姓名
     * @param id
     * @return
     */
    public String querySingerNameByID(int id);

}

 

Service2,現在遠端服務的AIdl語言介面的定義:

// IMusician.aidl
package liudeli.service2;

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

interface IMusician {

    /**
     * 通過ID查詢歌手姓名
     * @param id
     * @return
     */
     String querySingerNameByID(int id);
}

 

----------------------------- 分割線 下面程式碼是 Service1 訪問者相關的了 

 

 Service1,⚠️要把Service2 aidl 帶包一起copy到Service1,保持aidl相關一模一樣

 

Service1,繫結遠端服務相關程式碼

package liudeli.service1;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.widget.Toast;

import liudeli.service2.IMusician;

public class RemoteActivity extends Activity {

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

        bindServiceAction();
    }

    /**
     * Activity初始化的時候繫結服務
     */
    private void bindServiceAction() {
        Intent intent = new Intent();
        intent.setAction("liudeli.service2.service.MyService");
        // android 5.0以後直設定action不能啟動相應的服務,需要設定packageName或者Component
        intent.setPackage("liudeli.service2");
        bindService(intent, connection, BIND_AUTO_CREATE);
    }

    private IMusician iMusician;

    /**
     * 定義服務連線物件,用於連線遠端服務
     */
    private ServiceConnection connection = new ServiceConnection() {
        /**
         * 服務連線成功
         * @param name 可以獲取到服務到完整資訊
         * @param service 服務那邊返回到IBinder介面
         */
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 這裡和本地服務不同,本地服務是強制型別轉換,遠端服務直接使用代理完成
            iMusician = IMusician.Stub.asInterface(service);
        }

        /**
         * 服務斷開連線
         * @param name
         */
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    /**
     * 查詢遠端服務裡面的資料
     * @param view
     */
    public void queryRemoteService(View view) {
        if (null == iMusician) {
            Toast.makeText(this, "繫結遠端服務失敗,無法查詢", Toast.LENGTH_LONG).show();
            return;
        }
        try {
            String result = iMusician.querySingerNameByID(1);
            Toast.makeText(this, "查詢成功:" + result, Toast.LENGTH_LONG).show();
        } catch (RemoteException e) {
            e.printStackTrace();
            Toast.makeText(this, "遠端服務失敗 遠端異常", Toast.LENGTH_LONG).show();
        }
    }

    /**
     * Activity結束時,記得一定要解綁服務,否則會報連線資源異常
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(connection);
    }
}

 

Layout相關程式碼:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="queryRemoteService"
        android:text="查詢遠端服務"
        />

</LinearLayout>

 

結果: