一手遮天 Android - 异步和多线程: AsyncTask 的使用

项目地址 https://github.com/webabcd/AndroidDemo
作者 webabcd

一手遮天 Android - 异步和多线程: AsyncTask 的使用

示例如下:

/async/AsyncTaskDemo1.java

/**
 * AsyncTask 的使用
 *
 * AsyncTask - 异步任务(用于简化“UI 线程启动一个后台线程,后台线程向 UI 线程通知进度并汇报结果”的场景)
 *     execute() - 执行
 *     cancel() - 取消
 *     getStatus() - 状态
 *         PENDING - AsyncTask 在调用 execute() 之前是 PENDING 状态
 *         RUNNING - AsyncTask 在调用 execute() 之后是 RUNNING 状态
 *         FINISHED - AsyncTask 在执行完成之后是 FINISHED 状态(注:在回调 onPostExecute() 或 onCancelled() 中仍然是 RUNNING 状态)
 *
 *     onPreExecute() - 任务执行前(UI 线程)
 *     doInBackground() - 执行任务(后台线程),接收“输入数据”,通知“进度通知”,返回“执行结果”
 *     onProgressUpdate() - 接收“进度通知”(UI 线程)
 *     onPostExecute() - 接收“执行结果”(UI 线程),如果调用了 AsyncTask 的 cancel() 则不会执行到这里
 *     onCancelled(boolean mayInterruptIfRunning) - 任务被取消(调用 AsyncTask 的 cancel() 后,等待后台线程执行完后才会回调)
 *         mayInterruptIfRunning 为 false 的方式:将 AsyncTask 的 isCancelled 状态置为 true,等任务执行完毕后回调 onCancelled() 方法(后台线程执行完后才会回调)
 *         mayInterruptIfRunning 为 true 的方式:将 AsyncTask 的 isCancelled 状态置为 true,调用线程的 interrupt() 方法,等任务执行完毕后回调 onCancelled() 方法(后台线程执行完后才会回调)
 *
 *
 * 注:
 * 1、只能在 UI 线程上实例化 AsyncTask 并调用其 execute() 方法
 * 2、该 cancel 的时候一定要 cancel(比如执行 AsyncTask 的 Activity 关闭的时候,记住一定要 cancel 掉 AsyncTask)
 * 3、取消线程时,如果线程中有 io 阻塞的话,先要把这个 io 干掉
 */

package com.webabcd.androiddemo.async;

import android.os.AsyncTask;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.webabcd.androiddemo.R;

public class AsyncTaskDemo1 extends AppCompatActivity {

    private Button _buttonExecute;
    private Button _buttonCancel1;
    private Button _buttonCancel2;
    private TextView _textView1;
    private TextView _textView2;
    private ProgressBar _progressBar1;
    private ProgressBar _progressBar2;

    private MyTask _myTask;

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

        _buttonExecute = (Button) findViewById(R.id.buttonExecute);
        _buttonCancel1 = (Button) findViewById(R.id.buttonCancel1);
        _buttonCancel2 = (Button) findViewById(R.id.buttonCancel2);
        _textView1 = (TextView) findViewById(R.id.textView1);
        _textView2 = (TextView) findViewById(R.id.textView2);
        _progressBar1 = (ProgressBar) findViewById(R.id.progressBar1);
        _progressBar2 = (ProgressBar) findViewById(R.id.progressBar2);

