二、IPC机制续(IPC方式)

IPC机制

具体方式有很多,比如可以在Intent中附加Extra来传递信息,或者通过共享文件的方式来共享数据,还可以采用Binder方式来跨进程通信,另外,Content Provider天生就是支持跨进程访问的,因此,我们也可以使用它来进行IPC,另外通过网络通信也是可以实现数据传递的,所以Socket也可以实现IPC。

1.使用Bundle

由于Bundle实现了Parcelable接口,所以它可以方便地在不同进程间传输。

除了直接传递数据这种典型的使用场景,他还有一种特殊的使用场景,如A进程正在进行计算,计算完成之后需要把结果传递给B进程,但是这个结果不支持放入Bundle中,那么可以这样考虑,A中,通过Intent启动B进程的一个Service组件(如IntentService),让Service进行后台计算,计算完毕之后,再启动B进程中真正想要启动的组件由于Service也在B进程中,所以目标组件就可以直接获取结果。

        findViewById(R.id. button).setOnClickListener( new OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setClass(MainActivity. this, SecondActivity.class);
                User user = new User(0, "jake", true);
                user. book = new Book();
                intent.putExtra( "extra_user", (Serializable) user);
                startActivity( intent);
            }
        });
2.使用文件共享

两个进程通过读写同一个文化夹来交换数据,比如A进程把数据写进文件,B进程通过读取这个文件来获取数据。Linux使得并发读写文件可以没有限制,甚至两个线程同时对一个文件进行读写都是运行的。

希望在ManActivity中的onResume中序列化一个User对象到SDk卡上面的一个文件里面,在SecondActivity的onResume中去反序列化。

MainActivity:onResume执行下面的方法
      private void persistToFile() {
             new Thread( new Runnable() {
                   @Override
                   public void run() {
                        User user = new User(1, "hello world", false);
                        File dir = new File(MyConstants. CHAPTER_2_PATH);
                         if (! dir.exists()) {
                               dir.mkdirs();
                        }
                        File cachedFile = new File(MyConstants. CACHE_FILE_PATH );
                        ObjectOutputStream objectOutputStream = null;
                         try {
                               objectOutputStream = new ObjectOutputStream(
                                           new FileOutputStream(cachedFile));
                               objectOutputStream.writeObject( user);
                              Log. d(TAG, "persist user:" + user);
                        } catch (IOException e) {
                               e.printStackTrace();
                        } finally {
                              MyUtils. close(objectOutputStream);
                        }
                  }
            }).start();
      }
SecondActivity中取:
    private void recoverFromFile() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                User user = null;
                File cachedFile = new File(MyConstants. CACHE_FILE_PATH);
                if ( cachedFile.exists()) {
                    ObjectInputStream objectInputStream = null;
                    try {
                        objectInputStream = new ObjectInputStream(
                                new FileInputStream( cachedFile));
                        user = (User) objectInputStream.readObject();
                        Log. d(TAG, "recover user:" + user);
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    } finally {
                        MyUtils. close(objectInputStream);
                    }
                }
            }
        }).start();
    }

当然这种不支持并发,如果想要并发,需要使用线程同步机制来解决。SharePreferences是个特例,通过键值对来存储数据,底层采用xml来存储键值对,位置在/data/data/packagename/shared_prefs目录下面,从本质来说SharePreferences也属于文件的一种,但是由于系统对它的读写有一定的缓存策略,即在内存里面有一份SharePreferences文件的缓存,因此在多进程模式下,系统对他的读写变得不可靠,当面对高并发的读写访问就有很大几率丢失数据,因此不建议进程间通信使用SP。

3.使用Messenger

Messenger是一种轻量级的IPC方案,它的底层实现是AIDL。从构造方法可以很明显的看出AIDL的痕迹。

public Messenger(Handler target) {
     mTarget = target.getIMessenger();
}

public Messenger(IBinder target) {
     mTarget = IMessenger.Stub.asInterface(target);
}

