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。

目录
相关文章
|
Android开发 开发者 Kotlin
告别AsyncTask:一招教你用Kotlin协程重构Android应用,流畅度飙升的秘密武器
【9月更文挑战第13天】随着Android应用复杂度的增加,有效管理异步任务成为关键。Kotlin协程提供了一种优雅的并发操作处理方式,使异步编程更简单直观。本文通过具体示例介绍如何使用Kotlin协程优化Android应用性能,包括网络数据加载和UI更新。首先需在`build.gradle`中添加coroutines依赖。接着,通过定义挂起函数执行网络请求,并在`ViewModel`中使用`viewModelScope`启动协程,结合`Dispatchers.Main`更新UI,避免内存泄漏。使用协程不仅简化代码,还提升了程序健壮性。
572 1
|
存储 Java 数据库连接
Android Java开发异步
【6月更文挑战第15天】
197 8
|
JSON Java API
【Android】使用 Retrofit2 发送异步网络请求的简单案例
**摘要:** Retrofit是Android和Java的HTTP客户端库,简化了RESTful API交互。它通过Java接口定义HTTP请求,并提供注解管理参数、HTTP方法等。要使用Retrofit,首先在AndroidManifest.xml中添加`INTERNET`权限,然后在`build.gradle`中引入Retrofit和Gson依赖。创建服务器响应数据类和描述接口的接口,如`Result`和`Api`。通过Retrofit.Builder配置基础URL并构建实例,之后调用接口方法创建Call对象并发送异步请求。
737 1
|
Android开发
40. 【Android教程】AsyncTask:异步任务
40. 【Android教程】AsyncTask:异步任务
606 2
|
数据库 Android开发
android AsyncTask
android AsyncTask
148 1
|
Java Android开发
Android 中的AsyncTask的使用心得
Android 中的AsyncTask的使用心得
152 1
|
Android开发 开发者
Android AsyncTask 的使用
Android AsyncTask 的使用
158 1
|
安全 API 数据库
【转】Android线程模型(AsyncTask的使用)
【转】Android线程模型(AsyncTask的使用)
160 1
|
Android开发
Android中的多线程及AsyncTask的引入,最终入职阿里
Android中的多线程及AsyncTask的引入,最终入职阿里
|
Java Android开发
android AsyncTask入门
android AsyncTask入门
142 0

热门文章

最新文章