40. 【Android教程】AsyncTask:异步任务

在前面的章节有提到过,Android 系统默认会在主线程(UI 线程)执行任务,但是如果有耗时程序就会阻塞 UI 线程,导致页面卡顿。这时候我们通常会将耗时任务放在独立的线程,然后通过 Handler 等线程间通信机制完成 UI 的刷新。很多时候我们也许只是想执行一个简单的任务,为此写一套 Handler 线程通信就会显得比较复杂,不用担心,Android 系统为我们提供了一个专门用于执行异步任务的工具——Async Task,它可以让我们执行后台任务并轻松的与 UI 线程进行状态同步,今天就一起来学习一下 AyncTask 的用法。

1. AsyncTask 简介

AsyncTask 类通常用来在执行后台任务的同时刷新 UI,通过调用execute()方法触发后台任务的执行,首先会回调 AsyncTask 的onPreExecute(),接着回调doInBackground()来执行自定义的后台任务,最后回调onPostExecute()方法用来刷新 UI,整体流程示意图如下:

2. AsyncTask 的基本用法

2.1 声明 AsyncTask

我们不能直接创建 AsyncTask,正确的方法是继承自 AsyncTask 实现一个它的子类,如下:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {protected Long doInBackground(URL... urls) {// 执行后台耗时任务return;}protected void onProgressUpdate(Integer... progress) {// 任务执行进度更新}protected void onPostExecute(Long result) {// 执行完毕,更新UI}}

以上是 AsyncTask 的核心回调方法,每个方法的含义会在后面具体讲到。

2.2 指定参数

AsyncTask 可以帮助你在子线程和主线程之间同步参数,根据不同的业务场景,参数类型和个数也会不一样。刚刚在 2.1 小节声明 AyncTask 子类的时候,需要传入 3 个泛型参数:

  • TypeOfVarArgParams:
    在任务启动之后,传入给后台任务的参数类型

  • ProgressValue:
    启动之后到任务结束之间,系统会不断回调此方法,用来更新任务的进度

  • ** ResultValue:**
    后台任务的执行结果

2.3 启动后台任务

在声明完后台任务之后,就可以直接启动了。启动方式比较简单,直接通过调用execute()方法启动后台任务:

new DownloadFilesTask().execute(url1, url2, url3);

3 AsyncTask 关键回调方法

AsyncTask 是由 4 个回调方法配合组成,这 4 个回调方法按照一定的顺序依次被调用,所以我们需要 focus 的是在正确的回调方法中实现我们想要的逻辑,下面详细看看如何使用。

  • onPreExecute():
    在执行execute()方法之后该方法立即被调用,标志着 AyncTask 正式开启。通常用来做一些需要在后台任务开启之前完成的初始化工作,比如展示一个进度条、或者弹出一个对话框等等。该方法在 UI 线程执行。
  • doInBackground(Params):
    在执行完onPreExecute()方法之后立即被调用,用来执行需要放在后台执行的耗时任务。在创建 AsyncTask 的时候传入的参数就是提供给doInBackground使用的。在后台任务执行完毕后,还需要将执行结果返回到onPostExecutes ()中,同时我们也可以通过publishProgress(Progress…)方法来手动发布任务进度,进度将从子线程发送到 UI 线程。毋庸置疑,该方法在子线程中执行。
  • onProgressUpdate(Progress…):
    当我们通过publishProgress(Params)发布进度之后,系统会回调该方法,用来获取任务执行进度并更新 UI。这一步就完成了子线程到主线程的通信,该方法在 UI 线程执行
  • onPostExecute(Result):
    当后台任务执行完毕,该方法被回调,同时标志着整个 AyncTask 结束。与onPreExecute相反,通常会在onPostExecute中做一些回收工作,比如提示“下载完成”、“加载失败”、隐藏进度条等等。

4 AsyncTask 示例

本节的功能和第 38 节 Handler 的功能类似,我们还是完成一个后台执行耗时任务,并同步更新进度条的功能,可以直接在 Handler 的例子上修改。

4.1 布局文件

布局文件基本一样,只是默认将进度条和进度显示隐藏起来,等到onPreExecute()方法的时候在做初始化展示,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><ProgressBarandroid:visibility="gone"android:id="@+id/progressBar"style="?android:attr/progressBarStyleHorizontal"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentStart="true"android:layout_alignParentTop="true" /><Buttonandroid:id="@+id/start_progress"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/progressBar"android:layout_alignParentStart="true"android:layout_marginStart="24dp"android:layout_marginTop="62dp"android:text="开始任务" /><TextViewandroid:visibility="gone"android:id="@+id/textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignTop="@+id/start_progress"android:layout_alignBottom="@+id/start_progress"android:layout_alignParentEnd="true"android:layout_marginEnd="85dp"android:gravity="center"android:text="当前进度:0%"android:textSize="16sp" /></RelativeLayout>

4.2 异步任务控制

异步任务的代码基本上和 Handler 一致,我们通过Thread.sleep(1000)来模拟一秒钟的耗时操作,然后在onPreExecute()中展示进度条,在后台任务执行完后通过publishProgress(int)来将任务进度发送到主线程,由onProgressUpdate(int)方法在 UI 线程接收进度,并更新进度条。最后在结束的时候返回“已完成”提示,在onPostExecute(String)方法中进行收尾工作,隐藏进度条并展示“已完成”。代码如下:

package com.emercy.myapplication;import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;public class MainActivity extends Activity {private static final int MAX = 100;private ProgressBar progressBar;private Button startProgress;private TextView textView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);progressBar = findViewById(R.id.progressBar);startProgress = findViewById(R.id.start_progress);textView = findViewById(R.id.textView);progressBar.setMax(MAX);startProgress.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {new DownloadTask().execute();}});}// 1、创建Async Task子类private class DownloadTask extends AsyncTask<Integer, Integer, String> {// 2、初始化阶段,展示进度条@Overrideprotected void onPreExecute() {progressBar.setVisibility(View.VISIBLE);textView.setVisibility(View.VISIBLE);}// 3、执行后台任务@Overrideprotected String doInBackground(Integer... integers) {int i;for (i = 0; i < 100; i++) {try {// 一秒钟的耗时操作Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 4、发布进度publishProgress(i);}return "异步任务已完成";}// 5、接收后台任务数据并更新进度条@Overrideprotected void onProgressUpdate(Integer... values) {textView.setText("当前进度:" + values[0] + "%");progressBar.setProgress(values[0]);}// 6、任务结束@Overrideprotected void onPostExecute(String s) {progressBar.setVisibility(View.GONE);textView.setText(s);}}
}

