Android 多线程编程:IntentService & HandlerThread

Android——Handler+Service,实现后台长期周期性定时任务编程 通过利用Handler和Service,我们可以实现在Android应用中后台长期周期性定时任务的功能。在Service中结合Handler的使用,我们可以轻松地实现定时任务的延迟执行和周期性执行。通过结合Handler和Service,我们可以实现后台的长期周期性定时任务。在Android开发中,我们经常会遇到需要在后台执行长期周期性定时任务的需求,比如定时更新数据、发送消息等。至此,我们已完成了使用Handler+Service实现后台长期周期性定时任务的代码编写。二、Service介绍。 阅读详情

Android 多线程开发的演变

因为 Android 是使用 Java 开发的,所以当我们谈及 Android 中的多线程,必然绕不过 Java 中的多线程编程。但在这篇文章中,我们不会过多地分析 Java 中的多线程编程的知识。我们会在以后分析 Java 并发编程的时候分析 Java 中的多线程、线程池和并发 API 的用法。

我们先来总结一下 Android 多线程编程的演变过程:

首先是 Java 的 Thread。因为本身在创建一个线程和销毁一个线程的时候会有一定的开销,当我们任务的执行时间相比于这个开销很小的时候,单独创建一个线程就显得不划算。所以,当程序中存在大量的、小的任务的时候,建议使用线程池来进行管理。

但我们一般也很少主动去创建线程池,这是因为——也许是考虑到开发者自己去维护一个线程池比较复杂—— Android 中已经为我们设计了 AsyncTask。AsyncTask 内部封装了一个线程池,我们可以使用它来执行耗时比较短的任务。但 AsyncTask 也有一些缺点:

  1. 如果你的程序中存在很多的不同的任务的时候,你可能要为每个任务定义一个 AsyncTask 的子类。
  2. 从异步线程切换到主线程的方式不如 RxJava 简洁。

所以,在实际开发的过程中,我通常使用 RxJava 来实现异步的编程。尤其是局部的优化、不值得专门定义一个 AsyncTask 类的时候,RxJava 用起来更加舒服。

上面的多线程创建的只是普通的线程,对系统来说,优先级比较低。在 Android 中还提供了 IntentService 来执行优先级相对较高的任务。启动一个 IntentService 任务的时候会将任务添加到其内部的、异步的消息队列中执行。此外,IntentService 又继承自 Service,所以这让它具有异步和较高的优先级两个优势。

在之前的文章中,我们已经分析过 AsyncTask、RxJava 以及用来实现线程切换的 Handler. 这里奉上这些文章的链接:

  1. 《Android AsyncTask 源码分析》
  2. 《RxJava2 系列-1:一篇的比较全面的 RxJava2 方法总结》
  3. 《RxJava2 系列-2:背压和Flowable》
  4. 《RxJava2 系列-3:使用 Subject》

在这里我们要分析 IntentService 和 HandlerThread,它们都会使用到 Android 中的 Handler 机制,你可以通过下面的文章来进行了解:

《Android 消息机制:Handler、MessageQueue 和 Looper》

1、异步消息队列:HandlerThread

如果你之前还没有了解过 Handler 的实现的话,那么最好通过我们上面的那篇文章 《Android 消息机制:Handler、MessageQueue 和 Looper》 了解一下。因为 HandlerThread 就是通过封装一个 Looper 来实现的。

1.1 HandlerThread 的使用

HandlerThread 继承自线程类 Thread,内部又维护了一个 Looper,Looper 内又维护了一个消息队列。所以,我们可以使用 HandlerThread 来创建一个异步的线程,然后不断向该线程发送任务。这些任务会被封装成消息放进 HandlerThread 的消息队列中被执行。所以,我们可以用 HandlerThread 来创建异步的消息队列。

在使用 HandlerThread 的时候有两个需要注意的地方:

  1. 因为 HandlerThread 内部的 Looper 的初始化和开启循环的过程都在 run() 方法中执行,所以,在使用 HandlerThread 之前,你必须调用它的 start() 方法。
  2. 因为 HandlerThread 的 run() 方法使用 Looper 开启一个了无限循环,所以,当不再使用它的时候,应该调用它的 quitSafely() 或 quit() 方法来结束该循环。

在使用 HandlerThread 的时候只需要创建一个它的实例,然后使用它的 Looper 来创建 Handler 实例,并通过该 Handler 发送消息来将任务添加到队列中。下面是一个使用示例:

