Android多线程之IntentService

简介: IntentService继承自Service,所以IntentService也是四大组件之一,IntentService内部封装了HandlerThread线程 (只有一个线程) 来按顺序处理异步任务

**@author:小马快跑
@email:mqcoder90@gmail.com

@github:https://github.com/crazyqiang**

IntentService是什么?

IntentService继承自Service,所以IntentService也是四大组件之一,IntentService内部封装了HandlerThread线程 (只有一个线程) 来按顺序处理异步任务,通过startService(Intent) 来启动IntentService并通过Intent来传递异步任务,当任务结束后IntentService通过stopSelf(int startId)来自己停止服务。IntentService是一个抽象类,如果想使用IntentService,首先创建一个类继承IntentService,然后重写onHandleIntent(Intent)在子线程中处理Intent传过来的任务。

IntentService特点:

  • onHandleIntent(Intent)发生在子线程,不能直接更新UI,需要先把结果发到Activity中
  • 提交的任务顺序执行,如果一个任务A正在IntentService中执行,此时发送另一个异步任务B到IntentService中,那么必须等到任务A执行完之后任务B才会开始执行
  • 已经在IntentService中执行的任务是不会被打断的

IntentService使用例子

先上效果图:
IntentService.gif
可以看到,我们先启动了第1个任务,当第1个任务还没有执行完时,此时又启动了第2个任务,第2个任务不会立即执行,而是等到第1个任务下载到100%完成之后才会开始第2个下载任务,这就验证了IntentService会顺序执行异步任务,来看具体实现,首先继承一个IntentService并覆写onHandleIntent():

public class MyIntentService extends IntentService {
    public static final String ACTION_ONE = "action_one";
    public static final String ACTION_TWO = "action_two";
    private int progressOne, progressTwo;

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        if (intent == null) return;
        String action = intent.getAction();
        switch (action) {
            case ACTION_ONE:
                while (progressOne < 100) {
                    progressOne++;
                    sendBroadcast(getUpdateIntent(0, progressOne));
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                break;
            case ACTION_TWO:
                while (progressTwo < 100) {
                    progressTwo++;
                    sendBroadcast(getUpdateIntent(1, progressTwo));
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                break;
        }
    }
 }

onHandleIntent()是在子线程中执行,通过Intent接收任务然后执行任务,并通过BroadCastReceiver把运算结果不断发送到Activity中来更新UI,当所有任务执行完成以后,IntentService自动关闭。我们看到在IntentService中处理了任务,那么这里的任务是哪里传过来的呢?看下面代码:

 Intent intent = new Intent(IntentServiceActivity.this, MyIntentService.class);
 intent.setAction(MyIntentService.ACTION_ONE);
 startService(intent);

我们看到通过startService(Intent)直接启动并把任务传递到IntentService,最后别忘了在AndroidManifest.xml中定义IntentService:

 <service
     android:name=".multiThread.intentService.MyIntentService"
     android:screenOrientation="portrait" />

完整源码地址:Android多线程之IntentService

IntentService源码解析

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    public IntentService(String name) {
        super();
        mName = name;
    }

首先定义变量,并在构造方法中传入工作线程的名字。

    @Override
    public void onCreate() {
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @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;
    }

IntentService中上面三个方法的执行顺序:onCreate>onStartCommand>onStart

1、在onCreate()中初始化一个HandlerThread线程并启动,接着初始化一个ServiceHandler并把HandlerThread中的Looper作为参数传入ServiceHandler,这样就可以在主线程中通过ServiceHandler把Message发送到HandlerThread子线程中处理了;
2、在onStartCommand()中又调用了onStart()并根据mRedelivery 返回START_REDELIVER_INTENT 或者是START_NOT_STICKY,这两个有什么区别呢?我们来复习一下在onStartCommand()中返回值:

  • START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
  • START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务
  • START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
  • START_FLAG_REDELIVERY:如果你实现onStartCommand()来安排异步工作或者在另一个线程中工作, 那么你可能需要使用START_FLAG_REDELIVERY来让系统重新发送一个intent。这样如果你的服务在处理它的时候被Kill掉, Intent不会丢失.

所以当返回START_FLAG_REDELIVERY时,如果Service被异常Kill掉,在Service重启以后会重新发送Intent;如果返回START_NOT_STICKY,当Service被异常Kill掉时不会重新启动。

3、在onStart()中把Intent封装到Message中并通过ServiceHandler发送到HandlerThread中了,经过HandlerThread中的Looper.loop()循环取消息,最终还是还是ServiceHandler去处理消息,所以我们来看ServiceHandler:

   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);
        }
    }

    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);

