### AsyncTask用法
> 参考:[AndroidDevelopersReference](https://developer.android.google.cn/reference)
>
> 参考:《第一行代码》- 郭霖
由于在安卓中许手动显式创建线程会比较耗费资源,使用AsyncTask或者线程池是比较好的做法。而我写的程序里面包含了一个okhttp的异步请求,故今天想把okhttp的异步请求转换到AsyncTask中来实现。
在《第一行代码》里,AsyncTask的建立方法是单独建立一个类。但是我刚从web开发过来,有点不适应Android遍地都是类的情形。同时,我建立的这个AsyncTask是只有一个类使用的,所以将其作为使用类的内部类也是可以的。
但是这里要注意一点情况,和Handler一样,作为内部类的非静态类会隐式持有外部类的引用。这就导致了当AsyncTask或者Handler的生命周期比他的外部类长的时候,虚拟机无法回收外部类,因为AsyncTask或Handler仍然存在对外部类的引用,故外部类仍然处于可达性算法中的可达范围内(可达性算法可见我的文章:[[【学习】内存回收器 GC](http://cong-onion.cn/archives/内存回收器-GC)](http://cong-onion.cn/archives/%E5%86%85%E5%AD%98%E5%9B%9E%E6%94%B6%E5%99%A8-GC))。所以为了避免内存泄漏,最好使用静态内部类。关于内部类我后面考虑再开一篇文章单独来讲一下。
### 什么是AsyncTask
先引用Android Developers的官方文档:
>AsyncTask enables proper and easy use of the UI thread. This class allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
总的来说就是AsyncTask是用来简单、快捷实现需要在子线程内执行的任务的。比如说一些`相对`耗时的操作,如IO、网络请求等
> AsyncTask is designed to be a helper class around `Thread` and `Handler` and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the `java.util.concurrent` package such as `Executor`, `ThreadPoolExecutor` and `FutureTask`.
这句话解释了我上面说为什么是`相对`耗时。这里说明了AsyncTask是用于短任务的,最多几秒钟,如果有更长的时间的话还是用Java提供的J.U.C包和其他API好。
> An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called `Params`, `Progress` and `Result`, and 4 steps, called `onPreExecute`, `doInBackground`, `onProgressUpdate` and `onPostExecute`.
要继承AsyncTask,需要三个泛型,分别是`传入值`、`进度(一般用Interger)`、`结果`。还有四个方法:
+ onPreExecute:执行前操作,可以用于初始化操作,比如显示进度条
+ doInBackground:执行中,`这里面所有的代码都会被放在子线程中运行`。所以不能在这里进行任何的UI操作。如果需要更新UI元素,比如反馈当前任务的进度,可以调用publishProgress(Progress...)来完成。
+ onProgressUpdate:当在后台任务(子线程任务)调用了publishProgress后,这个方法很快会被调用。这个方法是运行在主线程的,所以可以用来进行UI操作。
+ onPostExecute(Result):当后台任务执行完毕并通过了return语句返回时,这个方法很快就会被调用。返回的数据会作为参数传递到这个方法中,可以利用这个方法来进行一些UI操作,比如我这里面的`把从网络上请求而来的数据显示在UI上`
我的实现方式如下:
```java
private static class RequestDataAsyncTask extends AsyncTask<Void, Integer, List<Bean>> {
// deal with memory leak
WeakReference<Fragment> fragment;
private RequestDataAsyncTask(Fragment fragment) {
this.Fragment = new WeakReference<>(fragment);
}
@Override
protected List<Bean> doInBackground(Void... voids) {
List<Bean> beanList = new ArrayList<>();
OkHttpClient okHttpClient = new OkHttpClient();
/* do some network works */
return beanList;
}
// the reasult of doInBackground will pass into this method
@Override
protected void onPostExecute(List<Bean> beanList) {
/* refresh the UI, such as pushing data into the RecyclerView */
}
}
}
```
值得注意的是,为了解决上述的内存泄漏问题,在这里我采取了官方推荐的写法:
+ 声明内部类为静态,静态类不会隐式持有外部类的指针,从而不会造成外部类无法被回收
+ 外部类作为弱引用传入内部类中。这样在内存紧张的情况下,在允许的情况下VM讲有机会回收外部类。
上述两点方法可以避免在AsyncTask的生命周期在比外部类(如Activity/Fragment等)长时外部类无法回收的问题
【学习】Android中AsyncTask的学习与实践笔记