myHandlerThread = new HandlerThread("MyHandlerThread");
myHandlerThread.start();
handler = new Handler( myHandlerThread.getLooper() ){
    @Override
    public void handleMessage(Message msg) {
        // ... do something
    }
};
handler.sendEmptyMessage(1);

这里我们创建了 HandlerThread 实例之后用它来创建 Handler 然后通过 Handler 把任务加入到消息队列中进行执行。

显然,使用 HandlerThread 可以很轻松地实现一个消息队列。你只需要在创建了 Handler 之后向它发送消息,然后所有的任务将被加入到队列中执行。当然,它也有缺点。因为所有的任务将会被按顺序执行,所以一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。

1.2 HandlerThread 源码解析

下面是该 API 的源码,实现也比较简单,我们直接通过注释来对主要部分进行说明:

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    protected void onLooperPrepared() { }

    // 在这个方法开启了 Looper 循环,因为是一个无限循环,所以不适用的时候应该将其停止
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    
    // 获取该 HandlerThread 对应的 Looper
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) { }
            }
        }
        return mLooper;
    }

    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    // ... 无关代码
}

上面的代码比较简单明了,在 run() 方法中初始化 Looper 并执行。如果 Looper 还没有被创建,那么当调用 getLooper() 方法获取 Looper 的时候会让线程阻塞。当 Looper 创建完毕之后会唤醒所有阻塞的线程继续执行。另外,就是两个停止 Looper 的方法。它们基本上就是对 Looper 进行了一层封装。

2、IntentService

2.1 使用 IntentService

IntentService 继承自 Serivce,因此它比普通的多线程任务优先级要高。这使得它相比于普通的异步任务不容易被系统 kill 掉。它内部也是通过一个 Looper 来实现的,所以也是一种消息队列。在研究它的源码之前,我们先来看一下它的使用。

IntentService 的使用是比较简单的,只需要:1).继承它并实现其中的 onHandleIntent() 方法;2). 将 IntentService 注册到 manifest 中;3). 像开启一个普通的服务那样开启一个 IntentService 即可。下面是该类的一个使用示例:

public class FileRecognizeTask extends IntentService {

    public static void start(Context context) {
        Intent intent = new Intent(context, FileRecognizeTask.class);
        context.startService(intent);
    }
    
    public FileRecognizeTask() {
        super("FileRecognizeTask");
    }

    @Override
    protected void onHandleIntent(@androidx.annotation.Nullable @Nullable Intent intent) {
        // 你的需要异步执行的业务逻辑
    }
}

OK,介绍完了 IntentService 的使用,我们再来分析一下它的源码。

2.2 IntentService 源码分析

实现 IntentService 的时候使用到了我们上面分析过的 HandlerThread. 首先,在 onCreate() 回调方法中创建了一个 HandlerThread,然后使用它的 Looper 创建了一个 ServiceHandler:

HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);

ServiceHandler 是 IntentSerice 的内部类,其定义如下:

private final class ServiceHandler extends Handler {

    public ServiceHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        onHandleIntent((Intent)msg.obj);
        stopSelf(msg.arg1);
    }
}

ServiceHandler 用来执行被添加到队列中的消息。它会回调 IntentService 中的 onHandleIntent() 方法,也就是我们实现业务逻辑的方法。当消息执行完毕之后,会调用 Service 的 stopSelf(int) 方法来尝试停止服务。注意这里调用的是 stopSelf(int) 而不是 stopSelf()。它们之间的区别是,当还存在没有完成的任务的时候 stopSelf(int) 不会立即停止服务,而 stopSelf() 方法会立即停止服务。

IntentSerivce 的 onCreate() 方法会在第一次启动的时候被调用,来创建服务。而 onStartCommond() 方法会在每次启动的时候被调用。下面是该方法的定义。

@Override
public void onStart(@Nullable Intent intent, int startId) {
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}

@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
    onStart(intent, startId);
    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

onStartCommand() 内部调用了 onStart() 来处理请求。在 onStart() 方法中会通过 mServiceHandler 创建一个消息,并将该消息发送给 mServiceHandler. 该消息会在被 mServiceHandler 放进消息队列中排队,并在合适的时机被执行。

