展开说说:Android实现多线程解析

embedded/2024/9/23 6:36:16/

上一篇分析了开启多线程处理耗时任务的一些方法,但是就Android开发而言很多时候并不会直接使用Thread和Runnable,而是用AsyncTask、IntentService或者HandlerThread来实现在主线程开启新的子线程进行耗时任务并且等任务结束还能回到主线程更新UI。下面具体分析一下:

1、AsyncTask

AsyncTask是Google官方提供的一个轻量级的异步任务框架,即可以在主线程使用它发起耗时任务还可以在它的回调方法中返回任务执行进度和最终结果方便的更新UI界面。

这个类提供了三个泛型参数<Params, Progress, Result>,分别是执行任务所需的参数类型、任务执行进度的类型以及任务执行结果的返回类型。如果不需要具体参数就用Void代替,一个不需要一个Void都不需要就三个Void。

重要方法:

doInBackground

这个方法是在子线程执行的,在这里您可以做耗时操作。它的形参对应的是上面提到的第一个泛型参数Params。

这个方法从被回调的时序关系来说他不是最早的,但是我们把它放到第一个来分析是有以下几点原因:

第一:几个常用方法中他是唯一一个在子线程执行的,咱用AsyncTask为了啥不就是为了做点耗时任务嘛,所以他很重要

第二:从代码本身来看doInBackground是个抽象方法,是子类唯一必须要实现的方法,其他都不是抽象方法 是单纯重写父类方法,写不写看需求

第三:需要主动调用publishProgress方法传递进度值,否则后面的另一个重要方法onProgressUpdate不会被调用

第四:需要在return中返回计算结果给后面的另一个重要方法onPostExecute

onPreExecute

这个方法是在主线程执行的,他在doInBackground之前调用,因此用来做一些异步任务执行前的准备工作。所以从时序上来说他是四个方法中最早执行的。

onProgressUpdate

这个方法是在主线程执行的,当异步任务执行进度改变时被调用,此处可以用来更新进度条。

onPostExecute

这个方法是在主线程执行的,当异步任务执行结束时被调用,此处可以处理执行结果更新UI。

下面是一个demo,因为没有做实际的耗时任务因此我在doInBackground方法手动加了一个10秒的延时

/*** AsyncTAsk* 范型分别代表的是params请求参数、progress进度条、result返回结果*///todo 范型参数可以在调用excute方法时传入的,也可以通过构造方法public class AsyncTaskService extends AsyncTask<String,Integer,Object> {
private static final String TAG = AsyncTaskService.class.getSimpleName();private Activity activity;private ContentResolver contentResolver;public AsyncTaskService (Activity activity){this.activity = activity;}@Overrideprotected void onPreExecute() {super.onPreExecute();Log.e(TAG, "onPreExecute: " );if (contentResolver == null && activity != null){contentResolver = activity.getContentResolver();}}//在后台的线程,可以执行耗时操作//todo doInBackground是个抽象方法必须实现的,其他都不是抽象方法 是单纯重写父类方法@Overrideprotected Object doInBackground(String... voids) {Log.e(TAG, "doInBackground: "+voids[0]);String[] projection = {MediaStore.Images.Thumbnails._ID, MediaStore.Images.Thumbnails.DATA};//耗时查询系统相册 缩略图和非缩略图
//        contentResolver.query()//模仿进度条,必须主动调用否则onProgressUpdate不会执行publishProgress(0);try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}publishProgress(1);return voids[0]+"加盐";}@Overrideprotected void onProgressUpdate(Integer... values) {super.onProgressUpdate(values);Log.e(TAG, "onProgressUpdate: "+values[0] );}@Overrideprotected void onPostExecute(Object o) {super.onPostExecute(o);Log.e(TAG, "onPostExecute: o= " + o.toString() );}@Overrideprotected void onCancelled(Object o) {super.onCancelled(o);Log.e(TAG, "onCancelled: o="+ o.toString());}}

运行日志:

2024-03-04 16:00:08.102 10433-10433/com.example.testdemo3 E/AsyncTaskService: onPreExecute:2024-03-04 16:00:08.104 10433-10522/com.example.testdemo3 E/AsyncTaskService: doInBackground: AsyncTask传餐2024-03-04 16:00:08.104 10433-10433/com.example.testdemo3 E/AsyncTaskService: onProgressUpdate: 02024-03-04 16:00:18.145 10433-10433/com.example.testdemo3 E/AsyncTaskService: onProgressUpdate: 12024-03-04 16:00:18.146 10433-10433/com.example.testdemo3 E/AsyncTaskService: onPostExecute:

