目录

1. 定义

1.1 AsyncTask 的三个泛形参数

1.2 AsyncTask的4个核心方法

1.3 取消任务

2. 简单Demo上手

2.1 Java 版本

2.2 Kotlin 版本

3. AsyncTask 如何防止内存泄露


1. 定义

官方解释:AsyncTask可以正确及方便地使用UI线程。此类允许您执行后台操作并在UI线程上发布结果,而无需通过操作Thread和Handler。AsyncTasks应该用于短操作(最多几秒钟)。异步任务在后台线程运行计算,其结果在UI线程上发布。

1.1 AsyncTask 的三个泛形参数

java.lang.Object   ↳android.os.AsyncTask

1. Params(传入参数):在执行 execute(Params... params) 任务方法时传入。

2. Progress(执行进度):在后台计算期间发布的进度单位。

3. Result(执行结果):后台的计算结果。 这三个参数不是每次都必须被定义使用,如果你不想使用,就定义为 Void。 如果三个参数都不使用,如下所以:

private class MyTask extends AsyncTask { ... }

1.2 AsyncTask的4个核心方法

当 AsyncTask 被执行时,会经历4个步骤,分别是onPreExecute()、doInBackground()、onProgressUpdate()、onPostExecute()。 分别是:

1、onPreExecute():在 UI 线程上工作,在任务执行 doInBackground() 之前调用。此步骤通常用于设置任务,例如在用户界面中显示进度条。

2、doInBackground(Params...params):在子线程中工作,在 onPreExecute() 方法结束后执行,这一步被用于在后台执行长时间的任务,Params 参数通过 execute(Params) 方法被传递到此方法中。任务执行结束后,将结果传递给 onPostExecute(Result) 方法,同时我们可以通过 publishProgress(Progress) 方法,将执行进度发送给 onProgressUpdate(Progress) 方法。

3、onProgressUpdate(Progress...values):在 UI 线程上工作,会在 doInBackground() 中调用 publishProgress(Progress) 方法后执行,此方法用于在后台计算仍在执行时(也就是 doInBackgound() 还在执行时)将计算执行进度通过 UI 显示出来。例如,可以通过动画进度条或显示文本字段中的日志,从而方便用户知道后台任务执行的进度。

4、onPostExecute(Result result):在 UI 线程上工作,在任务执行完毕(即 doInBackground(Result) 执行完毕)并将执行结果传过来的时候工作。

1.3 取消任务

一个任务可以通过调用 cancel() 方法在任何时间取消。调用此方法后再调用 isCancelled() 方法,返回 true。调用此方法后,onPostExecute() 方法将在 onCancel() 方法返回后调用,而不是在 doInBackground() 返回结果后调用。为了确保任务被尽快取消,你应该在 doInBackground() 方法中进行周期性地检查 isCancelled() 的返回值,如果可能的话(例如在一个循环中进行检查),比如下面例子:

@Overrideprotected String doInBackground(String... strings) {    for (int i = 1; i <= 10; i++) {···        //在for循环中进行周期性检查,检查异步任务是否被取消        if (isCancelled()) {            break;        }        ···    }    ···    return result;}

2. 简单Demo上手

点击 Start AsyncTask 按钮,开始执行异步任务,点击 Stop AsyncTask 按钮,取消任务执行。效果如下所示:

2.1 Java 版本

详细代码:

public class AsyncTaskActivity extends AppCompatActivity implements View.OnClickListener {    private ProgressBar progressBar;    private TextView displayTv;    private Button startBtn, stopBtn;    private MyAsyncTask myAsyncTask;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_async_task);        progressBar = findViewById(R.id.progress_bar);        displayTv = findViewById(R.id.display_tv);        startBtn = findViewById(R.id.start_btn);        stopBtn = findViewById(R.id.stop_btn);        myAsyncTask = new MyAsyncTask();        startBtn.setOnClickListener(this);        stopBtn.setOnClickListener(this);    }    @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.start_btn:                myAsyncTask.execute("Jere test");                //AsyncTask只能执行一次,如果你在AsyncTask执行过程中再次调用 execute() 执行它,就会跳IllegalStateException异常                //java.lang.IllegalStateException: Cannot execute task: the task is already running.                startBtn.setEnabled(false);                break;            case R.id.stop_btn:                //中断线程执行                myAsyncTask.cancel(true);                break;            default:                break;        }    }    /**     * 创建MyAsyncTask类, 继承AsyncTask类 -> AsyncTask     * 3个泛型参数指定类型:     * Params(输入参数): String类型     * Progress(执行进度): Integer类型     * Result(执行结果): String类型     */    private class MyAsyncTask extends AsyncTask {        /**         * 在后台任务开始计算执行前执行onPreExecute()操作         */        @Override        protected void onPreExecute() {            super.onPreExecute();            displayTv.setText("onPreExecute: start! ");            Toast.makeText(AsyncTaskActivity.this, "onPreExecute", Toast.LENGTH_SHORT).show();        }        /**         * 接收输入参数,执行后台任务中的计算工作(耗时操作),计算结束,返回计算结果         * @param strings Params输入参数,在主线程执行execute()传入的参数         * @return 返回执行结果给onPostExecute()         */        @Override        protected String doInBackground(String... strings) {            for (int i = 1; i <= 10; i++) {                try {                    Thread.sleep(500);                } catch (InterruptedException e) {                    e.printStackTrace();                }                //通过调用publishProgress()方法,将执行进度传递给onProgressUpdate()                publishProgress(i);            }            String result;            result = Arrays.toString(strings) + " return from doInBackground";            return result;        }        /**         * 接收后台计算执行进度,在UI线程中通过ProgressBar现实执行进度。         * @param values : 执行进度,通过publishProgress()传入         */        @Override        protected void onProgressUpdate(Integer... values) {            super.onProgressUpdate(values);            //得到一个整型数组,但每次里面只有一个元素,所有通过values[0]就可以拿到当前的执行进度            progressBar.setProgress(values[0]);            displayTv.setText("onProgressUpdate: value = " + values[0]);        }        /**         * 接收后台任务计算结束返回的结果,在UI线程上显示出来         * @param s :后台计算结束返回的执行结果,由doInBackground()返回         */        @Override        protected void onPostExecute(String s) {            super.onPostExecute(s);            displayTv.setText("onPostExecute: " + s);            Toast.makeText(AsyncTaskActivity.this, "onPostExecute", Toast.LENGTH_SHORT).show();        }        /**         * 在主线程中调用cancel()方法,执行onCancelled(),取消执行后台任务         *         * 当任务计算完成时,无法取消任务,或者已经取消任务后不可再次取消         */        @Override        protected void onCancelled() {            super.onCancelled();            displayTv.setText("onCancelled");            progressBar.setProgress(0);            Toast.makeText(AsyncTaskActivity.this, "onCancelled", Toast.LENGTH_SHORT).show();        }    }}

点击 “Stop AsyncTask” 按钮, 执行 onCancelled() 方法,实现中断线程任务的效果如下:

2.2 Kotlin 版本

class TestAsyncTaskActivity : AppCompatActivity(), View.OnClickListener {    private var mAsyncTask: MyAsyncTask? = null    companion object {        const val TAG = "JereTest"    }    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_test_async_task)        mAsyncTask = MyAsyncTask(this)        startBtn.setOnClickListener(this)        cancelBtn.setOnClickListener(this)    }    override fun onClick(v: View?) {        when (v?.id) {            R.id.startBtn -> {                mAsyncTask?.execute("jereTest")                startBtn.isEnabled = false            }            R.id.cancelBtn -> mAsyncTask?.cancel(true)        }    }    class MyAsyncTask(activity: TestAsyncTaskActivity) : AsyncTask() {        private var weakRef: WeakReference? = null        init {            weakRef = WeakReference(activity)        }        override fun onPreExecute() {            super.onPreExecute()            val activity = weakRef?.get()            if (activity != null && !activity.isFinishing) {                Toast.makeText(activity, "MyAsyncTask onPreExecute()", Toast.LENGTH_SHORT).show()            }        }        override fun doInBackground(vararg params: String?): String {            for (i in 0..10) {                try {                    Thread.sleep(500)                } catch (e: InterruptedException) {                    e.printStackTrace()                }                //通过调用publishProgress()方法,将执行进度传递给onProgressUpdate()                publishProgress(i)                if (isCancelled) {                    break                }            }            return params[0]!!        }        override fun onProgressUpdate(vararg values: Int?) {            super.onProgressUpdate(*values)            val activity = weakRef?.get()            if (activity != null && !activity.isFinishing) {                activity.progressBar.progress = values[0]!!                activity.displayTv.text = "onProgressUpdate: value = " + values[0]            }        }        override fun onPostExecute(result: String?) {            super.onPostExecute(result)            val activity = weakRef?.get()            if (activity != null && !activity.isFinishing) {                Toast.makeText(activity, "MyAsyncTask onPostExecute()" + result, Toast.LENGTH_SHORT)                    .show()            }        }        override fun onCancelled() {            super.onCancelled()            Log.e(TAG, "click cancel button, cancel task execute")            val activity = weakRef?.get()            if (activity != null && !activity.isFinishing) {                Toast.makeText(activity, "cancel task", Toast.LENGTH_SHORT).show()            }        }    }}

 

3. AsyncTask 如何防止内存泄露

如上方 Demo 所示的代码,我们在 Activity 中创建了 MyAsyncTask 内部类, 来进行异步处理,然后引用 Activity 中的全局变量 progressBar 及 displayTv 来显示异步处理完的结果。这样的用法带来的结果就是,在实际使用中,我们都是将耗时的操作放到 AsyncTask 中的 doInBackground() 子线程中处理,其操作处理周期会超出该 Activity 的生命周期,但由于其一直引用着该 Activity,导致该 Activity 不会被垃圾回收机制回收,从而导致内存泄露。所以 Android Studio 也给了我们的警告提示!如下图所示:

This AsyncTask class should be static or leaks might occur (这个AsyncTask类应该是静态的,否则可能会发生泄漏),解决的方法呢,就是将该内部类写成静态的内部类,然后对 Activity(或者的需要的 Context)采用 WeakReference 弱引用, 方法如下所示:

// 1. 对 Activity 进行弱引用private WeakReference activityWeakReference;MyAsyncTask(Activity activity) {    activityWeakReference = new WeakReference<>(activity);}// 2. 对 Context 进行弱引用private WeakReference contextWeakReference;MyAsyncTask(Context context) {    contextWeakReference = new WeakReference<>(context);}

下面,我们将刚刚的 MyAsyncTask.java 进行重构,将 MyAsyncTask 改成静态的内部类,然后对 AsyncTaskActivity 进行弱引用,如下所示:

private static class MyAsyncTask extends AsyncTask {    private WeakReference asyncTaskActivityWeakReference;    MyAsyncTask(AsyncTaskActivity asyncTaskActivity) {        asyncTaskActivityWeakReference = new WeakReference<>(asyncTaskActivity);    }    /**     * 在后台任务开始计算执行前执行onPreExecute()操作     */    @Override    protected void onPreExecute() {        super.onPreExecute();        AsyncTaskActivity asyncTaskActivity = asyncTaskActivityWeakReference.get();        //只有在 AsyncTaskActivity 没被销毁的时候才显示 displayTv 及 Toast.        if (asyncTaskActivity != null && !asyncTaskActivity.isFinishing()) {            asyncTaskActivity.displayTv.setText("onPreExecute: start! ");            Toast.makeText(asyncTaskActivity, "onPreExecute", Toast.LENGTH_SHORT).show();        }    }    /**     * 接收输入参数,执行后台任务中的计算工作(耗时操作),计算结束,返回计算结果     * @param strings Params输入参数,在主线程执行execute()传入的参数     * @return 返回执行结果给onPostExecute()     */    @Override    protected String doInBackground(String... strings) {        for (int i = 1; i <= 10; i++) {            try {                Thread.sleep(500);            } catch (InterruptedException e) {                e.printStackTrace();            }            //通过调用publishProgress()方法,将执行进度传递给onProgressUpdate()            publishProgress(i);        }        String result;        result = Arrays.toString(strings) + " return from doInBackground";        return result;    }    /**     * 接收后台计算执行进度,在UI线程中通过ProgressBar现实执行进度。     * @param values : 执行进度,通过publishProgress()传入     */    @Override    protected void onProgressUpdate(Integer... values) {        super.onProgressUpdate(values);        AsyncTaskActivity asyncTaskActivity = asyncTaskActivityWeakReference.get();        //只有在 AsyncTaskActivity 没被销毁的时候才显示 progressBar 及 displayTv.        if (asyncTaskActivity != null && !asyncTaskActivity.isFinishing()) {            //得到一个整型数组,但每次里面只有一个元素,所有通过values[0]就可以拿到当前的执行进度            asyncTaskActivity.progressBar.setProgress(values[0]);            asyncTaskActivity.displayTv.setText("onProgressUpdate: value = " + values[0]);        }    }    /**     * 接收后台任务计算结束返回的结果,在UI线程上显示出来     * @param s :后台计算结束返回的执行结果,由doInBackground()返回     */    @Override    protected void onPostExecute(String s) {        super.onPostExecute(s);        AsyncTaskActivity asyncTaskActivity = asyncTaskActivityWeakReference.get();        //只有在 AsyncTaskActivity 没被销毁的时候才显示 displayTv 及 Toast.        if (asyncTaskActivity != null && !asyncTaskActivity.isFinishing()) {            asyncTaskActivity.displayTv.setText("onPostExecute: " + s);            Toast.makeText(asyncTaskActivity, "onPostExecute", Toast.LENGTH_SHORT).show();        }    }    /**     * 在主线程中调用cancel()方法,执行onCancelled(),取消执行后台任务     *     * 当任务计算完成时,无法取消任务,或者已经取消任务后不可再次取消     */    @Override    protected void onCancelled() {        super.onCancelled();        AsyncTaskActivity asyncTaskActivity = asyncTaskActivityWeakReference.get();        //只有在 AsyncTaskActivity 没被销毁的时候才显示 progressBar displayTv Toast.        if (asyncTaskActivity != null && !asyncTaskActivity.isFinishing()) {            asyncTaskActivity.displayTv.setText("onCancelled");            asyncTaskActivity.progressBar.setProgress(0);            Toast.makeText(asyncTaskActivity, "onCancelled", Toast.LENGTH_SHORT).show();        }    }}

 

具体代码请看 -> 源代码

Peace~

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. Python list sort方法的具体使用
  3. python list.sort()根据多个关键字排序的方法实现
  4. android上一些方法的区别和用法的注意事项
  5. android实现字体闪烁动画的方法
  6. Android中dispatchDraw分析
  7. Android四大基本组件介绍与生命周期
  8. Android(安卓)MediaPlayer 常用方法介绍
  9. 在Fragment中设置控件点击方法,执行失败。

随机推荐

  1. Android GPS学习笔记—HAL实现
  2. Android跨进程通信-IPC初探(三) - 使用AI
  3. cocos2dx通过Jni调用Android的Java层代码
  4. android load 本地 html 页面
  5. 新建android project和其配置文件的基本
  6. Android自定义动画框架让View实现Path动
  7. Mstar虚拟按键触摸屏驱动(芯片msg2133,按键
  8. Android绘图之绘制太极图
  9. 查询能够响应某一Intent的所有Activity
  10. android日期选择器,从底部弹出的日期选择