Android异步之旅:探索AsyncTask

简介: Android异步之旅:探索AsyncTask

前言:

在Android应用程序开发中,异步操作是非常常见的需求。比如,我们可能需要在后台线程中执行网络请求、数据库操作或者其他耗时的任务,而不阻塞UI线程。为了实现这些异步操作,Android提供了多种方式,其中之一就是使用AsyncTask类。

1.什么是AsyncTask?


    AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程并在主线程中更新UI。(两个线程池+Handler

2.介绍AsyncTask类的泛型参数和核心方法


AsyncTask是一个抽象的泛型类,它提供了ParamsProgressResult这三个泛型参数。

public abstract class AsyncTask<Params, Progress, Result>

其中,

  • 🟨Params表示参数的类型
  • 🟨Progress表示后台任务的执行进度和类型
  • 🟨Result表示后台任务的返回结果

AsyncTask类提供了四个核心方法(按照执行顺序介绍):

1️⃣onPreExecute():主线程中执行,用于准备工作

2️⃣doInBackground(Params...params):在线程池中执行,用于执行异步任务。在此方法中可以通过publishProgress方法来更新任务的进度,publishProgress方法调用onProgressUpdate方法。

3️⃣onProgressUpdate(Progress...values):在主线程中执行,当后台任务的执行进程发送变化时此方法会被调用。

4️⃣onPostExecute(Result result):在主线程中执行,在异步任务执行之后,此方法会被调用。

AsyncTask还提供了onCancelled()方法,它同样在主线程中执行,当异步任务被取消时,onCancelled会被调用,这个时候,onPostExecute则不会被调用。

3.如何使用AsyncTask?


使用AsyncTask的步骤:

🔶步骤一:继承AsyncTask类,并实现它的几个回调方法,比如doInBackground()方法用来执行后台任务,onPostExecute()方法用来更新UI。

🔶步骤二:在UI线程中创建AsyncTask的实例,并调用execute()方法来启动异步操作。

示例:

在Activity中,创建一个子类来继承AsyncTask,完成以下任务:

1.展示ProgressDialog

2.发送网络请求

3.关闭ProgressDialog

代码如下:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       new AsyncTask_test().execute("");
    }
    public static ProgressDialog dialog;
    public class AsyncTask_test extends AsyncTask<String,Integer,Long> {
        @Override
        protected void onPreExecute() {
            dialog=ProgressDialog.show(MainActivity.this,"", "努力加载中");
        }
        @Override
        protected Long doInBackground(String... strings) {
            OkHttpClient okHttpClient = new OkHttpClient();
            Request request=new Request.Builder()
                    .url("https://www.httpbin.org/get?a=1&b=2")
                    .build();
            Response response= null;
            try {
                response = okHttpClient.newCall(request).execute();
                if(!response.isSuccessful()){
                    Log.e("xxx","网络请求失败"+response);
                }
                String responsedata=response.body().string();
                if(responsedata!=null){
                    Log.e("xxx","输出:"+responsedata);
                }
            } catch (IOException e) {
                Log.e("xxx","报错"+e);
                throw new RuntimeException(e);
            }
            return null;
        }
        @Override
        protected void onPostExecute(Long aLong) {
            if(dialog!=null){
                dialog.dismiss();
            }
            super.onPostExecute(aLong);
        }
    }
}

AsyncTask在使用时的注意事项:

🟠AsyncTask的对象必须在主线程中创建。(原因:AsyncTask的handler对象是静态的,Handler对象要切换到主线程,由于静态成员在类加载时就被初始化,因此AsyncTask必须在主线程中加载)

🟠execute方法必须在UI线程调用

🟠不要在线程中直接调用onPreExecute()、onPostExecute、doInBackground和onProgressUpdate方法。

🟠一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常。

4.AsyncTask的工作原理


工作原理:

➡️当asyncTask执行execute()方法的时候,会先调用onPreExecute()方法。