        sample();
    }

    private void sample() {
        _buttonExecute.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                // 实例化 AsyncTask(必须在 UI 线程)
                _myTask = new MyTask();

                // 执行 AsyncTask(必须在 UI 线程),同一个 AsyncTask 对象只能调用一次 execute()
                _myTask.execute("myTask arg1", "myTask arg2"); // 这个参数为“输入数据”,其数据类型是在 AsyncTask 的泛型参数中定义的
            }
        });

        _buttonCancel1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 取消任务(mayInterruptIfRunning 为 false 的方式),将 AsyncTask 的 isCancelled 状态置为 true,等任务执行完毕后回调 onCancelled() 方法(后台线程执行完后才会回调)
                _myTask.cancel(false);
            }
        });

        _buttonCancel2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 取消任务(mayInterruptIfRunning 为 true 的方式),将 AsyncTask 的 isCancelled 状态置为 true,调用线程的 interrupt() 方法,等任务执行完毕后回调 onCancelled() 方法(后台线程执行完后才会回调)
                _myTask.cancel(true);
            }
        });
    }

    /**
     * 继承 AsyncTask 并实现相关逻辑
     * AsyncTask 有 3 个泛型参数,分别是“输入数据”,“进度通知”,“执行结果”,按需要指定其数据类型即可,如果不需要则用 java.lang.Void
     */
    private class MyTask extends AsyncTask<String, Integer, String> {

        // onPreExecute() - 任务执行前(UI 线程)
        @Override
        protected void onPreExecute() {
            _textView1.setText("异步任务准备执行");
        }

        // doInBackground() - 执行任务(后台线程),接收“输入数据”,通知“进度通知”,返回“执行结果”
        @Override
        protected String doInBackground(String... params) {
            // 接收“输入数据”
            writeMessage(String.format("异步任务开始执行:%s, %s", params[0], params[1]));

            try {
                int i = 0;
                int j = 0;
                while (i < 100 || j < 100) {
                    Thread.sleep(10);

                    // 判断是否调用了 AsyncTask 的 cancel() 方法,如果被 cancel 了则需要像这样手动写退出线程的逻辑
                    if (isCancelled()) {
                        break;
                    }

                    i++;
                    if (i == 100) {
                        j += 10;
                        if (j == 100) {
                            break;
                        } else {
                            i = 0;
                        }
                    }

                    // 通知“进度通知”
                    publishProgress(i, j);
                }
            } catch (InterruptedException e) {
                writeMessage(e.toString());
            }

            // 返回“执行结果”
            return "ok";
        }

        // onProgressUpdate() - 接收“进度通知”(UI 线程)
        @Override
        protected void onProgressUpdate(Integer... progresses) {
            _progressBar1.setProgress(progresses[0]);
            _progressBar2.setProgress(progresses[1]);
            _textView1.setText(String.format("子任务进度:%d%%,总任务进度:%d%%", progresses[0], progresses[1]));
        }

        // onPostExecute() - 接收“执行结果”(UI 线程),如果调用了 AsyncTask 的 cancel() 则不会执行到这里
        @Override
        protected void onPostExecute(String result) {
            _textView1.setText("异步任务执行完毕: " + result);
            _progressBar1.setProgress(100);
            _progressBar2.setProgress(100);
        }

        // onCancelled() - 任务被取消(调用 AsyncTask 的 cancel() 后,等待后台线程执行完后才会回调)
        @Override
        protected void onCancelled() {
            _textView1.setText("异步任务已经取消");
            _progressBar1.setProgress(0);
            _progressBar2.setProgress(0);
        }
    }

    private void writeMessage(final String message) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                _textView2.append(String.format("%s\n", message));
            }
        });
    }
}

/layout/activity_async_asynctaskdemo1.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ProgressBar
        android:id="@+id/progressBar1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:progress="0"
        android:max="100"
        style="?android:attr/progressBarStyleHorizontal" />

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

    <TextView
        android:id="@+id/textView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/buttonExecute"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="执行异步任务" />

    <Button
        android:id="@+id/buttonCancel1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="取消(mayInterruptIfRunning 为 false 的方式)" />

    <Button
        android:id="@+id/buttonCancel2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="取消(mayInterruptIfRunning 为 true 的方式)" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

项目地址 https://github.com/webabcd/AndroidDemo
作者 webabcd

posted @ 2021-06-02 09:44  webabcd  阅读(93)  评论(0编辑  收藏  举报