【达内课程】线程中的AsyncTask

AsyncTask介绍

【同步和异步】
同步:就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。也就是必须一件一件事做,等前一件做完了才能做下一件事。
异步:当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。

【Android 为什么要引入异步任务】
我们之前学过了,Android UI 操作并不是线程安全的,并且这些操作都需要在UI线程中执行。 如果我们把耗时的操作都放在 UI 线程中的话,会发生 ANR 异常。假如我们在非 UI 线程中,比如在主线程中 new Thread() 另外开辟一个线程,然后直接在里面修改 UI 控件的值,此时会抛出下述异常: android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views

我们在之前的文章中学了下述两种方法进行UI更新:
1、在 Handler 里写好 UI 更新,然后通过 sendMessage() 等的方法通知 UI 更新。
2、利用 Activity.runOnUiThread(Runnable) 把更新ui的代码创建在 Runnable 中,更新 UI 时,把Runnable 对象传进来即可

除了以上两种方法,Android 给我们提供了一个轻量级的用于处理异步任务的类:AsyncTask,我们一般是继承 AsyncTask,然后在类中实现异步操作,然后将异步执行的进度,反馈给 UI 主线程。使用 AsyncTask 可以更集中的管理某个任务的代码。

实际异步用的最多的地方就是网络操作,图片加载,数据传输等,AsyncTask 暂时可以满足初学者的需求,当然实际上我们使用更多的是第三发的框架,比如 Volley、OkHttp、android-async-http、XUtils等

【AsyncTask中的泛型】
Pramas参数的数据泛型,即执行任务之前,是否需要参数做位前提条件,如果不需要,可以使用 void 类型进行标识,如果需要,参数应该是哪种数据类型

Progress进度的数据类型,即执行任务过程中,是否需要提交进度,如果需要,应该使用哪种数据类型描述进度

Result结果的数据类型,即执行任务完成之后,是否需要使用某种数据标识任务的操作结果,如果需要,则一共是哪种数据类型

【AsyncTask 中的方法】
doInBackground()默认运行在子线程的方法,可以直接执行耗时操作,该方法的参数是 Params 类型的可变参数,返回值是 Result 类型

publishProgress()用于提交进度的方法,注意:该方法是用于调用的方法,而不是重写的方法

onProgressUpdate()更新进度的方法,该方法默认是运行在主线程的,所以可以直接更新 UI,每次调用publishProgress()都会导致本方法被回调,且本方法的参数是publishProgress()方法的参数

onPostExecute()处理结果的方法,该方法默认是运行在主线程,且该方法会在 doInBackground()方法执行完毕之后自动回调 1 次,该方法的参数是 doInBackground()方法的返回值

【执行AsyncTask】
创建任务的对象,调用execute()方法即可

【取消AsyncTask】
调用任务对象的 cancel(true) 即可取消任务

取消任务并不会使得子线程的任务直接终止,子线程中的任务依然执行完成,只是主线程的响应(包括 onProgressUpdate()onPostExecute())将不被执行

【Async的特点】
若干个 AsyncTask 任务即使同时调用 execute()准备执行,也会按照顺序一次执行,即若干个 AsyncTask 任务表现为 "串行"的

注意:只要是使用 AsyncTask 实现的任务,都是串行的,即假设存在 Task1、Task2 都继承自 AsyncTask,且各自创建对象分别执行,这些任务也都会是串行的

用AsyncTask做一个进度条的栗子

用 AsyncTask 做一个和之前效果一样的进度条程序:传送门

xml 代码相同,不赘述

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private ProgressBar progressBar;
    private Button button;
    private TextView textView;

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

        progressBar = findViewById(R.id.progressBar);
        button = findViewById(R.id.button);
        textView = findViewById(R.id.tv_show_progress);
        button.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        InnerSyncTask task = new InnerSyncTask();
        task.execute();
    }

    private class InnerSyncTask extends AsyncTask<String, Integer, Bitmap> {

        @Override
        protected Bitmap doInBackground(String... strings) {
            Log.d("Async", "[Thread ID:" + Thread.currentThread() + "] InnerClassSyncTask->doInBackground");
            for (int i = 0; i <= 100; i++) {
                //提交进度
                publishProgress(i);
                Log.d("Async", "[Thread ID:" + Thread.currentThread() + "] InnerClassSyncTask->publishProgress"+i);

                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            Log.d("Async", "[Thread ID:" + Thread.currentThread() + "] onProgressUpdate");
            progressBar.setProgress(values[0]);
            textView.setText(values[0] + "/100");
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            Log.d("Async", "[Thread ID:" + Thread.currentThread() + "] onPostExecute");
        }
    }
}

运行程序,查看日志

D/Async: [Thread ID:Thread[AsyncTask #1,5,main]] InnerClassSyncTask->doInBackground
D/Async: [Thread ID:Thread[AsyncTask #1,5,main]] InnerClassSyncTask->publishProgress0
D/Async: [Thread ID:Thread[main,5,main]] onProgressUpdate
D/Async: [Thread ID:Thread[AsyncTask #1,5,main]] InnerClassSyncTask->publishProgress1
D/Async: [Thread ID:Thread[main,5,main]] onProgressUpdate
......
D/Async: [Thread ID:Thread[AsyncTask #1,5,main]] InnerClassSyncTask->publishProgress98
D/Async: [Thread ID:Thread[AsyncTask #1,5,main]] InnerClassSyncTask->publishProgress99
D/Async: [Thread ID:Thread[main,5,main]] onProgressUpdate
D/Async: [Thread ID:Thread[AsyncTask #1,5,main]] InnerClassSyncTask->publishProgress100
D/Async: [Thread ID:Thread[main,5,main]] onProgressUpdate
D/Async: [Thread ID:Thread[main,5,main]] onPostExecute

取消AsyncTask

在刚才的案例中增加一个按钮,增加点击事件,取消 AsyncTask

public class AsyncActivity extends AppCompatActivity implements View.OnClickListener {

    ......
    private Button buttonCancel;
    private InnerSyncTask task;

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

        ......
        buttonCancel = findViewById(R.id.buttonCancel);
        buttonCancel.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.button:
                task = new InnerSyncTask();
                task.execute();
                break;
            case R.id.buttonCancel:
                task.cancel(true);
                break;
        }
    }
	......
}

在这里插入图片描述
我们打印日志可以发现子线程依然在执行,只是主线程的响应没被执行

......
D/Async: [Thread ID:Thread[AsyncTask #1,5,main]] InnerClassSyncTask->publishProgress100
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值