开启多进程

   <service
         android:name=".MyService"
         android:label="@string/app_name"
         android:process=":remote"/>

如果被设置的进程名是以一个冒号开头的,则这个新的进程对于这个应用来说是私有的。

   <service
        android:name=".MyService"
        android:label="@string/app_name"
        android:process="com.example.liuwangshu.myprogress.remote"/>     

这是一个全局进程,不同应用中的各种组件可以共享一个进程,从而减少资源的占用。

开启多进程会使Application运行两次,我们继承Application,解决的方法就是得到每个进程的名称,如果进程的名称和我们应用的进程名称相同则做我们应用的操作,如果不是则做其他进程的操作。

用Messenger进行进程间通信

Messenger(注意不是Message)是一种轻量级的IPC方案并对AIDL 进行了封装。Messenger是以串行的方式来处理客户端发来的信息,如果有大量的消息发到服务端,服务端仍然一个一个的处理再响应客户端显然是不合适的。另外,Messenger用来进程间进行数据传递但是却不能满足跨进程的方法调用,接下来我们来使用AIDL来实现跨进程方法调用。

用AIDL进行进程间通信

用ContentProvider进行进程间通信

ContentProvider为存储和获取数据提供统一的接口,它可以在不同的应用程序之间共享数据,本身就是适合进程间通信的。ContentProvider底层实现也是Binder,但是使用起来比AIDL要容易许多。系统也预制了很多的ContentProvider,例如通讯录,音视频等,这些操作本身就是跨进程进行通信。


多进程带来的问题

  • Application多次创建

  • 静态变量和单例模式完全失效

  • 线程同步机制完全失效

  • SP的可靠性降低


1,多进程相关小结

2,带你一起剖析Android AIDL跨进程通信的实现原理(已阅)

3,Android跨进程通信,深入浅出AIDL(已阅)

4,Android进程间通信(已阅)

5,Android多进程使用场景(已阅)

6,Android AIDL使用详解(已阅)

7,三步掌握 Android 中的 AIDL(已阅)

8,Android 多进程通信之几个基本问题(已阅)

9,Android 进程保活招式大全

10,你真的理解AIDL中的in,out,inout么?(已阅)


观点

首先多进程开发能为应用解决了OOM问题,Android对内存的限制是针对于进程的,这个阈值可以是48M、24M、16M等,视机型而定,所以,当我们需要加载大图之类的操作,可以在新的进程中去执行,避免主进程OOM。

多进程不光解决OOM问题,还能更有效、合理的利用内存。我们可以在适当的时候生成新的进程,在不需要的时候及时杀掉,合理分配,提升用户体验。减少系统被杀掉的风险。

多进程还能带来一个好处就是,单一进程崩溃并不影响整体应用的使用。例如我在图片浏览进程打开了一个过大的图片,java heap 申请内存失败,但是不影响我主进程的使用,而且,还能通过监控进程,将这个错误上报给系统,告知他在什么机型、环境下、产生了什么样的Bug,提升用户体验。

多进程不一定适合所有的应用,合理利用分配进程,使程序更加稳定,才是我们追求的目标。

应用内跨进程通信,绑定服务可以通过显示意图来绑定,但是如果是跨应用的进程间通信,那么就需要用到隐式意图了。 这里有一点需要注意的就是,在5.0以后隐式意图开启或者绑定service要setPackage(Service的包名),不然会报错。

你可以用Messager处理简单的跨进程通信,但是高并发量的要用AIDL。

默认实现Parcelable的模版只支持in ,如果需要需要支持out或inout需要手动实现readFromParcel方法。

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(this.name);
    dest.writeInt(this.price);
}
//手动实现这个方法
public void readFromParcel(Parcel dest) {
    //注意,这里的读取顺序要writeToParcel()方法中的写入顺序一样
    name = dest.readString();
    price = dest.readInt();
}

埋坑与完善

该篇文章内容不多,但是处处皆是精华,尤其是以下3条建议,以防引起惨案。

  1. xxx.aidl 中不能存在同方法名不同参数的方法。

  2. xxx.aidl 中实体类必须要有指定的tag。

  3. 在Android Studio里写完aidl文件还需要在build.gradle文件中android{}方法内添加aidl路径。

     sourceSets { 
         main { 
             java.srcDirs = ['src/main/java', 'src/main/aidl'] 
         } 
     }
    

Android 通过这个特性提供 RemoteCallbackList,让我们用来存储监听接口集合, 这个RemoteCallbackList 内部自动实现了线程同步的功能,而且它的本质是一个 ArrayMap,所以我们用它来绑定/解绑时,不需要做额外的线程同步操作。

private RemoteCallbackList<IDemandListener> demandList = new RemoteCallbackList<>();

@Override
public void registerListener(IDemandListener listener) throws RemoteException { 
    demandList.register(listener); 
} 

@Override
public void unregisterListener(IDemandListener listener) throws RemoteException { 
    demandList.unregister(listener); 
}

最后,我们通过 Handler 来进行定时发送消息。(handler 并不能精准的做定时任务,因为 handler 在发送和接收的过程中会有时间损耗) 。

另外我们需要通过 beginBroadcast() 来获取 RemoteCallbackList中元素的个数,同时 beginBroadcast() 和 finishBroadcast() 必须要配对使用,哪怕仅仅只是获取一下这个集合的元素个数。


results matching ""

    No results matching ""