➡️然后调用SERIAL_EXECUTOR的execute(mFuture),把任务加入到队列的尾部等待执行。

➡️执行的时候调用THREAD_POOL_EXECUTOR的execute(mFuture)方法。

➡️mFuture调用mWorker的call()方法,在call()方法中调用了dolnBackground()方法,并在最后调用了postResult()方法。

➡️postResult()方法也就是通过Handler发送消息给主线程,在主线程中调用AsyncTask的finish()方法,来决定是调用onCancelled()还是onPostExecute()方法。

源码解析:

@MainThread

public final AsyncTask<Params, Progress, Result> execute(Params... params) {

   return executeOnExecutor(sDefaultExecutor, params);

}

 @MainThread

   public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,

           Params... params) {

       if (mStatus != Status.PENDING) {

           switch (mStatus) {

               case RUNNING:

                   throw new IllegalStateException("Cannot execute task:"

                           + " the task is already running.");

               case FINISHED:

                   throw new IllegalStateException("Cannot execute task:"

                           + " the task has already been executed "

                           + "(a task can be executed only once)");

           }

       }


       mStatus = Status.RUNNING;


       onPreExecute();


       mWorker.mParams = params;

       exec.execute(mFuture);


       return this;

   }

其中,sDefaultExecutor是一个串行的线程池,一个进程中所有的AsyncTask全部在这个串行的线程池中排队执行。在executeOnExecutor方法中,AsyncTask的onPreExecute方法最先执行,然后线程池开始执行,下面是线程池的执行过程:

   public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

   private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

   private static class SerialExecutor implements Executor {

       final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();

       Runnable mActive;


       public synchronized void execute(final Runnable r) {

           mTasks.offer(new Runnable() {

               public void run() {

                   try {

                       r.run();

                   } finally {

                       scheduleNext();

                   }

               }

           });

           if (mActive == null) {

               scheduleNext();

           }

       }


       protected synchronized void scheduleNext() {

           if ((mActive = mTasks.poll()) != null) {

               THREAD_POOL_EXECUTOR.execute(mActive);

           }

       }

   }

当一个AsyncTask任务执行完后,AsyncTask会调用scheduleNext()方法继续执行下一个任务直到所有任务被执行为止,总的来说,默认情况下,AsyncTask是串行执行的。

AsyncTask中有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handle:

SerialExecutor:用于任务的排队

THREAD_POOL_EXECUTOR:用于真正地执行任务

Handler:用于将执行环境从线程池切换到主线程

在AsyncTask的构造方法中有如下一段代码,由于FutureTask的run方法会调用mWorker的call方法,因此mWorker的call方法最终会在线程池中执行。

 public AsyncTask(@Nullable Looper callbackLooper) {

       mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()

           ? getMainHandler()

           : new Handler(callbackLooper);


       mWorker = new WorkerRunnable<Params, Result>() {

           public Result call() throws Exception {

               mTaskInvoked.set(true);

               Result result = null;

               try {

                   Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

                   //noinspection unchecked

                   result = doInBackground(mParams);

                   Binder.flushPendingCommands();

               } catch (Throwable tr) {

                   mCancelled.set(true);

                   throw tr;

               } finally {

                   postResult(result);

               }

               return result;

           }

       };


       mFuture = new FutureTask<Result>(mWorker) {

           @Override

           protected void done() {

               try {

                   postResultIfNotInvoked(get());

               } catch (InterruptedException e) {

                   android.util.Log.w(LOG_TAG, e);

               } catch (ExecutionException e) {

                   throw new RuntimeException("An error occurred while executing doInBackground()",

                           e.getCause());

               } catch (CancellationException e) {

                   postResultIfNotInvoked(null);

               }

           }

       };

   }


在mWorker的call方法中,首先将mTaskInvoked设为true,表示当前任务已经被调用过了,然后执行AsyncTask的doInBackground方法,接着将返回值传递给postResult方法,它的实现如下:

