android规范

  1. Activity 间的数据通信,对于数据量比较大的,避免使用 Intent + Parcelable
    的方式,可以考虑 EventBus 等替代方案,以免造成 TransactionTooLargeException

  2. activity隐式跳转,在发出 Intent 之前必须通过 resolveActivity检查,避免找不到合适的调用组件,造成 ActivityNotFoundException 的异常

public void viewUrl(String url, String mimeType) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), mimeType);
if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_
ONLY) != null) {
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
if (Config.LOGD) {
Log.d(LOGTAG, "activity not found for " + mimeType + " over " +
Uri.parse(url). getScheme(), e);

  1. 避免在 Service#onStartCommand()/onBind()方法中执行耗时操作,如果确实有需求,应改用 IntentService 或采用其他异步机制完成

  2. 避免在 BroadcastReceiver#onReceive()中执行耗时操作,如果有耗时工作,应该创建 IntentService 完成,而不应该在 BroadcastReceiver 内创建子线程去做。
    说明:
    由于该方法是在主线程执行,如果执行耗时操作会导致 UI 不流畅。可以使用IntentService 、 创 建 HandlerThread 或 者 调 用 Context#registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)方法等方式,在其他 Wroker 线程执行 onReceive 方法。 BroadcastReceiver#onReceive()方法耗时超过 10 秒钟,可能会被系统杀死

IntentFilter filter = new IntentFilter();
filter.addAction(LOGIN_SUCCESS);
this.registerReceiver(mBroadcastReceiver, filter);
mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Intent userHomeIntent = new Intent();
userHomeIntent.setClass(this, UseHomeActivity.class);
this.startActivity(userHomeIntent);
}
};
  1. 添 加 Fragment 时 , 确 保 FragmentTransaction#commit() 在
    Activity#onPostResume()或FragmentActivity#onResumeFragments()内调用。
    不要随意使用FragmentTransaction#commitAllowingStateLoss()来代替,任何
    commitAllowingStateLoss()的使用必须经过 code review,确保无负面影响。

说明如下:

Activity 可 能 因 为 各 种 原 因 被 销 毁 , Android 支 持 页 面 被 销 毁 前 通 过
Activity#onSaveInstanceState() 保 存 自 己 的 状 态 。 但 如 果
FragmentTransaction.commit()发生在 Activity 状态保存之后,就会导致 Activity 重
建、恢复状态时无法还原页面状态,从而可能出错。为了避免给用户造成不好的体
验,系统会抛出 IllegalStateExceptionStateLoss 异常。推荐的做法是在 Activity 的
onPostResume() 或 onResumeFragments() ( 对 FragmentActivity ) 里 执 行
FragmentTransaction.commit(),如有必要也可在 onCreate()里执行。不要随意改用
FragmentTransaction.commitAllowingStateLoss() 或 者 直 接 使 用 try-catch 避 免
crash,这不是问题的根本解决之道,当且仅当你确认 Activity 重建、恢复状态时,
本次 commit 丢失不会造成影响时才可这么做

  1. 对于只用于应用内的广播,优先使用 LocalBroadcastManager 来进行注册
    和发送,LocalBroadcastManager 安全性更好,同时拥有更高的运行效率。
    说明:
    对于使用 Context#sendBroadcast()等方法发送全局广播的代码进行提示。如果该广
    播仅用于应用内,则可以使用 LocalBroadcastManager 来避免广播泄漏以及广播被
    拦截等安全问题,同时相对全局广播本地广播的更高效

  2. 使用 Toast 时,建议定义一个全局的 Toast 对象,这样可以避免连续显示
    Toast 时不能取消上一次 Toast 消息的情况(如果你有连续弹出 Toast 的情况,避免
    使用 Toast.makeText)

  3. 布局中不得不使用 ViewGroup 多重嵌套时,不要使用 LinearLayout 嵌套,
    改用 RelativeLayout,可以有效降低嵌套数。
    说明:
    Android 应用页面上任何一个 View 都需要经过 measure、 layout、 draw 三个步骤
    才能被正确的渲染。从 xml layout 的顶部节点开始进行 measure,每个子节点都需
    要向自己的父节点提供自己的尺寸来决定展示的位置,在此过程中可能还会重新
    measure(由此可能导致 measure 的时间消耗为原来的 2-3 倍)。节点所处位置越
    深,套嵌带来的 measure 越多,计算就会越费时。这就是为什么扁平的 View 结构
    会性能更好。
    同时,页面拥上的 View 越多,measure、 layout、 draw 所花费的时间就越久。要缩
    短这个时间,关键是保持 View 的树形结构尽量扁平,而且要移除所有不需要渲染的
    View。理想情况下,总共的 measure,layout,draw 时间应该被很好的控制在 16ms
    以内,以保证滑动屏幕时 UI 的流畅。
    要找到那些多余的 View(增加渲染延迟的 view),可以用 Android Studio Monitor
    里的 Hierarachy Viewer 工具,可视化的查看所有的 view。

  4. 在 Application 的业务初始化代码加入进程判断,确保只在自己需要的进程
    初始化。特别是后台进程减少不必要的业务初始化。

  5. 不要通过 Intent 在 Android 基础组件之间传递大数据(binder transaction
    缓存为 1MB),可能导致 OOM。

  6. 新建线程时,必须通过线程池提供(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,
NUMBER_OF_CORES*2, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, taskQueue,
new BackgroundThreadFactory(), new DefaultRejectedExecutionHandler());
//执行任务
executorService.execute(new Runnnable() {
...
});
  1. 线程池不允许使用 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,
