Android中我们经常需要开启子线程去获取网络数据,或者说做一些耗时操作,开发者经常使用的就是AsyncTask,Android 1.5提供的工具类AsyncTask使我们创建异步线程更加便捷。如果你还没有AsyncTask的基础,那么先阅读一下这篇博文吧。
Android多线程编程(异步通信)—>Handler和AsyncTask

本博文编写的理由:
线程的关闭,可以通过在activity的destroy方法中执行task的cancel方法,通过判断isCancelled值来退出任务,在activity结束的时候就结束了任务。但是相对于其他情况(比如说操作网络的时候),doInBackground方法里面还是会继续执行,直到结束。但是至少,我们使用了cancel方法,最终不会执行onPostExecute,而改去执行onCancelled。
于是相对于不能中断的任务,为避免任务一直持有activity,我们可以通过使用静态内部类,并且使用WeakReference来包裹我们的activity以达到更新UI的目的。

1.线程AsyncTask产生的问题

  • 开启线程后,未结束,此时用户又一次,甚至多次开启线程,导致多次请求。
    解决方式:将线程写为静态static。
  • 当用户开启线程后,退出界面,多次进入。由于线程持有Activity的变量的实例,导致Activity无法被回收,从而导致内存泄漏
    解决方式:采用弱引用的方式,将线程与Activity进行解耦。

2.弱引用的理解

强引用、弱引用经常用来解决OOM的问题。
先来说一下 强引用 吧:
Android —— 静态AsyncTask解决内存泄漏_第1张图片
注:如果强引用的对象只要不为null,gc就不会回收掉。
弱引用:弱引用是通过WeakReference类实现,使gc可以进行回收。
Android —— 静态AsyncTask解决内存泄漏_第2张图片

3.将线程静态后的优缺点

前面我们说了可以将线程做成静态的,加上利用弱引用实现线程和Activity的解耦。而静态后随出现了一些问题需要我们考虑:

  • 1)静态类中使用的变量需要静态,有何隐患。
    静态类是一直在内存中存在的,占用一定的内存,所以静态变量和类不能过多,否则会导致内存的不足。
    但必要时也是不可避免的。
  • 2)静态线程的开启方式,以及当线程需要外部传参的实现:
    线程的启动
    利用创建实例的方式:一个AsyncTask实例只能被执行一次;采用此方式那么传参可以直接通过线程的构造函数即可。

例如对于创建的LocalProductAsyncTask线程:开启方式。

refreshTask = new LocalProductAsyncTask(mView, 1, mConfig.mPageSize, classiftDatas, keyWord, false);                    refreshTask.execute();

传参:
不管线程是静态还是非静态,开启时都需要new 实例,这个时候传参就可以了。

4.具体的实现过程

用静态内部类来防止持有外部类的隐性引用。
实例1:handler弱引用:
Android —— 静态AsyncTask解决内存泄漏_第3张图片
实例2:附上完整代码:

public class AsyncTaskActivity extends Activity {    private AsyncTask task;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        /* 用匿名内部类的方式创建*/         task = new AsyncTask() {            @Override            protected Object doInBackground(Object[] params) {                for(int i=0;i<10;i++){                    Log.i("task","i="+i);                    try {                        Thread.sleep(2000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    if(isCancelled()){                        break;                    }                }                return null;            }             @Override             protected void onPostExecute(Object o) {                 super.onPostExecute(o);                 Log.i("task","执行结束了");             }             @Override             protected void onCancelled() {                 super.onCancelled();                 Log.i("task","执行了取消");             }         };        task.execute();        //从log可以看到,上个task和下面的task是串行执行的        new MyTask(this).execute();    }    @Override    protected void onDestroy() {        super.onDestroy();        task.cancel(true);        //这里不做取消MyTask的任务是为了验证weakReference是否起作用    }    public void doSomething(){        //为保险,还是需要判断下当前activity是否已经销毁,因为weakReference修饰的对象并不是马上就能被回收        Log.i("AsyncActivity","异步任务完成,更新UI");    }    static class MyTask extends AsyncTask{        private WeakReference weakAty;        public MyTask(Activity activity){            weakAty = new WeakReference(activity);        }        @Override        protected String doInBackground(String... params) {            for(int i=0;i<100;i++){                Log.i("Mytask","i="+i);                try {                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                if(isCancelled()){                    break;                }            }            return null;        }        @Override        protected void onPostExecute(String s) {            super.onPostExecute(s);            Log.i("Mytask","执行结束了");            AsyncTaskActivity mActivity;            if((mActivity= (AsyncTaskActivity) weakAty.get())!=null){                mActivity.doSomething();            }        }        @Override        protected void onCancelled() {            super.onCancelled();            Log.i("Mytask","执行了取消");        }    }}

更多相关文章

  1. Android 高性能编码一:多线程并发或分布式提高TPS
  2. Android入门篇三:使用静态变量在Activity之间传递数据
  3. Anbox:在 Linux 上运行 Android 应用程序的简单方式 | Linux 中国
  4. Android启动界面优化技巧-Splash Screens的正确方式
  5. Android Asynchronous Http Client - 开源http 多线程引擎
  6. Android的两种数据存储方式分析(二)
  7. Android TextView 添加下划线的几种方式
  8. Android 、BlackBerry 文本对齐方式对比
  9. Android异步任务AsyncTask实现方式

随机推荐

  1. Mac 下使用 clion 调试 PHP 内核源码
  2. PHP在引号前面添加反斜杠及去除反斜杠的
  3. PHP中钩子的理解与实例教程
  4. PHP 核心特性之匿名函数
  5. PHP与Python进行数据交互
  6. php命令行下的常用命令总结
  7. 正确理解 PHP 的重载
  8. 2021最新swoole视频教程推荐(从入门到高级
  9. 匿名函数
  10. PHP中global与$GLOBALS的区别