异步之AsyncTask(一)
发布日期:2021-10-20 03:26:56 浏览次数:14 分类:技术文章

本文共 5437 字,大约阅读时间需要 18 分钟。

531570-d078e6008e549fd0.png
插图.png

导读

在Android中每一个应用都拥有自己的独立进程,而一个进程可以拥有多个线程,在这些线程中有一个线程叫做MainThread(也叫UIThread).它负责显示、更新UI,与用户交互.

其他的线程叫做WorkerThread(也叫工作线程),由于在主线程中做耗时的操作会阻塞主线程,影响UI更新,会让用户感觉到应用卡顿,所以我们需要把耗时的操作放到工作线程当中去,例如:网络请求,IO操作,数据库读写.

另外工作线程是不允许操作UI的,如果你想在工作线程中操作UI,那么你将会得到如下错误:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

那么当我们想在做完耗时的操作后更新UI怎么办?比如我去网络下载图片,下载完成后显示到UI上,可能机智的你已经知道了Thread+Handler的方式,但是每次都要定义那么多东西,太麻烦了!这时候AsyncTask应运而生!

1.AsyncTask的基本介绍

而AsyncTask是Android对Thread+Handler的一个二次封装(由于内部封装了Handler,致使AsyncTask只能在主线程创建),在需要既要使用到WorkerThread又要与UI交互的时候,AsyncTask就能发挥出它最大的作用,给你带来非常大的便利.本系列将会讲解在AsyncTask在Android的使用方法,注意点,技巧等.

AsyncTask<Params,Progress,Result>是一个抽象类,通常需要继承它来使用.

  • Params 启动时接受的参数类型,在doingbackground中返回
  • Progress 进行中的返回的进度的类型,
  • Result 结束后返回的结果的类型

2.AsyncTask的方法:

  • doInBackground(Params)异步执行任务时调用,并且接受参数,与Thread的run方法类似,与其他方法不同的是, 这个方法必须要重写.
  • onPreExecute 在任务开始之前调用,通常可以用来做初始化参数,或者判断网络是否连接.
  • onProgressUpdate 在doInBackground中调用publishProgress()触发.
  • onPostExecute doInBackground方法执行完成之后会调用,并接受Result.
  • onCancelled(Result) 任务被取消时候调用
  • onCancelled 同上

一般情况下AsyncTask的执行顺序是

onPreExecute->doInBackground->onProgressUpdate->onPostExecute

3.实战,使用AsyncTask下载网络图片

1.布局,这里布局很简单,一个ImageView,一个ProgressBar

2.再在Activity里定义一个ImageLoadTask

