AIDLを模倣してプロセス間通信を実現


前言
この文章はAIDLをまねてプロセス間通信を実現し、プロセス間通信の全体の流れに慣れていない場合は、前の「Binder学習心得」という文章を見て、この文章をまとめた(彼はこの文章と相補的で、長すぎるため、別れざるを得ず、見ていても疲れている).そして,この文章と結びつけてプロセス間通信の印象を深めることができる.文の中に間違いがあったら、伝言をありがとうございます.他の学生が穴に入るのを避けます.
プロセスA、すなわちアプリケーションAのコード
まずAにサービスクラスを書くと、MyServiceはこのサービスを継承してサービスになりますが、次のコードからonBindという方法を書き換えたことがわかります.このサービスを統合すれば、この方法を実現しなければなりません.
 public class MyService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return myBinder;
    }

    //    
    ".MyService">
        
            "www.bjp.ftz.com" />//   B         
        
    

どうしてですか.このサービス類を見てみましょう.
 public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
        @Nullable
        public abstract IBinder onBind(Intent intent);
    }

上のセグメントコードから,サービスは抽象クラスであり,そのonBindは抽象メソッドであるため,サービスというクラスを継承するにはonBindというメソッドを実現しなければならないが,このメソッドは何のために用いられるのか.startServiceとbindServiceの違いはよく知られています.したがって、startserviceオープンサービスはonbindを呼び出すことはありません.bindServiceメソッドを呼び出すと、onBindメソッドはIBinderオブジェクトを呼び出して返します.このオブジェクトは私たちのBアプリケーションが持っているものです(実際には持っているものではありません.以下に説明します).
では、このIBinderオブジェクトは私たち自身で実現しました.このIBinderオブジェクトは2つの能力を持っています.1つは特殊なタスクを完了する能力で、1つはプロセスをまたいで伝送する能力です.では、どんな種類がこのような能力を持っているのでしょうか.それはBinderです.コードの断片を見てください.
 public class Binder implement IBinder{
        public void attachInterface(IInterface owner, String descriptor){
                mOwner = owner;
                mDescriptor = descriptor;
        }
        public IInterface queryLocalInterface(String descriptor) {
           if (mDescriptor.equals(descriptor)) {
                    return mOwner;
            }
            return null;
        }
        boolean onTransact(int code, Parcel data, Parcel reply, int flags)//               ,     。
        final class BinderProxy implements IBinder {
        ......//Binder      ,    《Binder    》         
        }
    }

OK,上のコードフラグメントからattachInterfaceメソッドがキー値ペアでIinterfaceオブジェクトを保持して特使タスクを完了することがわかる.queryLocalInterfaceメソッドは、Iinterfaceオブジェクトを特殊な値であるattachInterfaceメソッドのキー値で取得します.特殊能力は、プロセスをまたいで伝送する能力がこのonTransact方法です.今は不詳ですが、彼がここで伝送をすればいいことを知っています.
Ok、特殊な任務を遂行する能力とプロセスをまたがる伝送能力について話しました.では、このBinderを継承してこの2つの能力を獲得しましょう.MyBinderはBinderを継承し、onTransactメソッドを再書き込みします.
    class MyBinder extends Binder {
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            return super.onTransact(code, data, reply, flags);
        }
    }

IBinderという相手が特殊な任務を遂行する能力を持っていると言ったら、MyServiceはこう書きます.
 public class MyService extends Service {
        public static String MYBINDER = "this";//         ,       IInterface  。
        @Override
        public IBinder onBind(Intent intent) {
            MyBinder myBinder = new MyBinder();
            myBinder.attachInterface(new MyBusiness(), MYBINDER);//          IInterface  。            。
            return myBinder;
        }
    }

ええ.このMyBusinessは何の鬼ですか.これがその特殊な任務ですね.加算しましょう(*^^*)コードは以下の通りです.
 class MyBusiness implements IInterface {
        public int add(int a, int b) {
            return a + b;
        }
        /**
         * Retrieve the Binder object associated with this interface.
         * You must use this instead of a plain cast, so that proxy objects
         * can return the correct result.
         */
        @Override
        public IBinder asBinder() {//     IInterface
            return null;
        }
    }

