Android面试系列文章2018之Android部分AsyncTask机制篇

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ClAndEllen/article/details/79346383

Android面试系列文章2018之Android部分AsyncTask机制篇

AsyncTask知识体系图

1.AsyncTask是什么?

  它本质上是一个封装了线程池和Handler的异步框架。

2.AsyncTask的基本用法

  使用AsyncTask要理解3个泛型参数和4个方法,一旦理解这个三四,那么AsyncTask使用起来非常熟悉了。

  我们就拿下载图片作为一个例子,代码如下:

public class MyAsyncTask extends AsyncTask<String,Integer,Bitmap>{

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        //这里是在异步操作之前执行,运行在UI线程,一般显示给用户:此时即将要去加载图片了

        //此处将progressBar设置为可见.
        // progressBar.setVisibility(View.VISIBLE);

    }

    @Override
    protected Bitmap doInBackground(java.lang.String... strings) {
        //这里执行耗时操作,此例子中,是网络请求图片的操作
        Bitmap bitmap = null;

        String url = strings[0];//获取加载的图片的url

        //......
        //以上是网络请求图片的代码,并将图片封装到bitmap中

        publishProgress(22);//此方法的调用将会触发onProgressUpdatef方法的调用

        return bitmap;
    }


    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);

        //此方法运行于UI线程,一般用来更新进度
        //progressBar.setProgress(values[0]);


    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        super.onPostExecute(bitmap);
        //此方法中bitmap是doInBackground执行完成后返回的,而且此方法运行在UI线程,更新UI

        //隐藏progressBar
        //progressBar.setVisibility(View.GONE);
        //更新imageView
        //imageView.setImageBitmap(bitmap);

    }
}

由以上代码,笔者总结如下:

3个泛型指的是什么呢?我们来看看AsyncTask这个抽象类的定义,当我们定义一个类来继承AsyncTask这个类的时候,我们需要为其指定3个泛型参数:

AsyncTask <Params, Progress, Result>

  • Params: 这个泛型指定的是我们传递给异步任务执行时的参数的类型

  • Progress: 这个泛型指定的是我们的异步任务在执行的时候将执行的进度返回给UI线程的参数的类型

  • Result: 这个泛型指定的异步任务执行完后返回给UI线程的结果的类型
    我们在定义一个类继承AsyncTask类的时候,必须要指定好这三个泛型的类型,如果都不指定的话,则都将其写成Void,例如:

    AsyncTask <Void, Void, Void>

4个步骤:当我们执行一个异步任务的时候,其需要按照下面的4个步骤分别执行

  • onPreExecute(): 这个方法是在执行异步任务之前的时候执行,并且是在UI Thread当中执行的,通常我们在这个方法里做一些UI控件的初始化的操作,例如弹出要给ProgressDialog
  • doInBackground(Params… params): 在onPreExecute()方法执行完之后,会马上执行这个方法,这个方法就是来处理异步任务的方法,Android操作系统会在后台的线程池当中开启一个worker thread来执行我们的这个方法,所以这个方法是在worker thread当中执行的,这个方法执行完之后就可以将我们的执行结果发送给我们的最后一个 onPostExecute 方法,在这个方法里,我们可以从网络当中获取数据等一些耗时的操作
  • onProgressUpdate(Progess… values): 这个方法也是在UI Thread当中执行的,我们在异步任务执行的时候,有时候需要将执行的进度返回给我们的UI界面,例如下载一张网络图片,我们需要时刻显示其下载的进度,就可以使用这个方法来更新我们的进度。这个方法在调用之前,我们需要在 doInBackground 方法中调用一个 publishProgress(Progress) 的方法来将我们的进度时时刻刻传递给 onProgressUpdate 方法来更新
  • onPostExecute(Result… result): 当我们的异步任务执行完之后,就会将结果返回给这个方法,这个方法也是在UI Thread当中调用的,我们可以将返回的结果显示在UI控件上

  为什么我们的AsyncTask抽象类只有一个 doInBackground 的抽象方法呢??原因是,我们如果要做一个异步任务,我们必须要为其开辟一个新的Thread,让其完成一些操作,而在完成这个异步任务时,我可能并不需要弹出要给ProgressDialog,我并不需要随时更新我的ProgressDialog的进度条,我也并不需要将结果更新给我们的UI界面,所以除了 doInBackground 方法之外的三个方法,都不是必须有的,因此我们必须要实现的方法是 doInBackground 方法。

3.AsyncTask机制的原理

  a.它本质上是一个静态的线程池,AsyncTask派生出的子类可以实现不同的异步任务,这些任务都是提交到静态的线程池中执行。

  b.线程池中的工作线程执行doInBackground(mParams)方法执行异步的任务。

  c.当任务状态改变后,工作线程向UI线程发送消息,AsyncTask内部的InternalHandler响应这些消息,并调用相关的回调函数。

4.AsyncTask注意事项:

  a.内存泄漏:

  静态内部类持有外部类的匿名引用,导致外部对象无法得到释放,解决方法很简单,让内部持有外部的弱引用即可解决

  b.生命周期
  在Activity的onDestory()中及时对AsyncTask进行回收,调用其cancel()方法来保证程序的稳定性。

  c.结果丢失
  当内存不足时,当前的Activity被回收,由于AsyncTask持有的是回收之前Activity的引用,导致AsyncTask更新的结果对象为一个无效的Activity的引用,这就是结果丢失。

  d.并行或串行
  在1.6(Donut)之前: 在第一版的AsyncTask,任务是串行调度。一个任务执行完成另一个才能执行。由于串行执行任务,使用多个AsyncTask可能会带来有些问题。所以这并不是一个很好的处理异步(尤其是需要将结果作用于UI试图)操作的方法。1.6-2.3: 所有的任务并发执行,这会导致一种情况,就是其中一条任务执行出问题了,会引起其他任务出现错误。3.0之后AsyncTask又修改为了顺序执行,并且新添加了一个函数 executeOnExecutor(Executor),如果您需要并行执行,则只需要调用该函数,并把参数设置为并行执行即可。

没有更多推荐了,返回首页