Best Practice For Android

阿里巴巴Android开发手册个人理解记录

Android基本组件

  • Activity间的数据通信:

    • putExtra: 数据量小于 < 1024kb (IPC缓冲区大小限制)
    • Huge Data:
      • EventBus
      • ActivityResults.data(static)
      • 数据库 & SP
  • Activity数据持久化

    • onSaveInstanceState() : 用于异常情况Activity的重建恢复,默认实现方案恢复了设置ID的控件状态,如textview里的文字,checkbox的勾选状态
    • onPause & onStop:用于数据的持久化
  • Activity 间通过隐式 Intent 的跳转,在发出 Intent 之前必须通过resolveActivity检查,避免找不到合适的调用组件,造成 ActivityNotFoundException 的异常

  • Service

  • 避免在 BroadcastReceiver#onReceive()中执行耗时操作,如果有耗时工作, 应该创建 IntentService 完成,而不应该在 BroadcastReceiver 内创建子线程去做(10s)

  • 避免使用隐式 Intent 广播敏感信息,信息可能被其他注册了对应 BroadcastReceiver 的 App 接收。

    通过 Context#sendBroadcast()发送的隐式广播会被所有感兴趣的 receiver 接收,恶意应用注册监听该广播的 receiver 可能会获取到 Intent 中传递的敏感信息,并进行其他危险操作。如果发送的广播为使用 Context#sendOrderedBroadcast()方法发送的有序广播,优先级较高的恶意 receiver 可能直接丢弃该广播,造成服务不可用,或者向广播结果塞入恶意数据。如果广播仅限于应用内,则可以使用 LocalBroadcastManager#sendBroadcast()实现,避免敏感信息外泄和 Intent 拦截的风险。

  • 7

  • 不要在 Activity#onDestroy()内执行释放资源的工作,例如一些工作线程的 销毁和停止,因为 onDestroy()执行的时机可能较晚。可根据实际需要,在 Activity#onPause()/onStop()中结合 isFinishing()的判断来执行。

  private boolean isDestroyed = false;    private void destroy()  {        if (isDestroyed) {            return;        }        // 回收资源     isDestroyed = true;    }    @Override    protected void onPause() {        super.onPause();        if (isFinishing()) {            destroy();        }    }    @Override    public void onDestroy() {        destroy();    }
  • 9

  • 10

  • Service 需要以多线程来并发处理多个启动请求,建议使用 IntentService, 可避免各种复杂的设置。

  • 对于只用于应用内的广播,优先使用 LocalBroadcastManager 来进行注册 和发送,LocalBroadcastManager 安全性更好,同时拥有更高的运行效率
  • 当前 Activity 的 onPause 方法执行结束后才会执行下一个 Activity 的 onCreate 方法,所以在 onPause 方法中不适合做耗时较长的工作,这会影响到页面之间的跳 转效率。
  • 不要在 Android 的 Application 对象中缓存数据。基础组件之间的数据共享 请使用 Intent 等机制,也可使用 SharedPreferences 等数据持久化机制
    • Application在应用被杀死再次重启时会被重新的创建
      • 直接将数据通过intent传递给 Activity 。
      • 使用官方推荐的几种方式将数据持久化到磁盘上。
  • 使用 Toast 时,建议定义一个全局的 Toast 对象,这样可以避免连续显示 Toast 时不能取消上一次 Toast 消息的情况(如果你有连续弹出 Toast 的情况,避免 使用 Toast.makeText)。
  • 使用 Adapter 的时候,如果你使用了 ViewHolder 做缓存,在 getView()的 方法中无论这项 convertView 的每个子控件是否需要设置属性(比如某个 TextView 设置的文本可能为 null,某个按钮的背景色为透明,某控件的颜色为透明等),都需 要为其显式设置属性(Textview 的文本为空也需要设置 setText(“”),背景透明也需要 设置),否则在滑动的过程中,因为 adapter item 复用的原因,会出现内容的显示错 乱。
  • Activity 或者 Fragment 中动态注册 BroadCastReceiver 时,registerReceiver() 和 unregisterReceiver()要成对出现

UI与布局

  • 布局中不得不使用 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

  • 【推荐】在 Activity 中显示对话框或弹出浮层时,尽量使用 DialogFragment,而非 Dialog/AlertDialog,这样便于随 Activity 生命周期管理对话框/弹出浮层的生命周期
  • 源文件统一采用 UTF-8 的形式进行编码。
  • 【强制】禁止在非 ui 线程进行 view 相关操作
  • 【推荐】文本大小使用单位 dp,view 大小使用单位 dp。对于 Textview,如果在文 字大小确定的情况下推荐使用 wrap_content 布局避免出现文字显示不全的适配问题。

    文字大小???

  • 【强制】禁止在设计布局时多次设置子 view 和父 view 中为同样的背景造成页面过 度绘制,推荐将不需要显示的布局进行及时隐藏

  • 【推荐】灵活使用布局,推荐 Merge、ViewStub 来优化布局,尽可能多的减少 UI 布局层级,推荐使用 FrameLayout,LinearLayout、RelativeLayout 次之。

    布局顺序???

  • 8 自定义View

  • 9
  • 【推荐】尽量不要使用 AnimationDrawable,它在初始化的时候就将所有图片加载
    到内存中,特别占内存,并且还不能释放,释放之后下次进入再次加载时会报错
  • 【强制】不能使用 ScrollView 包裹 ListView/GridView/ExpandableListVIew;因为这 样会把 ListView 的所有 Item 都加载到内存中,要消耗巨大的内存和 cpu 去绘制。推荐使用NestedScrollView

进程,线程与消息通信

  • 不要通过 Intent 在 Android 基础组件之间传递大数据(binder transaction 缓存为 1MB),可能导致 OOM
  • 【强制】在 Application 的业务初始化代码加入进程判断,确保只在自己需要的进程 初始化。特别是后台进程减少不必要的业务初始化。
  • 【强制】新建线程时,必须通过线程池提供(AsyncTask 或者 ThreadPoolExecutor 或者其他形式自定义的线程池),不允许在应用中自行显式创建线程。
  • 【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方 式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险
  • 【强制】子线程中不能更新界面,更新界面必须在主线程中进行,网络操作不能在 主线程中调用
  • 【强制】不要在非 UI 线程中初始化 ViewStub,否则会返回 null
  • 尽量减少不同 APP 之间的进程间通信及拉起行为。拉起导致占用系统资源,
    影响用户体验。
  • 【推荐】新建线程时,定义能识别自己业务的线程名称,便于性能优化和问题排查
  • 【推荐】ThreadPoolExecutor 设置线程存活时间(setKeepAliveTime),确保空闲时 线程能被释放
  • 【推荐】禁止在多进程之间用 SharedPreferences 共享数据,虽然可以 (MODE_MULTI_PROCESS),但官方已不推荐。6.0之上已经废弃,并未实现并发的机制。
  • 11

文件与数据库

  • 【强制】任何时候不要硬编码文件路径,请使用 Android 文件系统 API 访问。
  • 【强制】当使用外部存储时,必须检查外部存储的可用性。
  • 【强制】应用间共享文件时,不要通过放宽文件系统权限的方式去实现,而应使用 FileProvider。
  • SP:http://blog.csdn.net/offbye/article/details/60882824
  • 【推荐】SharedPreference 提交数据时,尽量使用 Editor#apply(),而非 Editor#commit()。一般来讲,仅当需要确定提交结果,并据此有后续操作时,才使 用 Editor#commit()。

    SharedPreference 相关修改使用 apply 方法进行提交会先写入内存,然后异步写入 磁盘,commit 方法是直接写入磁盘。如果频繁操作的话 apply 的性能会优于 commit, apply 会将最后修改内容写入磁盘。但是如果希望立刻获取存储操作的结果,并据此做相应的其他操作,应当使用 commit。

  • 数据库:6 ~ 10

Bitmap、Drawable 与动画

  • 【强制】加载大图片或者一次性加载多张图片,应该在异步线程中进行。图片的加 载,涉及到 IO 操作,以及 CPU 密集操作,很可能引起卡顿。
  • 【强制】在 ListView,ViewPager,RecyclerView,GirdView 等组件中使用图片时, 应做好图片的缓存,避免始终持有图片导致内存泄露,也避免重复创建图片,引起 性 能 问 题 。 建 议 使 用 Fresco ( https://github.com/facebook/fresco )、 Glide(https://github.com/bumptech/glide)等图片库。
  • 【强制】png 图片使用 tinypng 或者类似工具压缩处理,减少包体积。
  • 【推荐】应根据实际展示需要,压缩图片,而不是直接显示原图。手机屏幕比较小,直接显示原图,并不会增加视觉上的收益,但是却会耗费大量宝贵的内存。

  • 【强制】使用完毕的图片,应该及时回收,释放宝贵的内存。

  • 【推荐】针对不同的屏幕密度,提供对应的图片资源,使内存占用和显示效果达到 合理的平衡。如果为了节省包体积,可以在不影响 UI 效果的前提下,省略低密度图片。
  • 【强制】在 Activity.onPause()或 Activity.onStop()回调中,关闭当前 activity 正在执 行的的动画。

更多相关文章

  1. Android 弹出键盘向上顶布局
  2. Android 子线程中更新UI
  3. ktolin在Android中布局界面拼接
  4. android之布局LinearLayout
  5. Android 读取网络数据
  6. Android 线程同步 ConditionVariable的用法
  7. android之线性布局LinearLayout以及weight权重使用
  8. 【Android】使用代码动态创建布局

随机推荐

  1. Android(安卓)toast弹出时间自定义
  2. Android(安卓)WebView清空缓存
  3. Android: 利用Bimap,canvas处理图片(画直
  4. android 使用include 调用内部组件
  5. Android读取Txt文件
  6. Android(安卓)Bundle类
  7. android的安装和卸载
  8. android与数据库
  9. Porting Wifi driver on Android
  10. Android(安卓)MVP架构搭建