编译之后,效果如下:

可以看到大体的效果和 Handler 是一样的,但是整个异步任务的处理流程更加清晰了,而且可以很方便的做任务前的初始化任务后的回收工作,整个线程的切换也不再需要我们去控制,全部交给 AsyncTask 操作就行,一切就是这么简单!

5 小结

本节介绍了一个专门用于执行异步任务的工具类,首先需要创建一个子类继承自 AsyncTask,然后确定好需要传入和返回的参数类型,接着覆写 4 个关键的方法,剩下的线程切换及数据传输就交给系统完成了。
相比 Handler,AsyncTask使用更简单,我们只需要关注我们的后台逻辑,而 Handler 需要我们自行管理的东西比较多。所以在执行后台任务刷新 UI 的场景,强烈推荐使用 AsyncTask,可以让我们的开发更加顺畅。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/828010.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

外贸干货|客户迟迟不付款,怎么催?

(一) Gentle reminder 温馨提醒 "Hello Mary, l hope this message finds you well. l wanted to kindly remind you about the payment for our agreed-upon order. We appreciate your business and would like to proceed with the next steps as soon as possible.…

DS32K查看内置寄存器数值

需要在debug的时候进行查看&#xff0c;先暂停&#xff0c;再打开EmbSys Registers窗口。 需要先将导出的内容选中并双击&#xff0c;不然复制出来会变成问号。右上角有个复制按钮&#xff0c;复制到剪贴板就行。譬如我这里选择了MCR寄存器&#xff0c;复制出来的就是这个寄存器…

下载nvm来配置node版本

背景提示&#xff1a;入职的公司项目久远&#xff0c;一直运行不起来&#xff0c;原来是我node版本太高&#xff0c;需要降级才行。然后找到这个nvm配置一下 准备工作 如果电脑有配置node的&#xff0c;需要先卸载掉才能配置nvm&#xff01;&#xff01;&#xff01;这是重点嗷…

Leetcode双指针刷题(一)

给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面…

播放相关知识-持续更新

一&#xff1a;基础知识&#xff1a; 1.编码方式&#xff1a; H264&#xff1a; H265&#xff1a; AV1&#xff1a; 1.多码流&#xff0c;为什么现在视频播放有这么多的码流&#xff08;100、200、300、400、500、600、800、1020等等&#xff09; 优点&#xff1a;用户不同的…

大模型解决方案:具体业务场景下的智能表单填充(附代码)

大模型相关目录 大模型,包括部署微调prompt/Agent应用开发、知识库增强、数据库增强、知识图谱增强、自然语言处理、多模态等大模型应用开发内容 从0起步,扬帆起航。 大模型应用向开发路径:AI代理工作流大模型应用开发实用开源项目汇总大模型问答项目问答性能评估方法大模型…

在组件页面刷新为什么触发不了组件的生命周期销毁钩子

当在前端开发中遇到组件页面刷新时&#xff0c;无法触发组件生命周期的销毁钩子&#xff08;如 Vue 的 beforeDestroy/destroyed 或 React 的 componentWillUnmount&#xff09;&#xff0c;通常有以下几种情况或原因&#xff1a; 页面刷新的本质&#xff1a;当浏览器页面执行刷…

