阿里Android开发规范:进程、线程与消息通信

643 阅读4分钟

以下内容摘自 阿里巴巴Android开发手册

我们的目标是:

  • 防患未然,提升质量意识,降低故障率和维护成本;
  • 标准统一,提升协作效率;
  • 追求卓越的工匠精神,打磨精品代码。
  • 【强制】必须遵守,违反本约定或将会引起严重的后果;
  • 【推荐】尽量遵守,长期遵守有助于系统稳定性和合作效率的提升;
  • 【参考】充分理解,技术意识的引导,是个人学习、团队沟通、项目合作的方向。

阿里Android开发规范:资源文件命名与使用规范
阿里Android开发规范:四大基本组件
阿里Android开发规范:UI 与布局
阿里Android开发规范:进程、线程与消息通信
阿里Android开发规范:文件与数据库
阿里Android开发规范:Bitmap、Drawable 与动画
阿里Android开发规范:安全与其他

1、【强制】不要通过 Intent 在Android基础组件之间传递大数据(binder transaction缓存为 1MB),可能导致OOM。
2、【强制】在 Application 的业务初始化代码加入进程判断,确保只在自己需要的进程初始化。特别是后台进程减少不必要的业务初始化。
正例:

public class MyApplication extends Application {
	@Override
	public void onCreate() {
		//在所有进程中初始化
		....
		//仅在主进程中初始化
		if (mainProcess) {
			...
		}
		//仅在后台进程中初始化
		if (bgProcess) {
			...
		}
	}
}

3、【强制】新建线程时,必须通过线程池提供(AsyncTask 或者 ThreadPoolExecutor或者其他形式自定义的线程池),不允许在应用中自行显式创建线程。 说明: 使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。另外创建匿名线程不便于后续的资源使用分析,对性能分析等会造成困扰。
正例:

int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
int KEEP_ALIVE_TIME = 1;
TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;

BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<Runnable>();

ExecutorService executorService = new ThreadPoolExecutor(
	NUMBER_OF_CORES, //corePoolSize:核心线程数
	NUMBER_OF_CORES*2, //maximumPoolSize:线程池最大线程数
	KEEP_ALIVE_TIME, //keepAliveTime:非核心线程闲置超时时间
	KEEP_ALIVE_TIME_UNIT, //Unit:非核心线程闲置超时时间单位
	taskQueue, //workQueue:任务队列
	new BackgroundThreadFactory(), //threadFactory:线程工厂
	new DefaultRejectedExecutionHandler() //handler:表示当拒绝处理任务时的策略);
//执行任务
executorService.execute(new Runnnable() {
...
});

反例:

new Thread(new Runnable() {
	@Override
	public void run() {
		//操作语句
		...
	}
}).start();

扩展参考:
blog.mindorks.com/threadpoole…
4、【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明: Executors 返回的线程池对象的弊端如下:

  1. FixedThreadPool 和 SingleThreadPool : 允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM;
  2. CachedThreadPool 和 ScheduledThreadPool : 允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

正例:

int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
int KEEP_ALIVE_TIME = 1;
TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;

BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<Runnable>();

ExecutorService executorService = new ThreadPoolExecutor(
	NUMBER_OF_CORES, //corePoolSize
	NUMBER_OF_CORES*2, //maximumPoolSize
	KEEP_ALIVE_TIME, //keepAliveTime
	KEEP_ALIVE_TIME_UNIT, //Unit
	taskQueue, //workQueue
	new BackgroundThreadFactory(), //threadFactory
	new DefaultRejectedExecutionHandler() //handler);

反例:

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

扩展参考: dev.bizo.com/2014/06/cac…
5、【强制】子线程中不能更新界面,更新界面必须在主线程中进行,网络操作不能在主线程中调用。
6、【强制】不要在非 UI 线程中初始化 ViewStub,否则会返回 null。
7、【推荐】尽量减少不同 APP 之间的进程间通信及拉起行为。拉起导致占用系统资源,影响用户体验。
8、【推荐】新建线程时,定义能识别自己业务的线程名称,便于性能优化和问题排查。
正例:

public class MyThread extends Thread {
	public MyThread(){
		super.setName("ThreadName");
		…
	}
}

9、【推荐】ThreadPoolExecutor 设置线程存活时间(setKeepAliveTime),确保空闲时线程能被释放。 10、【推荐】 禁止在多进 程之间用 SharedPreferences 共享数据 , 虽然可以(MODE_MULTI_PROCESS),但官方已不推荐。
11、【推荐】谨慎使用 Android 的多进程,多进程虽然能够降低主进程的内存压力,但会遇到如下问题:

  1. 不能实现完全退出所有 Activity 的功能;
  2. 首次进入新启动进程的页面时会有延时的现象(有可能黑屏、白屏几秒,是白屏还是黑屏和新 Activity 的主题有关);
  3. 应用内多进程时,Application 实例化多次,需要考虑各个模块是否都需要在所有进程中初始化;
  4. 多进程间通过 SharedPreferences 共享数据时不稳定。

阿里Android开发规范:资源文件命名与使用规范
阿里Android开发规范:四大基本组件
阿里Android开发规范:UI 与布局
阿里Android开发规范:进程、线程与消息通信
阿里Android开发规范:文件与数据库
阿里Android开发规范:Bitmap、Drawable 与动画
阿里Android开发规范:安全与其他