因此,我们可以总结一下 IntentService 的工作过程:首先,当我们第一次启动 IntentService 的时候会初始化一个 Looper 和 Handler;然后调用它的 onStartCommond() 方法,把请求包装成消息之后发送到消息队列中等待执行;当消息被 Handler 处理的时候会回调 IntentService 的 onHandleIntent() 方法来执行。此时,如果又有一个任务需要执行,那么 IntentService 的 onStartCommond() 方法会再次被执行并把请求封装之后放入队列中。当队列中的所有的消息都执行完毕,并且没有新加入的请求,那么此时服务就会自动停止,否则服务还会继续在后台执行。

这里,同样也应该注意下,IntentService 中的任务是按照被添加的顺序来执行的。

总结

以上就是我们对 IntentService 和 HandlerThread 的分析。它们都是使用了 Handler 来实现,所以搞懂它们的前提是搞懂 Handler。关于 Handler,还是推荐一下笔者的另一篇文章 《Android 消息机制:Handler、MessageQueue 和 Looper》。


我是 WngShhng. 如果您喜欢我的文章,可以在以下平台关注我:

Android线程,线程池,AsyncTask,HandlerThread和IntentService的用法 Android线程,线程池,AsyncTask,HandlerThread和IntentService的用法demo 立即下载

相关推荐

通达信双紫擒龙指标实战指南:从源码解析到精准安装

本文详细解析了通达信双紫擒龙指标的核心逻辑、源码获取与安全验证、安装流程及实战应用技巧。通过紫紫红黄四种颜色信号捕捉趋势转折点,结合MACD、布林通道和成交量加权算法,提升交易准确性。文章还提供了个性化设置、信号解读及常见问题解决方案,帮助投资者高效运用该指标。

weixin_29248611的博客 1044

Android核心组件之Service

1、什么是Service      Service的官网解释是:Service是一个在后台执行较长时间操作且不提供用户界面接口的应用程序组件。其它的应用程序组件能开启一个Service,Service将在后台运行甚至用户切换到其它应用时也有效。另外,一个组件可以绑定一个Service并与之相互通讯,同时也可以执行一些进程间的通讯操作。在 Service中主要执行一些比较耗时的操作,诸如网络下载,

叶功恒的博客专栏 1997

Unity2020 发布Android包,下载安装配置JDK、SDK、NDK详细教程

配置成功页面 JDK、SDK、NDK

qq_41263535的博客 1万+

Android消息机制Handler、Thread、HandlerThread理解

最近重新看回AMS的启动过程,发现AMS的构造方法里创建了几个前台线程,有以下几点疑问。 疑问 HandlerThread是什么? MainHandler初始化传入的是前台线程的Looper对象,这说明什么? MainHandler收到消息队列的消息后,执行代码跑在主线程还是前台线程? Handler 1.Handler的一般用法 在应用程序开发中,如果直接在主线程中跑耗时的操作(比如下载),会导致主线程阻塞,超过5s会触发ANR,这时候我们会新开一个子线程执行耗时操作,同时通过Handler来通知主线

知难行易 739

树莓派5首次开机保姆级教程(无显示器通过VNC连接树莓派桌面)

选择 Interface Options > VNC > Yes 启用服务。2.在Windows电脑上安装VNC软件。重启树莓派:sudo reboot。3.使用VNC远程访问树莓派桌面。

qq_34184505的博客 2349

工作中SVN的使用,保姆级教程!

SVN是一款集中式版本控制系统,采用客户端-服务器模式管理代码版本。与Git相比,SVN在目录权限控制、大型二进制文件处理等方面具有优势,适合特定场景使用。本文介绍了SVN的安装方法、基本操作(检出、提交、更新、回滚等)以及分支管理(创建、合并、切换)。同时讲解了文件冲突的解决方法,并演示了如何在IDEA中集成SVN工具。SVN虽然逐渐被Git取代,但在某些特定场景下仍是可靠选择,工具选择应基于团队和项目需求。

胜人者有力,自胜者强! 1849

Android IntentService完全解析 当Service遇到Handler

转载请标明出处: http://blog.youkuaiyun.com/lmj623565791/article/details/47143563; 本文出自:【张鸿洋的博客】 一 概述 大家都清楚,在Android的开发中,凡是遇到耗时的操作尽可能的会交给Service去做,比如我们上传多张图,上传的过程用户可能将应用置于后台,然后干别的去了,我们的Activ...

weixin_30746117的博客 541

088、多摄像头跨镜目标追踪 ID 频繁切换?ReID 特征 + 轨迹关联 + 时间约束方案