通过日志可以看出AsyncTask执行异步任务的逻辑是先执行onPreExecute方法让我们做一些准备工作,然后doInBackground方法被回调做耗时任务,需要主动调用publishProgress方法,然后onProgressUpdate被回调,doInBackground中伪造了十秒延时后再次主动调用publishProgress方法onProgressUpdate再次被回调,最后任务执行结束以后onPostExecute被回调返回执行结果。

注意:

AsyncTask对象必须在主线程创建,并且开启任务的execute方法也必须在主线程执行。还有啊,一个AsyncTask对象只能调用一次execute方法。

2、IntentService

IntentService是四大组件之一Service的子类专门解决它不能执行耗时任务处理异步请求,

3、HandlerThread

HandlerThread其实相对小众且陌生的一个类, HandlerThread继承Thread类,本质上就是一个普通Thread只不过内部建立了Looper,简化了像下面这种子线程与子线程之间的通信。同样用来处理子线程和主线程之间相互交互的场景。


http://www.ppmy.cn/embedded/34133.html

相关文章

TCP(TCP客户端、服务器如何通信)

一、TCP介绍 TCP的特点&#xff1a; 面向连接的协议&#xff1a;TCP是一种可靠的、面向连接的协议&#xff0c;在通信之前需要建立连接&#xff0c;以确保数据的可靠传输。这意味着在传输数据之前&#xff0c;发送方和接收方之间需要建立一条可靠的连接通道。流式协议&#x…

【DPU系列之】如何通过带外口登录到DPU上的ARM服务器?(Bluefield2举例)

文章目录 1. 背景说明2. 详细操作步骤2.1 目标拓扑结构2.2 连接DPU带外口网线&#xff0c;并获取IP地址2.3 ssh登录到DPU 3. 进一步看看系统的一些信息3.1 CPU信息&#xff1a;8核A723.2 内存信息 16GB3.3 查看ibdev设备 3.4 使用小工具pcie2netdev查看信息3.5 查看PCIe设备信息…

使用 docker-compose 编排 lnmp(dockerfile) 完成 wordpress

一、使用 docker-compose 编排 lnmp(dockerfile) 完成 wordpress 环境准备 ##修改主机名 hostnamectl set-hostname lyh bash [rootlyh ~]###关闭防火墙及核心防护 systemctl stop firewalld ##关闭核心防护 setenforce 0 ##关闭核心防护##安装Docker-20…

前端之深拷贝

前提&#xff1a; 就是在实际开发中&#xff0c;我有一个编辑的弹窗&#xff0c;可以查看和编辑&#xff0c;因为弹窗里面是一个步骤条&#xff0c;点击下一步就要向对应的接口发送请求&#xff0c;考虑到就比如我点击下一步&#xff0c;此次表箱信息其实不需要修改&#xff0…

抓包证书安装到安卓7.0+手机

前言: 首先理解一下,这个不只是证书到浏览器,而是抓包证书到安卓7.0+手机上的文章; 还有一点区分,在浏览器上装的证书,只是让抓包工具可以抓取手机浏览器的包,而不是抓取手机app上的包; 如果你的证书只是简单的在浏览器下进行安装,那么你的手机app是走不了代理网络的…

探索CSS3文本效果:打造魅力无限的网页排版

CSS3为网页设计带来了革命性的变化&#xff0c;特别是在文本效果方面&#xff0c;它赋予了开发者前所未有的创意空间。本文将带你深入了解CSS3中一些令人兴奋的文本效果&#xff0c;从基本的阴影处理到复杂的动画效果&#xff0c;每个技巧都将通过实际代码示例展现其魅力所在。…

Linux——命名管道

管道特点 只能用于具有具体祖先的进程之间的通信&#xff0c;通常&#xff0c;一个管道由一个进程创建&#xff0c;然后该进程调用fork&#xff0c;创建子进程&#xff0c;关闭相应的读写端&#xff0c;然后父子进程就可以通信了管道提供流式服务一般而言&#xff0c;进程退出…

UDP通信

文章目录 recvfrom和sendto函数UDP通信server和client流程UDP实现的并发服务器和客户端 recvfrom和sendto函数 ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);sockfd&#xff1a; 套接字buf&#xff1a;缓冲…