Android线程
1、引言
在Android中,几乎完全采用了Java的线程机制,由于Android的特性,主线程只处理和界面相关的事情,子线程处理耗时操作。Android中扮演线程角色的有Thread、AsyncTask、IntentService和HandlerThread。对于AsyncTask来说,底层用到了线程池,对于IntentService和HandlerThread,底层用到了线程。
2、AsyncTask
AsyncTask是一个抽象的泛型类,它提供了Params、Progress和Result这三个泛型参数。
public abstract class AsyncTask<Params, Progress, Result>
其中Params表示参数类型,Progress表示后台任务的执行进度的类型,Result表示后台任务返回结果的类型。并且提供了五个核心的方法。
@MainThread
protected void onPreExecute() {
}
此方法有个@MainThread注解,表示在主线程执行,在异步任务执行之前,此方法会被调用,一般可以做一些准备工作。
@WorkerThread
protected abstract Result doInBackground(Params... params);
此方法有个@WorkerThread注解,表示在工作(子)线程执行,用于执行异步任务,params参数表示异步任务的输入参数,可调用publishProgress方法来更新任务进度,publishProgress会调用onProgressUpdate方法。并且此方法需要返回计算结果给onPostExecute方法。
@MainThread
protected void onPostExecute(Result result) {
}
在主线程中执行,在异步任务执行后,此方法会被调用,result是后台任务的返回值。
@MainThread
protected void onProgressUpdate(Progress... values) {
}
在主线程中执行,后台任务的执行进度发生变化时,此方法会被调用。
@MainThread
protected void onCancelled(Result result) {
onCancelled();
}
在主线程中执行,当异步任务被取消是,此方法会被调用,而onPostExecute则不会被调用。
class MyTask extends AsyncTask<String, Integer, String> {
@Override
protected void onPreExecute() {
Log.i(TAG, "onPreExecute() called");
textView.setText("loading...");
}
@Override
protected String doInBackground(String... strings) {
Log.i(TAG, "doInBackground(Params... params) called");
try {
OkHttpClient client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS).build();
Request request = new Request.Builder()
.url(strings[0])
.get()
.build();
Call call = client.newCall(request);
Response response = call.execute();
if (response.code() == 200) {
InputStream is = response.body().byteStream();
long total = response.body().contentLength();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int count = 0;
int length = 0;
while ((length = is.read(buf)) != -1) {
baos.write(buf, 0, length);
count += length;
//调用publishProgress公布进度,最后onProgressUpdate方法将被执行
publishProgress((int) (count * 1.0f / total * 100));
//为了演示进度,休眠500毫秒
Thread.sleep(500);
}
return new String(baos.toByteArray(), "utf8");
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
return null;
}
//onProgressUpdate方法用于更新进度信息
@Override
protected void onProgressUpdate(Integer... progresses) {
Log.i(TAG, "onProgressUpdate(Progress... progresses) called");
progressBar.setProgress(progresses[0]);
textView.setText("loading..." + progresses[0] + "%");
}
//onPostExecute方法用于在执行完后台任务后更新UI,显示结果
@Override
protected void onPostExecute(String result) {
Log.i(TAG, "onPostExecute(Result result) called");
textView.setText(result);
execute.setEnabled(true);
cancel.setEnabled(false);
}
//onCancelled方法用于在取消执行中的任务时更改UI
@Override
protected void onCancelled() {
Log.i(TAG, "onCancelled() called");
textView.setText("cancelled");
progressBar.setProgress(0);
execute.setEnabled(true);
cancel.setEnabled(false);
}
}
上面代码中,实现一个具体的AsyncTask类,主要模拟get请求,并且更新progress。
AsyncTask使用限制
- 类必须在主线程中加载
- 对象必须在主线程中创建
- execute方法必须在UI线程调用
- 不要在程序中直接调用onPreExecute、onPostExecute、doInBackground、onProgressUpdate方法
- 一个AsyncTask对象只能执行一次,多次执行会报运行时异常。
3、HandlerThread
HandlerThread本质上是一个线程类,它继承了Thread,并且可以创建一个带有looper的线程,进行looper循环;looper对象可以用于创建Handler类来进行来进行调度,必须调用start()方法,Thread会先调用run方法来创建Looper对象。源码如下:
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
创建HandlerThread很简单,它有两个构造函数,第一个构造函数只需要传递线程名称即可,第二构造函数除了线程名称,还需要设置优先级的功能
HandlerThread thread = new HandlerThread("downImage");
thread.start();
HandlerThread thread = new HandlerThread("downImage", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
需要注意的是,HandlerThread的run是一个无限循环,因此明确不需要它时,需要调用quit和quitSafely方法来终止线程的执行。
4、IntentService
IntentService继承了Service,并且它是一个抽象类,因此必须创建它的子类才能使用IntentService。它用于执行后台耗时的任务,执行完会自动停止。它拥有较高的优先级,不易被系统杀死(继承自Service的缘故),因此比较适合执行一些高优先级的异步任务。
IntentService其实还是由HandlerThread和Handler实现的。
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
onCreate中创建了一个HandlerThread ,在通过HandlerThread创建了一个Handler。startService后,最终会调用onStart方法。
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
从上面可以看出,mServiceHandler 发送的消息最终都会在HandlerThread 执行,会将Intent的对象传递给onHandleIntent抽象方法(需要子类实现)处理。onHandleIntent处理完之后会调用stopSelf(int startId)方法尝试停止服务,而不是stopSelf()来立即停止服务。下面创建一个示例看看它是怎样实现的。
public class DownLoadService extends IntentService {
public DownLoadService(String name) {
super(name);
}
@Override
protected void onHandleIntent(@androidx.annotation.Nullable @Nullable Intent intent) {
String url = intent.getStringExtra("url");
Bitmap bitmap = dowload(url);
// 保存逻辑处理
}
}
启动跟Service一样
Intent intent = new Intent(this, DownLoadService.class);
startService(intent);
Android线程的更多相关文章
- Android线程管理之ThreadLocal理解及应用场景
前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...
- Android线程管理之Thread使用总结
前言 最近在一直准备总结一下Android上的线程管理,今天先来总结一下Thread使用. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Executo ...
- Android线程管理之ExecutorService线程池
前言: 上篇学习了线程Thread的使用,今天来学习一下线程池ExecutorService. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Execu ...
- Android线程管理之ThreadPoolExecutor自定义线程池
前言: 上篇主要介绍了使用线程池的好处以及ExecutorService接口,然后学习了通过Executors工厂类生成满足不同需求的简单线程池,但是有时候我们需要相对复杂的线程池的时候就需要我们自己 ...
- Android线程管理之AsyncTask异步任务
前言: 前面几篇文章主要学习了线程以及线程池的创建与使用,今天来学习一下AsyncTask异步任务,学习下AsyncTask到底解决了什么问题?然而它有什么弊端?正所谓知己知彼百战百胜嘛! 线程管理相 ...
- Android线程之主线程向子线程发送消息
和大家一起探讨Android线程已经有些日子了,谈的最多的就是如何把子线程中的数据发送给主线程进行处理,进行UI界面的更新,为什么要这样,请查阅之前的随笔.本篇我们就来讨论一下关于主线程向子线程如何发 ...
- Android线程管理(三)——Thread类的内部原理、休眠及唤醒
线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...
- Android线程管理(二)——ActivityThread
线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...
- android 线程学习
很多人觉得线程难理解,主要有两个问题: 线程休眠,既然线程已经休眠了,程序的运行速度还能提高吗? 线程体一般都进行死循环,既然线程死循环,程序就应该死掉了,就会没有反应. 1.关于线程休眠问题 对线程 ...
- Android 线程模型
Android 线程模型 1. import android.os.Handler; import android.os.Message; public class MainActivity ext ...
随机推荐
- WeexSDK源码分析(iOS)
0.从工作原理谈起 Weex 表面上是一个客户端技术,但实际上它串联起了从本地开发.云端部署到分发的整个链路.开发者首先可在本地像编写 web 页面一样编写一个 app 的界面,然后通过命令行工具将之 ...
- [Unity插件]DOTween基础
官方文档链接:http://dotween.demigiant.com/documentation.PHP#globalSettings 普通版下载地址:http://dotween.demigian ...
- Media Queries 媒体查询常见设备断点
按需调整断点 一.谷歌后摘抄的一部分媒体查询 /*#region SmartPhones */ /* SmartPhones */@media only screen and (min-device- ...
- Java RMI 概观
RMI是Java的一组拥护开发分布式应用程序的API. RMI使用Java语言接口定义了远程对象,它集合了Java序列化和Java远程方法协议(Java Remote Method Protocol) ...
- spring cloud+.net core搭建微服务架构:配置中心(四)
前言 我们项目中有很多需要配置的地方,最常见的就是各种服务URL地址,这些地址针对不同的运行环境还不一样,不管和打包还是部署都麻烦,需要非常的小心.一般配置都是存储到配置文件里面,不管多小的配置变动, ...
- mysql 开发进阶篇系列 35 工具篇 mysqldump(数据导出工具)
一.概述 mysqldump客户端工具是用来备份数据库或在不同数据库之间进行数据迁移.备份内容包含创建表或装载表的sql语句.mysqldump目前是mysql中最常用的备份工具. 三种方式来调用my ...
- salesforce lightning零基础学习(五) 事件阶段(component events phase)
上一篇介绍了lightning component events的简单介绍.此篇针对上一篇进行深入,主要讲的内容为component event中的阶段(Phase). 一. 阶段(Phase)的概念 ...
- (原创)UML要点总结
今天我们总结要点: 我们就从这张图慢慢讲. 一.类图部分 基础: 类图→长方形表示.类名在最上栏,下面是数据,第三栏是方法.其存在两种关系:关联和泛化 属性: 全形: 可见性 名:类型 重 ...
- 从零开始学 Web 之 CSS3(三)渐变,background属性
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...
- 高性能、高可用性Socket通讯库介绍 - 采用完成端口、历时多年调优!(附文件传输程序)
前言 本人从事编程开发十余年,因为工作关系,很早就接触socket通讯编程.常言道:人在压力下,才可能出非凡的成果.我从事的几个项目都涉及到通讯,为我研究通讯提供了平台,也带来了动力.处理socket ...