文章摘要:本文针对多摄像头跨镜目标追踪中ID频繁切换的问题,提出了一种结合ReID特征、轨迹关联和时间约束的综合解决方案。作者分析了ID切换的三个主要原因:ReID特征不稳定、轨迹关联依赖最近邻匹配以及忽略时间约束。通过改进ReID特征提取(多层特征融合)、引入轨迹预测(卡尔曼滤波)和添加时间窗口约束,成功将ID切换率从35%降至3%以下。文章详细分享了实现细节和踩坑经验,为跨摄像头目标追踪提供了实用优化思路。

ai技术增长的博客 169

android service使用handle,android中对Looper、HandlerThread、IntentService的理解及使用方法...

消息队列处理模型容器保存事件,队列涉及到角色:类 功能MessageQueue 存放消息Looper 轮循消息队列,从中取出消息Thread 处理消息Message 消息Handler 在其他线程发消息给当前线程1.looper的例子及说明由Looper决定Looper对象在哪个线程创建,Handler的handl...

weixin_42127020的博客 678

2025华为杯第二十二届中国研究生数学建模竞赛D题:低空湍流监测及最优航路规划 - 完整解题分析+完整MATLAB源码!(下篇)

🎓 本文收录于 《滚雪球学数学建模》专栏,本专栏专注于从零基础出发,带你循序渐进掌握数学建模的核心方法与思维路径。通过“滚雪球式”学习法,从最简单的生活化案例到经典建模工具,再到省赛、国赛真题实战演练,逐步积累知识与技能,帮助你搭建完整的建模体系。无论你是刚接触建模的新生,还是希望提升科研与竞赛能力的学者与工程师,本专栏都将为你提供一条清晰、高效、可实操的建模成长路线,助力你快速进阶,突破难点,迈向数学建模竞赛与实际应用的更高峰 🚀!

**My Coding Family** 1621

【升级U8+】不能将值 NULL 插入列 ‘VT_ID‘,表 ‘VoucherItems‘;列不允许有 Null 值。

不能将值 NULL 插入列 ‘VT_ID’,表 ‘UFDATA_006_2012.dbo.VoucherItems’;列不允许有 Null 值。INSERT 失败。

努力不懈的为广大客户提供优质的产品与真诚、贴心、专业的服务! 513

Android中 AsyncTask、HandlerThread、IntentService、ThreadPool、JobIntentService 和 WorkManager等对比

在 Android 异步开发中,AsyncTask和是常用的异步处理工具。AsyncTask是一个轻量级的异步任务工具,适合执行短时间的后台任务,并更新 UI。

loutengyuan的专栏 1151

用 Custom Entity 打造 RAP Value Help:从能跑到好用的深度踩坑笔记

本文介绍了在RAP项目中实现Value Help(Fiori输入帮助)的完整流程。通过Custom Entity方式,开发者可以灵活构建不依赖数据库实体的值帮助功能,但需手动实现CDS原本提供的过滤、排序、分页等能力。文章以一个典型场景为例,详细说明了如何为Partner维护界面的City字段创建可搜索的值帮助,包括创建查询实现类、绑定CDS Custom Entity、服务发布等关键步骤,并特别指出了处理排序分页请求等常见问题。最后强调在ABAP Cloud环境下需要自行实现查询能力,而非依赖传统工具类。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 134

Android HandlerThread与IntentService

HandlerThread本质上是一个线程类,它继承了Thread; HandlerThread有自己的内部Looper对象,可以进行looper循环; 通过获取HandlerThread的looper对象传递给Handler对象,可以在handleMessage方法中执行异步任务。 创建HandlerThread后必须先调用HandlerThread.start()方法,Thread会先调...

jiang19921002的博客 464

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Android多线程之HandlerThread在IntentService中的应用