OK、Aアプリのこちらの全体的な構造は書き終わったので、業務を記入していませんが、まずBアプリがこのAアプリにバインドされているのを見てみましょう.どうやって通信したんだ?
Bアプリケーション、クリックしてバインドを開始します.コードは次のとおりです.
    tv.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intent = new Intent();
                intent.setAction("www.bjp.ftz.com");
                bindService(intent, conn, BIND_AUTO_CREATE);
                Toast.makeText(MainActivity.this, "   ", Toast.LENGTH_LONG).show();
            }
        });
    ServiceConnection conn = new ServiceConnection(){
        @Override
        public void onServiceConnected(ComponentName name, IBinder service){
            MainActivity.this.service = service;
            System.out.println(service);
            setData();
        }
        @Override
        public void onServiceDisconnected(ComponentName name){

        }
    };

上記の手順を簡単に説明すると、bindServiceというメソッドを呼び出してServiceManagerというクラスにオープンサービスを要求すると、ServiceManagerサービスはこのサービスを見つけてこのサービスonBindメソッドを呼び出してIBinderオブジェクトを取得し、このIBinderオブジェクトによってBindProxyというエージェントオブジェクト(前述)を取得します.次に、ServiceConnectionのonServiceConnectedメソッドでIBinderオブジェクトを取得し、このIBinderオブジェクトがBindProxyオブジェクトであることを示すように出力します.△疑問があれば、私の前の文章「Binder学習心得」を見に行ってください.
    bjp.ftz.bindertest_b I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@4296ea80 time:26434129

OK、私たちが得たのはBinderの中の内部クラスであることが証明されています.では、BindProxyという内部クラスのコードクリップを見てみましょう.
    final class BinderProxy implements IBinder {
        //     IBinder    
        public IInterface queryLocalInterface(String descriptor) {
            return null;
        }
        /**
         * Perform a generic operation with the object.
         *
         * @param code The action to perform.  This should
         * be a number between
         * @param data Marshalled data to send to the target.Mustnot be null.
         * If you are not sending any data, you must create an empty Parcel
         * that is given here.
         * @param reply Marshalled data to be received from the target.  May be
         * null if you are not interested in the return value.
         * @param flags Additional operation flags.  Either 0 for a normal
         * RPC
         */
         //     IBinder    
        public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
            return transactNative(code, data, reply, flags);
        }

上のコードからBinderProxyを通過したいことがわかります.queryLocalInterfaceメソッドでIinterfaceオブジェクトを取得することはできません.NULLを返します.では、どうすればいいのでしょうか.そしてtransactメソッドに集まりました.Perform a generic operation with the object.共通の操作オブジェクトを実行することを意味します.言うまでもありません.この方法では、4つのパラメータが必要です.最初のパラメータは、どのメソッドを調整するかを表す動作です.2番目は転送するデータ、3番目に返されるデータ、4番目は...コメントは0が正常表示なので0にします(*^^*)OK、パラメータの構築を開始します.
     @Override
        public void onServiceConnected(ComponentName name, IBinder service){
            Parcel parcel = Parcel.obtain();//     
            Parcel obtain = Parcel.obtain();//     
            parcel.writeInterfaceToken("this");//  this        ,   A                  this   。                   
            parcel.writeInt(5);//  a = 5
            parcel.writeInt(5);//  b = 5
            try {
                boolean transact = service.transact(1, parcel, obtain, 0);//     ,    boolean         。
                if(transact){//    ,             。
                    obtain.readException();
                    int i = obtain.readInt();
                    System.out.println(i + "=============");
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

サービスとしてtransact(1,parcel,obtain,0);実行後、AアプリケーションのonTransactというメソッドを呼び出してデータ読み込みを行います(そうですね.このメソッドは彼の伝送機能を実現しました).OK,AアプリケーションはBアプリケーションから転送されたデータの読み取りを開始した.(前述した特殊な機能の残りの半分が実現し始めたことに注意してください).コードは次のとおりです.
     @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch (code){// B   transact         。               。
                case 1: 
                    data.enforceInterface("this");//               B   parcel.writeInterfaceToke  
                    int a = data.readInt();//  a
                    int b = data.readInt();//  b
                    int add = ((MyBusiness)//    
                    //         myBinder.attachInterface     IInterface  ,(         )   add        。
                    this.queryLocalInterface("this")).add(5, 5);
                    reply.writeNoException();
                    reply.writeInt(add);//     B  
                    return true;//  true          
            }
            return super.onTransact(code, data, reply, flags);
        }

OK、通信全体がこのように書き終わったので、Bアプリが受信したデータは間違いなく10(*^^*)になります.
もしあなたが全体の流れを歩いて下りてきたら、AIDLが自動的に生成したソースコードはそんなに難しくないことに気づきます.ここではAIDLと比較しないで、自分で比較して、は~~~~~~.