在Processes and Application Lifecycle中我们了解了进程的生命周期和类型,今天我们来了解一下多进程和进程间通信。
我们先来了解一下关于Android系统的一些概念:
- Android操作系统是一个多用户的Linux系统,在Android系统中每个app代表一个不同的用户。
- 在默认情况下,系统会给每一个app一个唯一的Linux user ID,这个ID只有系统可以使用,app并不知道自己的ID。系统会给app内的所有文件设置权限,只有那个ID的app才能访问。
- 每个进程有自己的virtual machine(VM),每个进程运行在自己独立的地方。不同进程内存是不共享的。
- 在默认情况下,每个app运行在自己的进程中。系统会开启进程,当app中任何一个components需要被执行时。系统会关闭进程,当进程不在被需要的时候或者需要回收内存的时候。
Android多进程概念:一般一个app只有一个进程,所有的components都运行在同一个进程中,进程名称就是app包名。但是每一个进程都有内存的限制,如果一个进程的内存超过了这个限制的时候就会报OOM错误。为了解决内存限制的问题,Android引入了多进程的概念,将占用内存的操作放在一个单独的进程中分担主进程的压力。
多进程的好处:
- 分担主进程的内存压力。
- 常驻后台任务。
- 守护进程,主进程和守护进程相互监视,有一方被杀就重新启动它。
- 多么块,对有风险的模块放在单独进程,崩溃后不会影响主进程的运行。
多进程的缺点:
- Applicaton的重新创建,每个进程有自己独立的virtual machine,每次创建新的进程就像创建一个新的Application
- 静态成员变量和单例模式失效,每个进程有自己独立的虚拟机,不同虚拟机在内存分配上有不同的地址空间,这就导致不同虚拟机在访问同一个对象时会产生多分副本。
- SharedPreference的可靠性下降,不支持多进程
- 线程同步机制失效
Android进程间通信:
1. 系统Intent传递数据
Parcelables和Bundles可以被用来在进程间传递,但是在进程间传递时不建议使用custom parcelable。使用Parcelable在两个app之间传递数据时,要确保两个app中Parcelable的对象一样,并且放置在包中的位置也相同。但是使用Intent在传递数据时,你需要把数据的大小限制在几KB,传送太多数据时系统会抛出TransactionTooLargeException。
2. AIDL
- 新建AIDL接口
interface IMyAidlInterface { /** * 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); String getName(String name); }
- 创建AIDLService
public class AIDLService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return mStub; } IMyAidlInterface.Stub mStub = new IMyAidlInterface.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public String getName(String name) { return "aidl testing " + name; } }; }
- 传递数据
public class MainThreadActivity extends AppCompatActivity { private IMyAidlInterface iMyAidlInterface; ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_thread); Person.DATING_COUNT = 10; startDemoService(); bindAIDLService(); findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { try { String name = iMyAidlInterface.getName("I am Jim"); Log.i("name", name); ((TextView) findViewById(R.id.tv_content)).setText(name); } catch (RemoteException exception) { } } }); } private void bindAIDLService() { Intent intent = new Intent(this, AIDLService.class); bindService(intent, mServiceConnection, BIND_AUTO_CREATE); } }