Messenger的使用方法很简单,它对AIDL做了封装,使得我们可以更简单地进行线程间通信,同时由于它一次处理一个请求,因此在服务端我们不用考虑线程同步的问题,这个是因为服务端不存在并发执行的情况。

步骤:
1.服务端进程,首先我们要创建一个Service来处理客户端的请求,同时创建一个Handler并通过它来创建一个Messenger对象,在Service的onBind里面返回这个Messenger对象底层的Binder即可。
2.客户端进程,首先要绑定服务端的Service,绑定成功之后用服务端返回的IBinder对象创建一个Messenger,通过这个Messenger就可以向服务端发送消息了发送消息类型为Message对象。

如果要服务端能够回应客户端,就和服务端一样,需要创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务端,服务端通过这个replyTo参数就可以回应客户端。

服务端:
public class MessengerService extends Service {
    private static final String TAG = "MessengerService";
    private static class MessengerHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch ( msg. what) {
            case MyConstants. MSG_FROM_CLIENT:
                Log. i(TAG, "receive msg from Client:" + msg.getData().getString( "msg"));
                Messenger client = msg. replyTo;
                Message relpyMessage = Message. obtain(null, MyConstants.MSG_FROM_SERVICE );
                Bundle bundle = new Bundle();
                bundle.putString( "reply", "嗯,你的消息我已经收到,稍后会回复你。" );
                relpyMessage.setData( bundle);
                try {
                    client. send(relpyMessage);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
            default:
                super.handleMessage( msg);
            }
        }
    }
    private final Messenger mMessenger = new Messenger( new MessengerHandler());
    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand( intent, flags, startId);
    }
}
客户端:
public class MessengerActivity extends Activity {
    private static final String TAG = "MessengerActivity";
    private Messenger mService;
    private Messenger mGetReplyMessenger = new Messenger( new MessengerHandler());
    private static class MessengerHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch ( msg. what) {
            case MyConstants. MSG_FROM_SERVICE:
                Log. i(TAG, "receive msg from Service:" + msg.getData().getString( "reply"));
                break;
            default:
                super.handleMessage( msg);
            }
        }
    }
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            mService = new Messenger( service);
            Log. d(TAG, "bind service");
            Message msg = Message. obtain(null, MyConstants.MSG_FROM_CLIENT );
            Bundle data = new Bundle();
            data.putString( "msg", "hello, this is client.");
            msg.setData( data);
            msg. replyTo = mGetReplyMessenger;
            try {
                mService.send( msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        public void onServiceDisconnected(ComponentName className) {
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate( savedInstanceState);
        setContentView(R.layout. activity_messenger);
        Intent intent = new Intent( "com.ryg.MessengerService.launch");
        bindService( intent, mConnection, Context. BIND_AUTO_CREATE);
    }
    @Override
    protected void onDestroy() {
        unbindService( mConnection);
        super.onDestroy();
    }
}
Mainfest里面:
        <activity
            android:name= ".messenger.MessengerActivity"
            android:label= "@string/title_activity_messenger" >
            <intent-filter >
                <action android:name ="android.intent.action.MAIN" />
            </intent-filter >
        </activity >

        <service
            android:name= ".messenger.MessengerService"
            android:process= ":remote" >
            <intent-filter >
                <action android:name ="com.ryg.MessengerService.launch" />
            </intent-filter >
        </service >

注意:
通过Messenger来传递Message,Message中能用的载体只有what,arg1,arg2,Bundle以及replyTo。Message中的另外一个字段object在同一个进程中是很实用的,但是在跨进程间通信的时候,在Android2.2以前object字段不支持跨进程传输,
即使2.2以后,也仅仅是系统提供的实现了Parcelable接口的对象才能通过它来传输。这就意味着我们自定义的Parcelable对象是无法通过object字段来传输的。

Messenger的工作原理图:
Messenger的工作原理

4.使用AIDL

由于Messenger的主要作用还是传递消息,有时候可能需要跨进程调用服务端的方法,那么Messenger就不行了。
使用AIDL进行跨进程通信也分为客户端和服务端两个方面:
(1)服务端
服务端首先要创建一个Service用来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口咋这个AIDL文件中声明,最后在Service中实现这个AIDL接口即可。

(2)客户端
首先绑定服务端的Service,绑定成功之后,将服务端返回的Binder对象转换成AIDL接口所属的类型,接着就可以调用AIDL中的方法了。

(3)AIDL接口的创建

package com.ryg.chapter_2.aidl;
import com.ryg.chapter_2.aidl.Book;
interface IBookManager {
     List<Book> getBookList();
     void addBook(in Book book);
}

AIDL文件支持的数据类型:
1)基本数据类型(int,long,char,boolean,double等)
2)String和CharSquence
3)List,只支持ArrayList,里面的每个元素都要必须能被AIDL支持
4)Map,只支持HashMap,里面的每个元素都必须被AIDL支持,
包括Key和Value
5)Parcelable,所有实现了Parcelable接口的对象
6)AIDL,所有的AIDL接口本身也可以在AIDL文件中使用
以上的6种数据类型就是AIDL所支持的所有类型,其中自定义的Parcelable对象和AIDL对象必须要显式import进来,不管是否和当前的AIDL文件位于同一个包里面。
另外,如果AIDL文件里面用到了自定义的Parcelable对象,那么必须新建一个和它同名的AIDL文件,并在里面声明它为Parcelable类型。
在IBookManager.aidl文件中使用到了自定义的Book对象,所以必须创建Book.aidl在里面添加:

