Android AsyncTasks并行执行

时间:2020-02-23 14:28:46  来源:igfitidea点击:

在本教程中,我们将通过讨论执行它的不同方式来深入研究android中的AsyncTasks。
我们还将看到通过异步任务处理配置更改的不同方法。
要了解AsyncTasks的基础知识,建议您阅读本教程。

Android AsyncTasks

AsyncTasks是一个帮助程序类,使我们可以运行可以与UI线程进行通讯的后台任务。

以下是AsyncTask类提供的主要方法:

  • onPreExecute
  • doInBackGround
  • onPostExecute
  • onProgressUpdate –为了调用此方法,请从doInBackground方法调用publishProgress方法。

声明AsyncTask的语法是:

private static class MyAsyncTask extends AsyncTask<A, B, C>

传递了三种类型的参数:

  • A –这些是可以在execute()方法中传递的参数类型。
    它们在doInBackground中使用。

  • B –在onProgressUpdate中可用

  • C –这是onPostExecute方法中存在的类型。

通常在实例上调用execute方法以启动AsyncTask。

AsyncTasks应该声明为静态。
否则,会发生泄漏,因为非静态类包含对Activity的直接引用,如果AsyncTask仍在运行时关闭了该Activity,则可以防止该Activity被垃圾回收。

AsyncTasks并行执行

直到Android Donut为止,当同时执行多个AsyncTask时,并行执行是不可能的。

从Android Donut并行执行多个异步任务,直到Android Honeycomb 3.0到来。

对于Android Honeycomb,将在单个线程上顺序执行多个AsyncTask,以防止发生IllegalStateExceptions。

为了从Android 3.0开始执行并行执行,我们需要在AsyncTask上调用方法executeOnExecutor(java.util.concurrent.Executor,Object [])

其中为执行器传递了THREAD_POOL_EXECUTOR。

注意:AsyncTask是使用Java的执行器服务构建的

并行执行多少个AsyncTask?

它取决于:核心池大小(CORE_POOL_SIZE)(线程池中的线程数)= CPU计数+ 1

最大池大小(MAXIMUM_POOL_SIZE)(线程池中的最大线程数)= CPU计数* 2 +1

因此,对于具有4核心处理器的智能手机,可以并行运行4 * 2 + 1 = 9 AsyncTasks。

AsyncTasks内存泄漏和方向更改

每当您在代码中定义AsyncTask时,IDE都会要求您将类设置为静态内部类,否则可能会发生内存泄漏。
为什么这样?

非静态内部类直接引用父类。
因此,如果AsyncTask的寿命长于Activity,则将阻止Activity收集垃圾。

因此,我们可以将AsyncTask定义为静态,或者其中保留对Activity的WeakReference。

静态对象的生命周期绑定到它所包含的类。

方向更改可能导致IllegalStateException,因为在AsyncTask在后台运行时,随附的活动配置会更改。
这可能导致内存泄漏。

因此,设置android:configChanges =" orientation"是处理AsyncTask和屏幕旋转的一种方法。
但这不是一个好习惯。

另一种可能的方法是在后台工作结束后,将方向锁定为onPreExecute中的当前方向,然后在onPostExecute中解锁。

理想的方法是将AsyncTask放入Fragment和setRetainInstance(true)中。

为了简单起见,由于在本教程中我们将重点放在并行执行上,因此我们将在下面的项目代码中的AndroidManifest.xml文件中设置configChanges。

代码

下面给出了activity_main.xml布局的代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  xmlns:tools="https://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:layout_margin="16dp"
  android:gravity="center"
  android:orientation="vertical"
  tools:context=".MainActivity">

  <ProgressBar
      android:id="@+id/progressBar1"
      style="?android:attr/progressBarStyleHorizontal"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:max="10" 

  <ProgressBar
      android:id="@+id/progressBar2"
      style="?android:attr/progressBarStyleHorizontal"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:max="10" 

  <Button
      android:id="@+id/btnSerialExecution"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="SERIAL EXECUTION" 

  <ProgressBar
      android:id="@+id/progressBar3"
      style="?android:attr/progressBarStyleHorizontal"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:max="10" 

  <ProgressBar
      android:id="@+id/progressBar4"
      style="?android:attr/progressBarStyleHorizontal"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:max="10" 

  <Button
      android:id="@+id/btnParallelExecution"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="PARELLEL EXECUTION" 

</LinearLayout>

我们创建了4个ProgressBar,其中2个将使用AsyncTask进度更新顺序填充,其余两个将并行执行。
让我们看看它的代码。

package com.theitroad.androidmultiasynctasks;

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;

import java.lang.ref.WeakReference;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

  Button btnParallelExecution, btnSerialExecution;
  ProgressBar progressBar1, progressBar2, progressBar3, progressBar4;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      initViews();
  }

  private void initViews() {
      btnSerialExecution = findViewById(R.id.btnSerialExecution);
      progressBar1 = findViewById(R.id.progressBar1);
      progressBar2 = findViewById(R.id.progressBar2);
      btnParallelExecution = findViewById(R.id.btnParallelExecution);
      progressBar3 = findViewById(R.id.progressBar3);
      progressBar4 = findViewById(R.id.progressBar4);

      btnSerialExecution.setOnClickListener(this);
      btnParallelExecution.setOnClickListener(this);

  }

  @Override
  public void onClick(View view) {

      switch (view.getId()) {
          case R.id.btnSerialExecution:

              MyObject myObject = new MyObject(progressBar1, 2);

              MyAsyncTask aTask1 = new MyAsyncTask();
              aTask1.execute(myObject);

              myObject = new MyObject(progressBar2, 3);

              MyAsyncTask aTask2 = new MyAsyncTask();
              aTask2.execute(myObject);
              break;

          case R.id.btnParallelExecution:

              myObject = new MyObject(progressBar3, 2);

              MyAsyncTask aTask3 = new MyAsyncTask();
              aTask3.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, myObject);

              myObject = new MyObject(progressBar4, 3);

              MyAsyncTask aTask4 = new MyAsyncTask();
              aTask4.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, myObject);
              break;
      }

  }

  private static class MyAsyncTask extends AsyncTask<MyObject, Integer, Void> {

      private WeakReference<MyObject> myObjectWeakReference;

      @Override
      protected Void doInBackground(MyObject... params) {
          this.myObjectWeakReference = new WeakReference<>(params[0]);
          for (int i = 0; i <= 10; i++) {
              publishProgress(i);

              try {
                  Thread.sleep(myObjectWeakReference.get().interval * 100);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
          return null;
      }

      @Override
      protected void onProgressUpdate(Integer... values) {
          super.onProgressUpdate(values);
          myObjectWeakReference.get().progressBar.setProgress(values[0]);
      }
  }

  private class MyObject {
      private ProgressBar progressBar;
      private int interval;

      MyObject(ProgressBar progressBar, int interval) {
          this.progressBar = progressBar;
          this.interval = interval;
      }
  }
}

我们创建了一个Model类,该类在AsyncTask参数中传递。
它包含ProgressBar实例以及线程将休眠的时间间隔。