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

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

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

   
    xmlns:tools="http://schemas.android.com/tools"
    
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context="study.me.imooc.AsyncTask.AsyncTaskActivity">

android:id="@+id/iv_async"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_world" />

android:id="@+id/pb"
style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
/>

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值

发表评论

最新留言

很好
[***.36.148.9]2022年06月18日 13时19分10秒

关于作者

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

最新文章

给你一个数组 nums ,数组中有 2n 个元素,按 [x1,x2,...,xn,y1,y2,...,yn] 的格式排列。 请你将数组按 [x1,y1,x2,y2,...,xn,yn] 格式重新排 2019-08-03 02:38:27
给你两个整数,n 和 start 。数组 nums 定义为:nums[i] = start + 2*i(下标从 0 开始)且 n == nums.length 。 2019-08-03 02:38:26
MyISAM 和 InnoDB 锁总结 2019-08-03 02:38:26
给你一个长度为 n 的整数数组 nums,其中 n大于1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。 2019-08-03 02:38:25
【每日一练】给你一个数组 candies 和一个整数 extraCandies ,其中 candies[i] 代表第 i 个孩子拥有的糖果数目。 2019-08-03 02:38:25
【每日一练】你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 2019-08-03 02:38:24
给定两个列表 Aand B,并且 B 是 A 的变位(即 B 是由 A 中的元素随机排列后组成的新列表)。 2019-08-03 02:38:24
给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 2019-08-03 02:38:23
【Java面试题】调用yield()、sleep()、notify()、wait()等方法对锁有何影响? 2019-08-03 02:38:23
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。 2019-08-03 02:38:22
synchronized 不是万能,错误加锁 2019-08-03 02:38:22
给定一个二叉树,判断它是否是高度平衡的二叉树。 2019-08-03 02:38:21
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。 2019-08-03 02:38:21
Thread 和 Runnable 区别? 2019-08-03 02:38:20
Mybatis 2019-08-03 02:38:20
在二维平面上,有一个机器人从原点 (0, 0) 开始。给出它的移动顺序,判断这个机器人在完成移动后是否在 (0, 0) 处结束。 2019-08-03 02:38:19
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。 2019-08-03 02:38:19
给出 N 名运动员的成绩,找出他们的相对名次并授予前三名对应的奖牌。前三名运动员将会被分别授予 “金牌”,“银牌” 和“ 铜牌” 2019-08-03 02:38:19
给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。 2019-08-03 02:38:18
验证回文串 2019-08-03 02:38:18