计划用这篇文章把目前我在Android领域的一些看到的、用到的、想到的经验和技巧总结一下。

1. WeakReference和AsyncTask的美妙结合

为了避免开发者在UI线程上做耗时操作,Android提供了不少异步API,其中之一就是AsyncTask。而对于某些频繁操作数据库的应用(例如,Phonebook)而言,需要一种异步的并且低耗资源的(低耗是两个方面的事情,要么是你占有的多点,但是能快速释放;要么是你本身就占有的少。这两种都可以保证其它应用有资源可用)组件。所以,那就来个WeakAsyncTask吧,唔,美妙的产物,既保证占有资源的快速释放,又保证操作是异步进行。

那为什么不是soft reference呢?

这个,来看看weak和soft两者的区别:

* A SoftReference should be cleared and enqueued as late as possible, that is, in case the VM is in danger of running out of memory.

* A WeakReference may be cleared and enqueued as soon as is known to be weakly-referenced.

不用问嘛,哪里能等到vm内存快光光的时候再去释放早已不用的资源啊,那个时候可能手机的UI看起来就卡卡的了。。

下面来看段代码:

public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget> extends        AsyncTask<Params, Progress, Result> {    protected WeakReference<WeakTarget> mTarget;    public WeakAsyncTask(WeakTarget target) {        mTarget = new WeakReference<WeakTarget>(target);    }    /** {@inheritDoc} */    @Override    protected final void onPreExecute() {        final WeakTarget target = mTarget.get();        if (target != null) {            this.onPreExecute(target);        }    }    /** {@inheritDoc} */    @Override    protected final Result doInBackground(Params... params) {        final WeakTarget target = mTarget.get();        if (target != null) {            return this.doInBackground(target, params);        } else {            return null;        }    }    /** {@inheritDoc} */    @Override    protected final void onPostExecute(Result result) {        final WeakTarget target = mTarget.get();        if (target != null) {            this.onPostExecute(target, result);        }    }    protected void onPreExecute(WeakTarget target) {        // No default action    }    protected abstract Result doInBackground(WeakTarget target, Params... params);    protected void onPostExecute(WeakTarget target, Result result) {        // No default action    }}

而通常,weaktarget经常会以activity为参数,这样的话,就更为贴切的。因为context的错误引用而导致的内存溢出问题也是挺常见的。


2. Sqlite机制导致的饿死(ANR)
我们知道,Android的数据库是用的sqlite,而且sqlite是全局的,也就是说,对于一个Android系统实例而言,所有的程序将会共用一个sqlite database。这里就会有一个有意思的事情发生:当某个应用A正在进行某个长耗时的数据库操作时,另外一些应用B在此期间也需要进行数据库操作,但是数据库被A独占,B只能等,等着等着,超过5秒了,好吧,B被ANR了。

事实上,这种情况不总出现。前提是A的操作属于独占式的操作,B在主线程上进行数据库操作。解决方法自然也分为两种,一种是A换用批量操作API:ContentProviderOperation,用ContentProviderOperation.Builder.withYieldAllowed (true)来允许当前的数据库操作可以被挂机;另外一种是B不要在主线程里进行数据库操作。

说道这里,我更加明白了google I/O视频上那个大哥为啥说"never, never, never do slow things on UI thread"了,因为没准哪天,你就被别人ANR了。。

3.如何解决ANR

一个朋友去一家智能手机公司面试开发时被问到如何解决ANR的问题。正好,公司的arc前两天对解决ANR进行一些经验分享。(总结的不一定全)

1.ANR有哪几种?

从ActivityManagerService的实现可以看到,ANR有四种,分别对应Android的四个fundermetals。这个也不难理解:所有fundermetal都会在main thread上运行,如果超过了响应的间隔,那么就会ANR。另外JNI调用native函数时也会发生无响应,不过我觉得应该不算单独的一种,它只是未响应发生在了native里,而不是vm里。

2.ANR是什么?

从ActivityManagerService可以看到,作为一个manager类,要去检测所管理的对象是否处于可相应状态,一个不错的方式就是给那个对象发消息,并等待回调。事实上,就是这么做的。每隔一段时间,manager会发消息给所有fundamental,这个消息格式固定,同时带一个delay time,譬如说activity的delay time就是5000ms,当消息发出之后,5000ms之内没有收到相应,那么manager就要把那个activity ANR掉。对于broadcast receiver、provider和service也是同样的,只是delay time不一样。

以Activity为例,几个负责Activity生命周期的回调方法(以on开头的那几个),被调用后,5000ms内没有返回,那么就ANR鸟。另外还有key dispatch ANR,也就是说,当用户点击了进行了某些操作产生key event了,那么应用就必须在规定时间处理key event,如果超时,会立刻ANR。

3.ANR的导致原因

我叙述一下google I/O 2010上一个presentation上说的:就是性能问题。我们知道,一般情况下,Android系统的瓶颈经常在I/O操作,无论是本地还是网络,经常会导致程序看起来不那么顺畅,如果达到某个时间没有响应,那么就ANR鸟。我猜测,

4.如何避免ANR

"Never never never do slow things on main thread".我引用了那个presentation的原话。

5.如何解决ANR的问题

上面介绍了ANR的一些基本知识,但是在现实问题中,ANR的问题经常会比较难解决。而且每一种ANR在logcat的信息中都会有不同的。如果要了解不同ANR的特点,就需要些多个实例来观察log信息。这里需要关注的几个信息是,线程、内存、CPU、异常堆栈等信息。google貌似提供了工具来dump发生ANR时的系统及APP信息。

更多相关文章

  1. Android开发学习之SQLite数据库初探
  2. Android(安卓)laucher总结
  3. App混合开发之WebView进行H5页面基本操作
  4. android 数据库之Cursor
  5. Android(安卓)4.1的新特性介绍
  6. 让我们来看看安卓这十年到底有哪些变化
  7. Android(安卓)基础知识4:四大组件之 ContentProvider(外共享数据)
  8. Android中Adapter中edittext,checkbox记住状态解决方案(二)
  9. android连接远程数据库教程1

随机推荐

  1. Android中的WebView控件用法
  2. 来电防火墙——学习记录
  3. android的UI操作单线程模型理解
  4. 学习Android前需要了解的几个重要概念
  5. 《Android Studio实用指南》12.18 文本搜
  6. 项目中平时遇到的小知识点集锦
  7. Android(安卓)PullToRefresh (ListView Gr
  8. Android 2.2 API demos -- Dialog
  9. android zxing 4.7.1横屏改竖屏 screenOr
  10. Android中的OpenSL ES是如何实现的?