Android AsyncTasks并行执行
在本教程中,我们将通过讨论执行它的不同方式来深入研究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实例以及线程将休眠的时间间隔。