1、IPC机制
1、Android IPC简介
- IPC:含义为进程间通信或者跨进程通信。
2、Android中的多进程模式
- Android中开启多进程方法,就是给四大组件在AndroidMenifest指定android:process属性,还有一种非常规的,就是通过JNI在native层去fork一个新的进程。
- process指定进程命名:以":"开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中,而进程名不以":"开头的进程属于全局进程,其他应用通过ShareUID方式可以和它跑在同一个进程中。
- Android系统会为每个应用分配一个唯一的UID,具体相同UID的应该才能共享数据。两个应用通过ShareUID跑在同一个进程中是有要求的,需要这个两个应用的有相同的ShareUID并且签名相同才行。
- 多进程会造成:
静态成员和单例模式完全失效。
线程同步机制完全失效。
SharedPreferences的可靠性下降。
Application会多次创建。 - SharedPreferences不支持两个进程同时去执行写操作,否则会导致一定几率的数据丢失,这是因为SharedPreferences底层是通过读写XML文件来实现的,并发写显然3是可能出现问题的,甚至并发读都有可能出现问题。
3、IPC基础
-
Serializable
serialVersionUID是用来辅助序列化与反序列化的,比如删除某个成员变量或增加新的成员变量,如果不指定serialVersionUID那么程序会挂掉,但是如果类发生了非常规性改变,如修改类名,修改成员变量的类型,尽管指定serialVersionUID,反序列化还是失败。
静态成员变量属于类不属于对象,所以不会参与序列化过程,其次用transient关键字标记的成员变量不参与序列化过程。 -
Parcelable
Parcelable是Android中的序列化方式,效率很高,主要用在内存序列化,而Serializable的Java的序列化接口,虽然简单但开销大,需要大量I/O操作,主要是在文件序列化。 -
Binder
从IPC角度来说,Binder是Android中的一种跨进程通信方式;从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager等)和相应ManagerService的桥梁;从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindservice的时候,服务端会返回一个包含服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。
以AIDL来分析Binder机制:
AIDL:public interface IBookManager extends android.os.IInterface { /** * Binder类 */ public static abstract class Stub extends android.os.Binder implements com.myapplication.IBookManager { //Binder的唯一标识 private static final java.lang.String DESCRIPTOR = "com.myapplication.aidl.IBookManager"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * 用于将服务端的Binder对象转换成客户端所需要的AIDL接口类型的对象 * 在同一进程,返回服务端Stub对象本身,不在同一进程返回系统封装后的Stub.proxy对象 */ public static com.myapplication.IBookManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } //如果不是同一个进程,其实是Binder的内部类BinderProxy,它的queryLocalInterface返回null android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.myapplication.IBookManager))) { return ((com.myapplication.IBookManager) iin); } return new com.myapplication.IBookManager.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } /** * 运行在服务端的Binder线程池中,返回false,则客户端请求失败 */ @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_getBookList: { data.enforceInterface(DESCRIPTOR); java.util.List<com.myapplication.aidl.Book> _result = this.getBookList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addBook: { data.enforceInterface(DESCRIPTOR); com.myapplication.aidl.Book _arg0; if ((0 != data.readInt())) { _arg0 = com.myapplication.aidl.Book.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addBook(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.myapplication.IBookManager { 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; } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ @Override public java.util.List<com.myapplication.aidl.Book> getBookList() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); //输入型 android.os.Parcel _reply = android.os.Parcel.obtain(); //输出型 java.util.List<com.myapplication.aidl.Book> _result; //声明返回对象 try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0); //调用transact后会调用onTransact _reply.readException(); _result = _reply.createTypedArrayList(com.myapplication.aidl.Book.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void addBook(com.myapplication.aidl.Book book) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); if ((book != null)) { _data.writeInt(1); book.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } /** * 记录客户端请求那个方法 */ public static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); public static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ public java.util.List<com.myapplication.aidl.Book> getBookList() throws android.os.RemoteException; public void addBook(com.myapplication.aidl.Book book) throws android.os.RemoteException; }
服务端:
public class BookService extends Service { private CopyOnWriteArrayList<Book> mBooks = new CopyOnWriteArrayList<>(); @Nullable @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public void onCreate() { super.onCreate(); mBooks.add(new Book(1,"Android")); } private Binder mBinder = new IBookManager.Stub(){ @Override public List<Book> getBookList() throws RemoteException { return mBooks; } @Override public void addBook(Book book) throws RemoteException { mBooks.add(book); } }; }
客户端:
public class BindActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(this,BookService.class); bindService(intent,mConnection,BIND_AUTO_CREATE); } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { IBookManager iBookManager = IBookManager.Stub.asInterface(service); Log.d("----",iBookManager.toString()); try { List<Book> bookList = iBookManager.getBookList(); Log.d("----",bookList.toString()); iBookManager.addBook(new Book(2,"ios")); Log.d("----", iBookManager.getBookList().toString()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onDestroy() { super.onDestroy(); unbindService(mConnection); } }
给Binder设置死亡代理:
mIBookManager = IBookManager.Stub.asInterface(service); try { service.linkToDeath(mDeathRecipient,0); } catch (RemoteException e) { e.printStackTrace(); } private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { mIBookManager.asBinder().unlinkToDeath(mDeathRecipient,0); mIBookManager = null; //重新连接 } };
4、Android中的IPC方式
-
使用Messenger
服务端:public class MessengerService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } private Messenger mMessenger = new Messenger(new MessengerHandler()); private class MessengerHandler extends Handler{ @Override public void handleMessage(Message msg) { switch (msg.what){ case 1: Log.d("------","收到了"+msg.getData().getString("msg")); Messenger replyTo = msg.replyTo; Message message = Message.obtain(null,1); Bundle bundle = new Bundle(); bundle.putString("reply","收到了"); message.setData(bundle); try { replyTo.send(message); //回复 } catch (RemoteException e) { e.printStackTrace(); } break; default: super.handleMessage(msg); } } } }
注册单独进程:
<service android:name=".MessengerService" android:process=":remote"/>
客户端:
public class MainActivity extends AppCompatActivity { private Messenger mMessenger; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(this,MessengerService.class); bindService(intent,mConnection,BIND_AUTO_CREATE); } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mMessenger = new Messenger(service); } @Override public void onServiceDisconnected(ComponentName name) { } }; public void send(View view){ Message message = Message.obtain(null, 1); Bundle bundle = new Bundle(); bundle.putString("msg","我的客户端"); message.setData(bundle); message.replyTo = mReplyMessenger; //指定回应的Messenger try { mMessenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } } private Messenger mReplyMessenger = new Messenger(new MessengerHandle()); private class MessengerHandle extends Handler{ @Override public void handleMessage(Message msg) { switch (msg.what){ case 1: Log.d("------","回复了"+msg.getData().getString("reply")); break; } } } @Override protected void onDestroy() { super.onDestroy(); unbindService(mConnection); } }
-
AIDL
支持的数据类型:
基本数据类型(int、long、char、boolean、double等);
String和CharSequence;
List:只支持ArrayList,里面的每个元素都必须能够被AIDL支持;
Map:只支持HashMap,里面的每个元素都必须被AIDL支持,包括key和value;
Parcelable:所有实现了Parcelable;
AIDL:所有的AIDL接口本身也可以在AIDL文件中使用。使用注意:
Parcelable对象和AIDL对象必须要显示import进来;
如果AIDL文件用到自定义的Parcelable对象,那么必须新建一个和它同名的AIDL文件,比如Book.aidl,然后添加内容:parcelable Book;
AIDL除了基本数据类型,其他类型的参数必须标上方向:in、out、inout,表示输入型参数、输出型参数、输入输出型参数;
AIDL只支持方法,不支持声明静态常量。CopyOnWriteArrayList:
支持并发读写,AIDL方法在服务端的Binder线程池中执行,当多个客户端同时连接时的情况。RemoteCallbackList:
RemoteCallbackList是系统专门提供用于删除跨进程listener的接口private RemoteCallbackList<对应的接口> mCallbackList = new RemoteCallbackList<>(); mCallbackList.register(对应的接口); mCallbackList.unregister(对应的接口); int n = mCallbackList.beginBroadcast(); for (int i = 0; i < n; i++) { mCallbackList.getBroadcastItem(i).xxxx; } mCallbackList.finishBroadcast();
-
Socket
服务端:public class TCPServerService extends Service { private boolean mIsServiceDestroyed = false; private String[] mDefinedMessages = {"你好啊","你叫我?","1111111"}; @Override public void onCreate() { super.onCreate(); new Thread(new TcpServer()).start(); } @Override public void onDestroy() { super.onDestroy(); mIsServiceDestroyed = true; } @Nullable @Override public IBinder onBind(Intent intent) { return null; } private class TcpServer implements Runnable{ @Override public void run() { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(8688); } catch (IOException e) { e.printStackTrace(); } while (!mIsServiceDestroyed){ try { final Socket client = serverSocket.accept(); Log.d("----",client.toString()); new Thread(new Runnable() { @Override public void run() { try { respone(client); } catch (IOException e) { e.printStackTrace(); } } }).start(); } catch (IOException e) { e.printStackTrace(); } } } } private void respone(Socket client) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())),true); out.println("欢迎来到聊天室"); while (!mIsServiceDestroyed){ String str = in.readLine(); if (str == null){ break; } Log.d("-----",str); int i = new Random().nextInt(mDefinedMessages.length); String msg = mDefinedMessages[i]; out.println(msg); } in.close(); out.close(); client.close(); } }
客户端:
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private TextView tvMessage; private EditText etInput; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: tvMessage.setText(tvMessage.getText()+(String)msg.obj); break; case 2: btnSend.setEnabled(true); break; } } }; private Button btnSend; private Socket mClientSocker; private PrintWriter mPrintWriter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); Intent intent = new Intent(this,TCPServerService.class); startService(intent); new Thread(new Runnable() { @Override public void run() { connectTCPServer(); } }).start(); } private void initView() { tvMessage = (TextView) findViewById(R.id.tv_message); etInput = (EditText) findViewById(R.id.et_input); btnSend = (Button) findViewById(R.id.btn_send); btnSend.setOnClickListener(this); } @Override public void onClick(View v) { if (v == btnSend){ String msg = etInput.getText().toString(); if (!TextUtils.isEmpty(msg) && mPrintWriter != null){ mPrintWriter.println(msg); etInput.setText(""); String time = formateDateTime(System.currentTimeMillis()); String show = "self "+time+":"+msg+"\n"; tvMessage.setText(tvMessage.getText()+show); } } } private void connectTCPServer(){ Socket socket = null; while (socket == null){ try { socket = new Socket("localhost",8688); mClientSocker = socket; mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true); mHandler.sendEmptyMessage(2); } catch (IOException e) { e.printStackTrace(); } } try { BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); while (!MainActivity.this.isFinishing()){ String msg = br.readLine(); if (msg != null){ Log.d("----",msg); String time = formateDateTime(System.currentTimeMillis()); String show = "server "+time+":"+msg+"\n"; mHandler.obtainMessage(1,show).sendToTarget(); } } mPrintWriter.close(); br.close(); } catch (IOException e) { e.printStackTrace(); } } private String formateDateTime(long time){ return new SimpleDateFormat("HH:mm:ss").format(new Date(time)); } }
-
Binder连接池
减少Service的数量。将所有AIDL放在同一个Service中去管理。
工作机制:每个业务模块创建自己的AIDL接口并实现此接口,这个时候不同业务模块之间是不能有耦合的,所有实现细节我们需要单独开来,然后向服务端提供自己的唯一标识和其对应的Binder对象;对于服务端来说,只需要一个Service就可以了,服务端提供一个queryBinder接口,这个接口能给根据业务模块的特征来返回相应的Binder对象给它们,不同的业务模块拿到所需要的Binder对象后就可以进行远程方法调用了。
BindPool: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 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(); } }
客户端:
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_main); 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(); } } }
2、理解Windowh和WindowManager
1、Window和WondowManager
- WondowManagers是外界访问Window的入口,Window的具体实现位于WindowManagerService中,WindowManager和WindowManagerService的交互是一个IPC过程。
- FLAG
FLAG_NOT_FOCUSABLE:
表示Window不需要获取焦点,也不需要接收各种输入事件,这个标记会同时启用FLAG_NOT_TOUCH_MODAL,最终事件会直接传递给下层的具有焦点的Window。
FLAG_NOT_TOUCH_MODAL:
系统会将当期区域以外的单击事件传递给底层的Window,当前Window区域以内的单击事件则自己处理。一般要开启,否则其他Window将无法收到单击事件。
FLAG_SHOW_WHEN_LOCKED:
让Window显示在锁屏界面上。 - Type参数表示Window类型,有三种,应用Window、子Window、系统Window;应用Window对应着一个Activity,层级是1-99,子Window不能单独存在,比如Dialog,层级是1000-1999,系统Window比如Toast,层级是2000-2999。
网友评论