在handleMessage()中,我们发现回调了onHandleIntent()方法,而这个方法是个抽象方法,也是在子类中我们必须要实现的,所以最终消息的处理需要我们仔细去处理,注意这个回调方法是在子线程中执行的,在执行完onHandleIntent()后,调用了stopSelf来关闭自己,关闭时IntentService回调onDestroy():

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

我们看到在IntentService结束时调用了mServiceLooper.quit()来停止HandlerThread中Looper的循环,即HandlerThread线程没有任务时不会再阻塞而是退出了。

相关文章
|
4月前
|
Java Android开发 UED
🧠Android多线程与异步编程实战!告别卡顿,让应用响应如丝般顺滑!🧵
【7月更文挑战第28天】在Android开发中,确保UI流畅性至关重要。多线程与异步编程技术可将耗时操作移至后台,避免阻塞主线程。我们通常采用`Thread`类、`Handler`与`Looper`、`AsyncTask`及`ExecutorService`等进行多线程编程。
58 2
|
1月前
|
调度 Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【10月更文挑战第11天】本文探讨了如何在Kotlin中实现高效的多线程方案,特别是在Android应用开发中。通过介绍Kotlin协程的基础知识、异步数据加载的实际案例,以及合理使用不同调度器的方法,帮助开发者提升应用性能和用户体验。
46 4
|
2月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
123 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
2月前
|
Java Android开发 UED
🧠Android多线程与异步编程实战!告别卡顿,让应用响应如丝般顺滑!🧵
在Android开发中,为应对复杂应用场景和繁重计算任务,多线程与异步编程成为保证UI流畅性的关键。本文将介绍Android中的多线程基础,包括Thread、Handler、Looper、AsyncTask及ExecutorService等,并通过示例代码展示其实用性。AsyncTask适用于简单后台操作,而ExecutorService则能更好地管理复杂并发任务。合理运用这些技术,可显著提升应用性能和用户体验,避免内存泄漏和线程安全问题,确保UI更新顺畅。
93 5
|
2月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android应用开发中的多线程编程,涵盖基本概念、常见实现方式及最佳实践。主要内容包括主线程与工作线程的作用、多线程的多种实现方法(如 `Thread`、`HandlerThread`、`Executors` 和 Kotlin 协程),以及如何避免内存泄漏和合理使用线程池。通过有效的多线程管理,可以显著提升应用性能和用户体验。
70 10
|
2月前
|
API Android开发 iOS开发
安卓与iOS开发中的线程管理对比
【9月更文挑战第12天】在移动应用的世界中,安卓和iOS平台各自拥有庞大的用户群体。开发者们在这两个平台上构建应用时,线程管理是他们必须面对的关键挑战之一。本文将深入探讨两大平台在线程管理方面的异同,通过直观的代码示例,揭示它们各自的设计理念和实现方式,帮助读者更好地理解如何在安卓与iOS开发中高效地处理多线程任务。
|
2月前
|
Java Android开发 开发者
安卓应用开发中的线程管理优化技巧
【9月更文挑战第10天】在安卓开发的海洋里,线程管理犹如航行的风帆,掌握好它,能让应用乘风破浪,反之则可能遭遇性能的暗礁。本文将通过浅显易懂的语言和生动的比喻,带你探索如何优雅地处理安卓中的线程问题,从基础的线程创建到高级的线程池运用,让你的应用运行更加流畅。
|
3月前
|
调度 Android开发 开发者
【颠覆传统!】Kotlin协程魔法:解锁Android应用极速体验,带你领略多线程优化的无限魅力!
【8月更文挑战第12天】多线程对现代Android应用至关重要,能显著提升性能与体验。本文探讨Kotlin中的高效多线程实践。首先,理解主线程(UI线程)的角色,避免阻塞它。Kotlin协程作为轻量级线程,简化异步编程。示例展示了如何使用`kotlinx.coroutines`库创建协程,执行后台任务而不影响UI。此外,通过协程与Retrofit结合,实现了网络数据的异步加载,并安全地更新UI。协程不仅提高代码可读性,还能确保程序高效运行,不阻塞主线程,是构建高性能Android应用的关键。
61 4
|
3月前
|
安全 网络安全 数据安全/隐私保护
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享安卓与iOS开发中的线程管理比较
【8月更文挑战第30天】本文将探讨网络安全与信息安全的重要性,并分享关于网络安全漏洞、加密技术和安全意识的知识。我们将了解常见的网络攻击类型和防御策略,以及如何通过加密技术和提高安全意识来保护个人和组织的信息安全。
|
3月前
|
Java 测试技术 Android开发
Android项目架构设计问题之构造一个Android中的线程池如何解决
Android项目架构设计问题之构造一个Android中的线程池如何解决
29 0