NUMBER_OF_CORES*2, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT,
taskQueue, new BackgroundThreadFactory(), new DefaultRejectedExecutionHandler());
  1. 禁 止 在 多 进 程 之 间 用 SharedPreferences 共 享 数 据 , 虽 然 可 以
    (MODE_MULTI_PROCESS),但官方已不推荐

  2. ThreadPoolExecutor 设置线程存活时间(setKeepAliveTime),确保空闲时
    线程能被释放

  3. 谨慎使用 Android 的多进程,多进程虽然能够降低主进程的内存压力,但会
    遇到如下问题:

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

16.应用间共享文件时,不要通过放宽文件系统权限的方式去实现,而应使用
FileProvider。

  1. SharedPreference 提 交 数 据 时 , 尽 量 使 用 Editor#apply() , 而 非
    Editor#commit()。一般来讲,仅当需要确定提交结果,并据此有后续操作时,才使
    用 Editor#commit()。
    说明:
    SharedPreference 相关修改使用 apply 方法进行提交会先写入内存,然后异步写入
    磁盘,commit 方法是直接写入磁盘。如果频繁操作的话 apply 的性能会优于 commit,apply 会将最后修改内容写入磁盘。但是如果希望立刻获取存储操作的结果,并据此
    做相应的其他操作,应当使用 commit。

  2. 多线程操作写入数据库时,需要使用事务,以免出现同步问题。
    说明:
    Android 的通过 SQLiteOpenHelper 获取数据库 SQLiteDatabase 实例,Helper 中会
    自动缓存已经打开的 SQLiteDatabase 实例,单个 App 中应使用 SQLiteOpenHelper
    的单例模式确保数据库连接唯一。由于 SQLite 自身是数据库级锁,单个数据库操作
    是保证线程安全的(不能同时写入),transaction 时一次原子操作,因此处于事务中
    的操作是线程安全的。
    若同时打开多个数据库连接,并通过多线程写入数据库,会导致数据库异常,提示
    数据库已被锁住

public void insertUserPhoto(SQLiteDatabase db, String userId, String content) {
ContentValues cv = new ContentValues();
cv.put("userId", userId);
cv.put("content", content);
db.beginTransaction();
try {
db.insert(TUserPhoto, null, cv);
// 其他操作
db.setTransactionSuccessful();
} catch (Exception e) {
// TODO
} finally {
db.endTransaction();
}
}
  1. 大数据写入数据库时,请使用事务或其他能够提高 I/O 效率的机制,保证执行速度。

  2. 加载大图片或者一次性加载多张图片,应该在异步线程中进行。图片的加载,涉及到 IO 操作,以及 CPU 密集操作,很可能引起卡顿

  3. png 图片使用 tinypng 或者类似工具压缩处理,减少包体积。

  4. 在 Activity.onPause()或 Activity.onStop()回调中,关闭当前 activity 正在执
    行的的动画。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容