博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android多线程之IntentService
阅读量:6244 次
发布时间:2019-06-22

本文共 5357 字,大约阅读时间需要 17 分钟。


@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使用例子

先上效果图:

可以看到,我们先启动了第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:

复制代码

完整源码地址:

####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线程没有任务时不会再阻塞而是退出了。

转载于:https://juejin.im/post/5a33e805f265da431280fab6

你可能感兴趣的文章
我的友情链接
查看>>
我的友情链接
查看>>
以太坊中的gas、gas price、gas limit到底是什么
查看>>
用户配置文件服务登录失败。无法加载用户配置文件
查看>>
com/android/dx/command/dexer/Main : Unsupported major.minor version 52.0
查看>>
我的友情链接
查看>>
四则运算法则表延伸 - 工厂方法模式
查看>>
我的友情链接
查看>>
话里话外:企业管理的五个层次
查看>>
Hazelcast集群服务(3)
查看>>
研究人员创建可***BIOS和网卡的恶意软件
查看>>
C++ numeric_limits的用法
查看>>
升级maildrop,解决自动回复乱码问题
查看>>
MySQL Sandbox---快速体验各版本MySQL
查看>>
我的友情链接
查看>>
CentOS安装KDE和Gnome
查看>>
非常有趣的js
查看>>
Spring 单元测试
查看>>
品读Mybatis源码---(1)解析配置文件
查看>>
android获取设备分辨率的新方法
查看>>