private class ImageLoadTask extends AsyncTask
{ @Override protected void onPreExecute() { super.onPreExecute(); //加载前显示进度条 mPb.setVisibility(View.VISIBLE); } @Override protected Bitmap doInBackground(String... params) { //接受参数 String url = params[0]; try { //使用httpurlconnection去下载图片 HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); InputStream is = connection.getInputStream(); Bitmap bitmap = BitmapFactory.decodeStream(is); //人为 模拟进度 for (int i = 0; i < 100; i++) { publishProgress(i); Thread.sleep(100); } return bitmap; } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } publishProgress(); return null; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); //更新进度 mPb.setProgress(values[0]); } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); if(null!=bitmap){ mIvAsync.setImageBitmap(bitmap); } mPb.setVisibility(View.GONE); } @Override protected void onCancelled(Bitmap bitmap) { super.onCancelled(bitmap); } @Override protected void onCancelled() { super.onCancelled(); } }

3.因为需要使用网络,所以要在AndroidManifest.xml里增加权限:

4.使用ImageLoadTask下载图片:

//execte中传入图片的url作为参数        new ImageLoadTask().execute("http://c.hiphotos.baidu.com/zhidao/pic/item/b812c8fcc3cec3fdc622032cd688d43f8794274e.jpg");

5.运行效果如下:

531570-e6d3f78d14bbbfe4.gif
运行效果图

另外我们需要知道的是,AsyncTask的并发数量有限,一般情况下需要等上一个AsyncTask执行完毕之后才能执行下一个:

531570-a495260b0d37693d.gif
效果图
可以看到,第一次进入的AsyncTask没有执行完毕,当我们第二次进去之后,第二个AsyncTask并没有立即执行,而是等第一个task执行完毕后才执行.

那么问题来了,当我退出界面之后,该界面的AsyncTask还在执行,而这样影响其他界面的Task执行了,怎么办?

4.取消AsyncTask

AsyncTask.cancel(mayInterruptIfRunning);

参数mayInterruptIfRunning: true if the thread executing this task should be interrupted; otherwise, in-progress tasks are allowed to complete.(传true表示task应该被中断,false代表进行中的task被允许执行完毕)

但是需要注意的是,调用cancel方法并不能真正立即把task取消掉,而只是把task的状态置为Cancel而已,需要配合isCancelled()方法来运用,在doingbackground或其他方法中判断是否被取消,然后做相应的处理.

那么我们将代码修改一下:

1.修改onDestroy()方法

@Override    protected void onDestroy() {        super.onDestroy();        //task不为空,并且它处于运行状态,那么我们将调用cancel方法        if (null != task && task.getStatus() == AsyncTask.Status.RUNNING) {            task.cancel(true);        }    }

2.修改doingbackground方法:

@Override        protected Bitmap doInBackground(String... params) {            String url = params[0];            try {                HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();                InputStream is = connection.getInputStream();                Bitmap bitmap = BitmapFactory.decodeStream(is);                //人为 模拟进度                for (int i = 0; i < 100; i++) {                    //增加是否取消的判断,如果取消,直接break掉                    if (isCancelled()){                        break;                    }                    publishProgress(i);                    Thread.sleep(100);                }                return bitmap;            } catch (IOException e) {                e.printStackTrace();            } catch (InterruptedException e) {                e.printStackTrace();            }            publishProgress();            return null;        }

修改之后的效果图如下:

531570-6b42b84dc16410df.gif
final

可以看到,当我们第二次进入之后,不需要再等第一个task执行完才去执行.

5.总结

  1. AsyncTask只能在主线程创建
  2. AsyncTask中只有doingbackground方法是异步的
  3. 一个AsyncTask不能被execute两次
  4. AsyncTask调用cancel后走的是onCanceled而不是onPostExecute,并且cancel并不能真正立即取消task,如果想要立即取消还需要isCancelled()方法来辅助.
    5.默认并发执行的AsyncTask只有一个,即下一个task需要在上一个task执行完毕后才会执行(从Android的某个版本开始,具体哪个忘记了,忘知道的留言指导)
  5. AsyncTask的方法都是系统调用的,不要手动调用

6.谢谢

若有错误,还望指点,如有没说到的地方,欢迎留言.若觉得对你有帮助,不妨点下喜欢.谢谢

扩展阅读:

与我联系,交个朋友

转载地址:https://blog.csdn.net/u014400934/article/details/103160968 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android相机使用技巧(一)
下一篇:在代码中修改Shape的solid属性的color值

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年03月10日 01时18分07秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

mysql有3个共同好友_共同好友mysql 2019-04-21
代理查询 mysql_查询数据库代理设置 2019-04-21
mysql dif_mysqldiff实现MySQL数据表比较 2019-04-21
mysql 允许其他主机访问权限_允许其他主机访问本机MySQL 2019-04-21
druid不能close mysql连接_alibaba druid mysql连接问题 2019-04-21
mysql 设置按天分表_MySQL 优化实战记录 2019-04-21
java连接mysql 不推荐_java连接mysql 2019-04-21
mysql数据库 quota_shell脚本抓取用户存储quota写道mysql并展现到grafana面板 2019-04-21
idea测试连接mysql报错08001_IDEA连接MySQL错误 2019-04-21
layui导入模板数据_layui表格-template模板的三种用法 2019-04-21
mysql分组显示行号_mysql 显示行号,以及分组排序 2019-04-21
MySQL常见的主从复制架构_如何搭建经典的MySQL 主从复制架构 2019-04-21
编写python程序、计算账户余额_小明有20w存款存在余额宝中,按余额宝年收益为3.35%计算,用Python编写程序计算,多少年后小明的存款达到30w?... 2019-04-21
python 公众号引流_公众号引流方法有哪些? 2019-04-21
java 减少内存_java中减少内存占用小技巧 2019-04-21
centos 7 mysql图形界面_centos7-vnstat图形界面搭建 2019-04-21
java 防渗透_「java、工程师工作经验怎么写」-看准网 2019-04-21
java中跳出当前循环怎么做_在java中,如何跳出当前的多重循环? 2019-04-21
java程序中执行maven_java – 将一个enviornment变量传递给Maven中的已执行进程 2019-04-21
java16下载_java lombok下载 2019-04-21