private Result postResult(Result result) {

   @SuppressWarnings("unchecked")

   Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,

           new AsyncTaskResult<Result>(this, result));

   message.sendToTarget();

   return result;

}

在上面代码中,postResult方法会通过Handler对象发送一个MESSAGE_POST_RESULT的消息,这个Handler对象的定义如下:

getHandler()获取Handler对象

private Handler getHandler() {

   return mHandler;

}

赋值mHandler

private final Handler mHandler;

public AsyncTask(@Nullable Looper callbackLooper) {

   mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()

       ? getMainHandler()

       : new Handler(callbackLooper);

    ...

}

(1)如果callbackLooper == null,就getMainHandler()

private static Handler getMainHandler() {

   synchronized (AsyncTask.class) {

       if (sHandler == null) {

           sHandler = new InternalHandler(Looper.getMainLooper());

       }

       return sHandler;

   }

}

(2)如果callbackLooper == Looper.getMainLooper(),就new Handler(callbackLooper)

public Handler(@NonNull Looper looper) {

   this(looper, null, false);

}

Handler对象收到MESSAGE_POST_RESULT这个消息后会调用AsyncTask的finish方法。

private void finish(Result result) {

   if (isCancelled()) {

       onCancelled(result);

   } else {

       onPostExecute(result);

   }

   mStatus = Status.FINISHED;

}

如果AsyncTask被取消执行了,那么就调用onCancelled方法,否则就会调用onPostExecute方法,就可以看到doInBackground的返回结果会传递给onPostExecute方法,到这里AsyncTask的整个工作过程就分析完毕了。


总结

通过本篇博客,我们了解了AsyncTask的工作原理和如何在Android应用程序中使用它来进行异步操作。AsyncTask提供了一种简单而强大的方式来管理异步任务,并在UI线程中更新UI,是Android开发中不可或缺的工具之一。希望本篇博客能帮助你更好地理解和使用AsyncTask。

目录
相关文章
|
1天前
|
Java Android开发
Android 中的AsyncTask的使用心得
Android 中的AsyncTask的使用心得
|
2天前
|
Android开发 开发者
Android AsyncTask 的使用
Android AsyncTask 的使用
|
2天前
|
安全 API 数据库
【转】Android线程模型(AsyncTask的使用)
【转】Android线程模型(AsyncTask的使用)
|
2天前
|
Java Android开发
android AsyncTask入门
android AsyncTask入门
|
25天前
|
Android开发 开发者
Android网络和数据交互: 请解释Android中的AsyncTask的作用。
Android&#39;s AsyncTask simplifies asynchronous tasks for brief background work, bridging UI and worker threads. It involves execute() for starting tasks, doInBackground() for background execution, publishProgress() for progress updates, and onPostExecute() for returning results to the main thread.
11 0
|
2月前
|
Android开发 开发者
Android异步之旅:探索IntentService
Android异步之旅:探索IntentService
20 0
|
2月前
|
消息中间件 数据库 Android开发
Android异步之旅:探索HandlerThread
Android异步之旅:探索HandlerThread
27 0
|
2月前
|
Android开发 对象存储
OSS对象储存android开发进行下载到本地文件时异步操作失效
android vivo80使用官方示例代码进行文件下载,但是使用oss.asyncGetObject(get, new OSSCompletedCallback<GetObjectRequest, GetObjectResult>()时onSuccess和onFailure不执行
|
9月前
|
安全 Java Android开发
Android 中AsyncTask后台线程,异步任务的理解
Android 中AsyncTask后台线程,异步任务的理解
103 0
|
5月前
|
XML Java 调度
Android App网络通信中通过runOnUiThread快速操纵界面以及利用线程池Executor调度异步任务实战(附源码 简单易懂)
Android App网络通信中通过runOnUiThread快速操纵界面以及利用线程池Executor调度异步任务实战(附源码 简单易懂)
31 0