AsyncTask面试知识小结

前言

今天我们来回顾复习下AsyncTask, 它是Android 一种轻量级的异步任务类,从实现来说,AsyncTask封装了线程池和Handler。它可以在线程池中执行后台任务,把执行的进度和结果传递给主线程并在主线程中更新UI,通过AsyncTask可以更加方便的执行后台任务以及在主线程访问UI,但他不适合进行特别耗时的后台任务。

一、什么是AsyncTask?

1、是一种轻量级的异步任务类;
2、是一个封装了线程池和Handler的异步框架;
3、使用它可以更加方便的执行后台任务以及在主线程访问UI,但他不适合进行特别耗时的后台任务;

二、AsyncTask的使用方法

1、3个参数
  • Params:执行AsyncTask时,后台任务需要传入的参数,在doInBackground中取出使用。
  • Progress:后台任务执行时,如果需要显示当前进度,则制定进度的数据类型。
  • Result:后台任务执行完成后的返回值类型。
2、5个方法
  • onPreExecute:
    在主线程中执行,在后台任务执行前调用,通常用于做一些准备操作。

  • doInBackground(Params… params):
    在线程池中执行,用于执行后台任务;params 参数是 execute(Params… params)方法中传递的参数。在此方法中可以调用 publishProgress 方法来更新任务的进度,publishProgress方法会调用onProgressUpdate方法。

  • publishProgress(Progress… values):
    用于更新任务的进度,需要手动调用,publishProgress方法会调用onProgressUpdate方法;values参数为设置的进度值。

  • onProgressUpdate(Progress… values):
    在主线程中执行,当后台任务的执行进度发生改变时,会被调用,values参数为进度值。

  • onPostExecute(Result result):
    在主线程中执行,当后台任务执行完成时,会被调用。result 的值是doInBackground的返回值。

三、AsyncTask的机制原理

  • AsyncTask 的本质是一个静态的线程池,可以执行不同的异步任务,这些任务提交到静态的线程池中执行。
  • 线程池中的工作线程执行doInBackgroup(Params… params)方法执行异步任务。
  • 当任务状态改变后,工作线程向UI线程发送消息,AsyncTask内部的InternalHandler 响应这些消息,并调用相关的回调函数。

四、AsyncTask的注意事项

1、内存泄漏
  • 原因:非静态内部类持有外部类的匿名引用,导致Activity无法释放。

  • 解决:

    • AsyncTask内部持有外部Activity的弱引用。
    • AsyncTask改为静态内部类。
    • AsyncTask.cancel()。
2、生命周期

不受Activity生命周期的影响,在Activity销毁之前,取消AsyncTask的运行,以此来保证程序的稳定。

3、结果丢失

由于屏幕旋转、Activity在内存紧张时被回收等情况下,Activity会被重新创建,此时,还在运行的AsyncTask会持有一个Activity的非法引用即之前的Activity实例。导致onPostExecute()没有任何作用。

4、并行or串行
  • Android 1.6之前,默认采用串行执行任务;
  • Android 1.6~ 2.3 ,默认采用并行执行任务;
  • Android 3.0,默认采用串行执行任务,如果需要改为并行,可以调用AsyncTask的executeOnExecutor()来执行任务即可。

5、AsyncTask的使用限制

  • AsyncTask的对象必须在主线程中创建;
  • execute 方法必须在UI线程调用;
  • 不要在程序中手动调用 onPreExecute、onPostExecute、 doInBackground、onProgressUpdate方法;
  • 一个AsyncTask对象只能调用一次excute()方法,执行一次,否则会报异常。

6、代码实践

模拟文件下载:
package com.example.ling.review.asynctask;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;

import java.lang.ref.WeakReference;


public class AsyncTaskActivity extends AppCompatActivity {
    private DownLoadFileTask mTask = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 创建 DownLoadFileTask 实例
        mTask = new DownLoadFileTask(this);
        // 执行任务
        mTask.execute("参数1", "参数2", "参数3");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 取消 AsyncTask的任务
        mTask.cancel(true);
    }

    /**
     * 1、DownLoadFileTask 改为静态内部类,避免内存泄漏
     * 2、将Activity 包装成弱引用,避免内存泄漏
     */
    public static class DownLoadFileTask extends AsyncTask<String, Integer, String> {
        private WeakReference<AsyncTaskActivity> mWeakReference = null;
        private ProgressDialog mProgressDialog = null;
        private Context mContext = null;

        public DownLoadFileTask(AsyncTaskActivity activity) {
            mWeakReference = new WeakReference<>(activity);
        }

        /**
         * 运行在主线程,执行后台任务之前调用,通常用来做一些准备操作
         */
        @Override
        protected void onPreExecute() {
            mContext = mWeakReference.get();
            if (mContext != null) {
                mProgressDialog = new ProgressDialog(mContext);
                mProgressDialog.setCancelable(false);
                mProgressDialog.setTitle("任务正在执行中");
                mProgressDialog.setMessage("任务正在执行中,敬请期待...");
                mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                mProgressDialog.setMax(200);
                mProgressDialog.show();
            }
        }

        /**
         * 运行在线程池中,执行后台耗时操作
         *
         * @param strings 参数
         * @return 结果
         */
        @Override
        protected String doInBackground(String... strings) {
            // 打印 mTask.execute();传递的参数
            StringBuilder builder = new StringBuilder();
            for (String string : strings) {
                builder.append(string).append(",");
            }
            Log.d("doInBackground", builder.toString());

            // 模拟下载
            int progress = 0;
            while (progress < 200) {
                try {
                    Thread.sleep(1000);   // 模拟耗时操作
                    progress += 10;
                    publishProgress(progress);// 更新进度,该方法调用后会触发 onProgressUpdate方法
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            publishProgress(progress);
            String msg = "文件下载成功!";
            return msg;
        }

        /**
         * 运行在主线程,用于更新进度,publishProgress方法执行后,会触发该方法
         *
         * @param values 进度值
         */
        @Override
        protected void onProgressUpdate(Integer... values) {
            if (mProgressDialog != null) {
                mProgressDialog.setProgress(values[0]);
            }
        }

        /**
         * 运行在主线程,后台任务执行完成后,将返回值传给该方法
         *
         * @param s 返回的结果
         */
        @Override
        protected void onPostExecute(String s) {
            if (mContext != null) {
                mProgressDialog.dismiss();
                Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show();
            }
        }
    }
}
模拟文件下载:运行结果:

1、打印参数日志:
01-28 10:25:56.385 5019-5089/com.example.ling.review D/doInBackground: 参数1,参数2,参数3,

2、运行界面效果

asyncTask

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章