package com.ryg.chapter_2.aidl;
parcelable Book;

AIDL中每个实现了Parcelable接口的类型的类,都需要像上面那样去声明,创建对应的AIDL文件,并声明那个类为parcelable。除此之外,AIDL中除了基本数据类型,其他类型的参数必须标上方向,in,out或者inout,in表示输入型参数,out表示输出型参数,inout表示输入输出型参数。AIDL接口中只支持方法,不支持静态常量。

in,out,inout区别:
http://hold-on.iteye.com/blog/2026138
inout区别

inout区别

为了方便开发,建议把所有的和AIDL相关的类和文件全部放入同一个包中,这样的好处是,当客户端是另外的应用时,我们可以直接把整个包复制放入到客户端工程中。
AIDL包结构,在客户端和服务端要一致,否则会运行出错,这是因为客户端需要反序列化服务端中和AIDL接口相关的所有类。

(4)远程服务端的Service实现

public class BookManagerService extends Service {
    private static final String TAG = "BMS";
    private CopyOnWriteArrayList<Book> mBookList = 
    new CopyOnWriteArrayList<Book>();
    private Binder mBinder = new IBookManager.Stub() {
        @Override
        public List<Book> getBookList() throws RemoteException {
            return mBookList;
        }
        @Override
        public void addBook(Book book) throws RemoteException {
            mBookList.add( book);
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        mBookList.add(new Book(1, "Android"));
        mBookList.add(new Book(2, "Ios"));
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

}
        <service
            android:name= ".aidl.BookManagerService"
            android:process= ":remote" >
        </service >

采用CopyOnWriteArrayList,它支持并发读写,AIDL方法是在服务端的Binder线程池中执行的,因此当多个客户端同时连接的时候,会存在多个线程同时访问的问题,所以要在AIDL方法中处理线程同步,这里使用它来进行自动的线程同步。

服务端可以使用CopyOnWriteArrayList和ConcurrentHashMap来进行自动线程同步,客户端拿到的依然是ArrayList和HashMap。

(5)客户端的实现
客户端首先绑定远程服务,绑定成功之后将服务端返回的Binder对象转换成为AIDL接口,然后就可以通过这个接口去调用服务端的远程方法了。

public class BookManagerActivity extends Activity {
    private static final String TAG = "BookManagerActivity";
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            IBookManager bookManager = IBookManager.Stub.asInterface(service);
            try {
                List<Book> list = bookManager.getBookList();
                Log. i(TAG, "query book list, list type:"
                        + list.getClass().getCanonicalName());
                Log. i(TAG, "query book list:" + list.toString());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        public void onServiceDisconnected(ComponentName className) {
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate( savedInstanceState);
        setContentView(R.layout. activity_book_manager);      
        Intent intent = new Intent( this, BookManagerService. class);
        bindService( intent, mConnection, Context. BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        unbindService( mConnection);
        super.onDestroy();
    }

}

(6)监听
比如现在想服务端有新书的时候通知客户端,那么必须要监听了需要使用RemoteCallbackList,存储我们自定义的监听器,它是一个泛型,支持管理任意的AIDL接口。它的内部是Map结构,key是IBinder类型,value是Callback类型。

注意:
服务端和客户端之间做监听器,服务端需要使用RemoteCallbackList,否则客户端的监听器无法收到通知(因为服务端实质还是一份新的序列化后的监听器实例,并不是客户端那份)

RemoteCallbackList的beginBroadcast和finishBroadcast必须配对使用,哪怕我们仅仅需要获取RemoteCallbackList中的元素个数。

(7)不要在客户端的ui线程里面调用服务端的耗时方法
客户端调用远程服务方法时,因为远程方法运行在服务端的binder线程池中(服务端方法可以执行大量耗时操作,不需要开线程执行异步任务的);
同时客户端线程会被挂起,所以如果该方法过于耗时,而客户端又是UI线程,会导致ANR,所以当确认该远程方法是耗时操作时,应避免客户端在UI线程中调用该方法。
同理,当服务器调用客户端的listener方法时,该方法也运行在客户端的binder线程池中,所以如果该方法也是耗时操作,请确认运行在服务端的非UI线程中。
另外,因为客户端的回调listener运行在binder线程池中,所以更新UI需要用到handler。

(8)服务端进程意外终止
客户端通过IBinder.DeathRecipient来监听Binder死亡,也可以在onServiceDisconnected中监听并重连服务端。区别在于前者是在binder线程池中,访问UI需要用Handler,后者则是UI线程。

(9)权限验证
可通过自定义权限在onBind或者onTransact中进行权限验证。

onBind中验证,验证不通过返回null,验证方式可以使用permission验证,首先在manifest里面注册。

<permission
        android:name= "com.ryg.chapter_2.permission.ACCESS_BOOK_SERVICE"
        android:protectionLevel= "normal" />

就可以在onBind里面验证了。

      @Override
      public IBinder onBind(Intent intent) {
             int check = checkCallingOrSelfPermission("com.ryg.chapter_2.permission.ACCESS_BOOK_SERVICE" );
            Log. d(TAG, "onbind check=" + check);
             if ( check == PackageManager. PERMISSION_DENIED) {
                   return null;
            }
             return mBinder;
      }

一个应用来绑定我们的服务的时候,会验证这个应用的权限,没有权限就返回null。这个方法同样适用于Messenger中。

我们自己内部的应用想要绑定我们的服务,只需要在Manifest采用如下方式使用permission即可。

<uses-permission android:name="com.ryg.chapter_2.permission.ACCESS_BOOK_SERVICE" />

服务端的onTransact方法中进行权限验证,验证失败就会返回false,服务端的方法就不会执行,验证方式可以采用permission验证,也可以使用Uid和Pid来验证。通过getCallingUid和getCallingPid可以拿到客户端所属的应用的Uid和Pid,通过这两个参数可以做一些验证工作,比如验证包名。

下面即验证了权限又需要包名以com.rgy开始。

             public boolean onTransact( int code, Parcel data, Parcel reply, int flags)
                         throws RemoteException {
                   int check = checkCallingOrSelfPermission( "com.ryg.chapter_2.permission.ACCESS_BOOK_SERVICE" );
                  Log. d(TAG, "check=" + check);
                   if ( check == PackageManager. PERMISSION_DENIED) {
                         return false;
                  }

                  String packageName = null;
                  String[] packages = getPackageManager().getPackagesForUid(
                               getCallingUid());
                   if ( packages != null && packages. length > 0) {
                         packageName = packages[0];
                  }
                  Log. d(TAG, "onTransact: " + packageName);
                   if (! packageName.startsWith( "com.ryg")) {
                         return false;
                  }

                   return super.onTransact( code, data, reply, flags);
            }
5.使用ContentProvider

底层实现是AIDL,使用比AIDL简单许多。自定义ContentProvider需要继承ContentProvider并实现里面的方法即可,onCreate,query,update,insert,delete,getType,getType用来返回Uri请求所对应的MimeType。如果应用不关系这个,只需要返回null或者”/“,根据Binder,我们知道这6个方法均运行在ContentProvider的进程里面,除了onCreate方法由系统回调并运行在主线程里面,其余的5个均由外界调用并运行在Binder线程池中。

虽然ContentProvider的底层数据看起来很像一个SQLite数据库,但是它对底层的数据的存储方式没有任何要求,我们即可以使用SQLite,也可以使用普通文件,甚至可以采用内存中的一个对象来进行数据的存储。

注册android:authorities是它的唯一标识,建议命名的时候加上包名前缀,如果声明了权限,那么外界应用也需要相应的权限。

ContentProvider(有的手机上会出现不加uses-permission依然可以访问BookProvider的问题)

6.使用Socket
Socket 一般用于网络通信,AIDL用这种方式会过于繁琐,不建议。

7.Binder连接池
比如100个地方需要用到AIDL那么不可能创建100个Service,需要减少Service的数量,将AIDL放在同一个Service里面去管理。

Binder连接池的作用就是将每个业务模块的Binder请求统一转发到远程的Service中去。

Binder连接池

Binder连接池,通过BinderPool的方式将Binder的控制与Service本身解耦,同时只需要维护一份Service即可。这里用到了CountDownLatch,大概解释下用意:线程在await后等待,直到CountDownLatch的计数为0,BinderPool里使用它的目的是为了保证Activity获取BinderPool的时候Service已确定bind完成~

例子:
两个AIDL:

ISecurityCenter.aidl
package com.ryg.chapter_2.binderpool;
interface ISecurityCenter {
    String encrypt(String content);
    String decrypt(String password);
}
ICompute.aidl
package com.ryg.chapter_2.binderpool;
interface ICompute {
    int add( int a, int b);
}

实现:

public class SecurityCenterImpl extends ISecurityCenter.Stub {
    private static final char SECRET_CODE = '^';
    @Override
    public String encrypt(String content) throws RemoteException {
        char[] chars = content.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            chars[ i] ^= SECRET_CODE;
        }
        return new String(chars);
    }

    @Override
    public String decrypt (String password ) throws RemoteException {
        return encrypt( password);
    }

}

以及:

public class ComputeImpl extends ICompute.Stub {
    @Override
    public int add(int a, int b) throws RemoteException {
        return a + b;
    }
}

为Binder连接池创建AIDL接口IBinderPool.aidl

interface IBinderPool {
    /**
     * @param binderCode, the unique token of specific Binder<br/>
     * @return specific Binder who's token is binderCode.
     */
    IBinder queryBinder( int binderCode);
}

为Binder连接池创建远程Service并实现IBinderPool,
下面是queryBinder的实现:

        @Override
        public IBinder queryBinder( int binderCode) throws RemoteException {
            IBinder binder = null;
            switch ( binderCode) {
            case BINDER_SECURITY_CENTER: {
                binder = new SecurityCenterImpl();
                break;
            }
            case BINDER_COMPUTE: {
                binder = new ComputeImpl();
                break;
            }
            default:
                break;
            }
            return binder;
        }

远程Service的实现比较简单了:

public class BinderPoolService extends Service {
    private static final String TAG = "BinderPoolService";
    private Binder mBinderPool = new BinderPool.BinderPoolImpl();
    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public IBinder onBind(Intent intent ) {
        Log.d(TAG, "onBind");
        return mBinderPool;
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

下面还有Binder连接池的具体实现,首先绑定远程服务,成功之后,客户端就可以通过它的queryBinder方法获取各自对应的Binder,拿到所需要的Binder之后,不同的业务模块之间就可以进行各自的操作了。

public class BinderPool {
    private static final String TAG = "BinderPool";
    public static final int BINDER_NONE = -1;
    public static final int BINDER_COMPUTE = 0;
    public static final int BINDER_SECURITY_CENTER = 1;

    private Context mContext;
    private IBinderPool mBinderPool;
    private static volatile BinderPool sInstance;
    private CountDownLatch mConnectBinderPoolCountDownLatch;

    private BinderPool(Context context) {
        mContext = context.getApplicationContext();
        connectBinderPoolService();
    }

    public static BinderPool getInsance(Context context) {
        if (sInstance == null) {
            synchronized (BinderPool.class) {
                if (sInstance == null) {
                    sInstance = new BinderPool(context);
                }
            }
        }
        return sInstance;
    }

    private synchronized void connectBinderPoolService() {
        mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
        Intent service = new Intent(mContext, BinderPoolService.class);
        mContext.bindService(service, mBinderPoolConnection,
                Context.BIND_AUTO_CREATE);
        try {
            mConnectBinderPoolCountDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * query binder by binderCode from binder pool
     * 
     * @param binderCode
     *            the unique token of binder
     * @return binder who's token is binderCode<br>
     *         return null when not found or BinderPoolService died.
     */
    public IBinder queryBinder(int binderCode) {
        IBinder binder = null;
        try {
            if (mBinderPool != null) {
                binder = mBinderPool.queryBinder(binderCode);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return binder;
    }

    private ServiceConnection mBinderPoolConnection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // ignored.
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBinderPool = IBinderPool.Stub.asInterface(service);
            try {
                mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            mConnectBinderPoolCountDownLatch.countDown();
        }
    };

    private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            Log.w(TAG, "binder died.");
            mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);
            mBinderPool = null;
            connectBinderPoolService();
        }
    };

    public static class BinderPoolImpl extends IBinderPool.Stub {

        public BinderPoolImpl() {
            super();
        }

        @Override
        public IBinder queryBinder(int binderCode) throws RemoteException {
            IBinder binder = null;
            switch (binderCode) {
            case BINDER_SECURITY_CENTER: {
                binder = new SecurityCenterImpl();
                break;
            }
            case BINDER_COMPUTE: {
                binder = new ComputeImpl();
                break;
            }
            default:
                break;
            }

            return binder;
        }
    }

}

使用:

public class BinderPoolActivity extends Activity {
    private static final String TAG = "BinderPoolActivity";
    private ISecurityCenter mSecurityCenter;
    private ICompute mCompute;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate( savedInstanceState);
        setContentView(R.layout. activity_binder_pool);
        new Thread(new Runnable() {
            @Override
            public void run() {
                doWork();
            }
        }).start();
    }
    private void doWork() {
        BinderPool binderPool = BinderPool.getInsance(BinderPoolActivity. this);
        IBinder securityBinder = binderPool
                .queryBinder(BinderPool. BINDER_SECURITY_CENTER);
        mSecurityCenter = (ISecurityCenter) SecurityCenterImpl
                . asInterface(securityBinder);
        Log.d(TAG, "visit ISecurityCenter");
        String msg = "helloworld-安卓";
        System. out.println( "content:" + msg);
        try {
            String password = mSecurityCenter.encrypt( msg);
            System. out.println( "encrypt:" + password);
            System. out.println( "decrypt:" + mSecurityCenter.decrypt(password ));
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        Log.d(TAG, "visit ICompute");
        IBinder computeBinder = binderPool
                .queryBinder(BinderPool. BINDER_COMPUTE);        
        mCompute = ComputeImpl.asInterface(computeBinder );
        try {
            System. out.println( "3+5=" + mCompute.add(3, 5));
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}
8.选择适合的IPC方式

选择方式

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值