HandlerThread HandlerThread 继承 Thread,是一种可以使用 Handler 的 Thread ,它的具体实现,就是在 run 方法中通过 Looper.prepare() 来创建消息队列,并通过 Looper.loop() 来开启消息循环。run 方法具体代码实现如下: public void run() { mTid = Process.my...

u013163331的博客 274

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Android多线程:IntentService使用教程(含实例讲解)

前言 多线程的应用在Android开发中是非常常见的,常用方法主要有: 继承Thread类 实现Runnable接口 AsyncTask Handler HandlerThread IntentService 今天,我将手把手教你使用IntentService(含实例介绍)。 目录 1. 定义 Android里的一个封装类,继承四大组件之一的Service 2. 作用 处理...

Carson带你学Android 7269

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Android多线程(二)——AsyncTask、HandlerThread、IntentService的使用与对比

目录简介用法思考 简介 定义 AsyncTask翻译过来的意思就是异步任务,是Android中实现异步任务的方式之一。 优势 与继承Thread和实现Runable接口相比的优势是内部实现了异步通信,工作线程与主线程通信更方便,又因为AsyncTask内部使用了线程池与缓存机制,避免频繁的创建和销毁线程减少了系统开销。 不足 只能继承AsyncTask类实现,涉及到与UI交互时为了方便取到view...

whale的博客 594

Connor学Android - HandlerThread和IntentService

Hey,欢迎阅读Connor学Android系列,这个系列记录了我的Android原理知识学习、复盘过程,欢迎各位大佬阅读斧正!原创不易,转载请注明出处:http://t.csdn.cn/cqCub,话不多说我们马上开始!

ConnorYan的博客 412

Android的几种多线程方式(AsyncTask,HandlerThread,IntentService,ThreadPool),使用场景以及注意事项

在程序开发的实践当中,为了让程序表现得更加流畅,我们肯定会需要使用到多线程来提升程序的并发执行性能。但是编写多线程并发的代码一直以来都是一个相对棘手的问题,所以想要获得更佳的程序性能,我们非常有必要掌握多线程并发编程的基础技能。 引入多线程而可能伴随而来的内存问题 虽然使用多线程可以提高程序的并发量,但是我们需要特别注意因为引入多线程而可能伴随而来的内存问题。例如:在 Activity 内部定义的一个 AsyncTask,它属于一个内部类,该类本身和外面的 Activity 是有引用关系的,如果 Act

u010227042的博客 570

Android多线程开发之IntentService的使用

一、IntentService简介我们看下官方对其的解释:/** * IntentService is a base class for {@link Service}s that handle asynchronous * requests (expressed as {@link Intent}s) on demand. Clients send requests * through {

Just do it 1332

全面详解Android实现多线程的几种方式(史上最全,最详细)

一、目录 Android多线程实现方式包括: 二、基础使用 Android多线程实现的基础使用包括: 继承Thread类 实现Runnable接口 Handler 接下来对各个进行分析。 1、继承Thread类 1.1 简介 1.2 使用详解 (1)使用步骤 (2) 具体使用 // 步骤1:创建线程类 (继承自Thread类) class MyThread extends Thr...

恬静释然的博客 5万+

Android之IntentService的使用

通过前面的学习,大家会发现我们在使用 Service 时总会创建一个线程来执行任务,而不是直接在 Service中执行。这是因为 Service 中的程序仍然运行于主线程中,当执行一项耗时操作时,不新建一个线程的话很容易导致 Application Not Responding 错误。当需要与 UI线程进行交互时,使用 Handler 机制来进行处理。 为了简化操作,Android提供了IntentService类。IntentService是 Android中提供的后台服务类,是Service 自动实现

PPYY3344的博客 2355

Android 多线程之IntentService 完全详解

转载请注明出处(万分感谢!): http://blog.youkuaiyun.com/javazejian/article/details/52334098 出自【zejian的博客】 关联文章: Android 多线程之HandlerThread 完全详解 Android 多线程之IntentService 完全详解 IntentService 一、IntentService概述

zejian的博客 4万+

Android多线程:请收好这份全面&详细的多线程学习指南!

前言 多线程的应用在Android开发中是非常常见的,常用方法主要有: 今天,我将献上一份全面 & 详细的Android多线程学习指南,希望你们喜欢。 目录 1. 多线程基础知识 在了解Android多线程实现方式前,需了解一些多线程基础知识,如线程、进程等 具体请看文章:Android多线程:你必须要了解的多线程基础知识汇总 2. Android多线程实现方式 ...

Carson带你学Android 5142

Android多线程之IntentService工作机制详解

前言:IntentService在我们平常的开发过程中是非常常见的,我们都习惯于用它去处理一些耗时任务,但是对于它的内部机制,你真的了解?下面我们通过几个常见的面试题,来对IntentService一一剖析。想要了解更多关于Android多线程知识,请移步 Android多线程专栏。 常见面试问题: 你对IntentService了解么?说一下他的用处和原理? IntentService和S...

白哥哥的博客 1372
上一篇: Exception java.lang.IllegalStateException: Cannot perform this operation because the connection pool
下一篇: 并发编程专题-4:ThreadLocal 原理解析
开发者如是说
博客等级 码龄10年 67粉丝 163原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值