JS -正则表达式

正则表达式 关于正则表达式&#xff0c;其实我写过几篇了&#xff0c;但是真正的正则表达式其实主要用于定义一些字符串的规则&#xff0c;计算机根据给出的正则表达式&#xff0c;来检查一个字符串是否符合规则。 我们来看一下&#xff0c;在JS中如何创建正则表达式对象。 语…

网络不更新,LOSS正常输出。

据别的文章说&#xff0c;学习率过高或者adam算法没加入eps参数也可能导致模型输出nan. 这个可以一开始就加上试试。先判断loss是否正常&#xff0c;再使用判断梯度是否正常。出现NAN。 loss.backward()for name, parms in model.named_parameters():if parms.grad is None or…

第67天:APP攻防-Frida反证书抓包移动安全系统资产提取评估扫描

思维导图 案例一&#xff1a;内在-资产提取-AppinfoScanne AppinfoScanner 一款适用于以 HW 行动/红队/渗透测试团队为场景的移动端(Android、iOS、WEB、H5、静态网站)信息收集扫描工具&#xff0c;可以帮助渗透测试工程师、攻击队成员、红队成员快速收集到移动端或者静态 WEB …

【禅道客户案例】小反馈,大杠杆!银丰新融「反馈管理」优秀实践

企业介绍 北京银丰新融科技开发有限公司&#xff08;简称&#xff1a;银丰新融&#xff09;成立于2000 年&#xff0c;自创立以来一贯专注于金融监管、风险管控等领域的信息系统建设&#xff0c;拥有目前国内金融风险领域规模庞大的信息技术服务团队。 银丰新融业务范围覆盖了…

VUE3 ref,props,生命周期

1.--ref属性 1.1代码 1.1.1子表 <template><div class"person"><h1>中国</h1><h2 ref"title2">北京</h2><h3>尚硅谷</h3><button click"showLog">点我输出h2这个元素</button>&l…

JavaScript注释:单行注释和多行注释详解

为了提高代码的可读性&#xff0c;JS与CSS一样&#xff0c;也提供了注释功能。JS中的注释主要有两种&#xff0c;分别是单行注释和多行注释。 在编程的世界里&#xff0c;注释是那些默默无闻的英雄&#xff0c;它们静静地站在代码的背后&#xff0c;为后来的维护者、为未来的自…

到底什么是爬虫

1. 引言 在数据驱动的世界里&#xff0c;网络爬虫&#xff08;Web Crawling&#xff09;技术扮演着获取和处理网上数据的关键角色。无论是为了数据分析、机器学习项目的数据集构建还是简单地监测网页变化&#xff0c;学习如何创建一个基本的网页爬虫可以大大提升你的工作效率和…

Vue页面生成导出PDF文件

第一种&#xff1a; 使用浏览器自带打印方法window.print(); 也可使用print-js插件&#xff08;原理相同&#xff09; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>printDemo</title> </…

【Vue】常见的七大属性(描述+案例)

一、前言 最近&#xff0c;因为项目需要自己就去学习了一下Vue的相关知识&#xff0c;自己花了几天&#xff0c;结合官方文档和相应的视频学习了一下Vue,了解了Vue大概的一些属性&#xff0c;方法&#xff0c;特点等。接下来博主会将自己学习的相关内容通过博客的形式进行记录…

flutter类的细节

title: flutter类的细节(hexo发表blog的初尝试) abbrlink: 9bcefa22 date: 2024-04-22 00:26:25 tags: description: flutter里抽象类的解释 cover: “http://anime-haven.net/lainceleyesdh.jpg” {% p center logo large, Flutter近日学习所遇到的问题 %} {% p center h3, 是…

python教程(5更新中)

常用内建模块 Python之所以自称“batteries included”&#xff0c;就是因为内置了许多非常有用的模块&#xff0c;无需额外安装和配置&#xff0c;即可直接使用。 本章将介绍一些常用的内建模块。 datetime datetime是Python处理日期和时间的标准库。 获取当前日期和时间 …

Linux蓝牙驱动模拟HID设备(把Linux系统模拟成蓝牙鼠标和蓝牙键盘)

by fanxiushu 2024-04-24 转载或引用请注明原始作者。 在经过windows的蓝牙驱动开发模拟成HID设备的大风大浪之后&#xff0c; 现在回到linux下实现相同功能&#xff0c;简直就是如小孩嬉闹一样的轻松。 但无论如何&#xff0c;作为模拟蓝牙HID设备的windows&#xff0c;linux一…

【学习】​CSMM和CMMI的关系你了解吗

CMMI和CSMM都是评估和提升软件组织能力成熟度的模型&#xff0c;但它们在起源、应用范围、模型结构和实施目的等方面存在一些区别。在当今竞争激烈的软件市场中&#xff0c;提升软件能力成为了多数组织追求成功的关键因素。而选择适合的体系标准能够助力企业发展得更加迅速。作…