前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >IntentService使用及源码分析

IntentService使用及源码分析

作者头像
程序员徐公
发布2018-09-18 17:30:42
3160
发布2018-09-18 17:30:42
举报

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1342026

IntentService使用及源码分析


转载请注明原博客地址: http://blog.csdn.net/gdutxiaoxu/article/details/52000680

本篇博客主要简介一下三个问题:

  1. 什么是IntentService?
  2. 怎样使用IntentService
  3. IntentSerice()源码分析

1)什么是IntentService?

我们知道Service和Activity一样是Android的四大组件之一,Service简称为后台服务,具有较高的优先级别。我们平时在Activity中直接开启Service,是运行在主线程的。如果想要执行耗时任务,我们必须自己开启线程。而IntentService是把任务放在子线程中执行的。

  • 我们先来看一下官方的解析是怎样的?

This “work queue processor” pattern is commonly used to offload tasks from an application’s main thread. The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate. All requests are handled on a single worker thread – they may take as long as necessary (and will not block the application’s main loop), but only one request will be processed at a time.undefined


简单来说主要有一下几点

  1. Service是运行在子线程的;
  2. 多个请求会按启动的顺序执行,但是一次只会处理一个任务;
  3. 任务执行完毕以后会自动退出Service,不需要我们自己处理

2)下面我们来看一下我们要怎样使用IntentService?

其实跟普通的Service差不多

  • 1)自定义一个MyIntentService集成IntentService,重写构造方法和onHandleIntent方法,在HandleIntent里面执行我们的耗时任务等操作
代码语言:javascript
复制
public class MyIntentService extends IntentService {

    private static final String ACTION_DOWNLOAD = "com.szl.intentservicedemo.action.DOWNLOAD";
    private static final String ACTION_UPLOAD = "com.szl.intentservicedemo.action.UPLOAD ";


    private static final String EXTRA_PARAM1 = "com.szl.intentservicedemo.extra.PARAM1";
    private static final String EXTRA_PARAM2 = "com.szl.intentservicedemo.extra.PARAM2";
     public static final String TAG="tag";

    public MyIntentService() {
        super("MyIntentService");
    }

   //这里省略了若干个方法


    //处理我们启动的Service
    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_DOWNLOAD.equals(action)) {
                final String param1 = intent.getStringExtra(EXTRA_PARAM1);
                final String param2 = intent.getStringExtra(EXTRA_PARAM2);
                handleDOwnload(param1, param2);
            } else if (ACTION_UPLOAD.equals(action)) {
                final String param1 = intent.getStringExtra(EXTRA_PARAM1);
                final String param2 = intent.getStringExtra(EXTRA_PARAM2);
                handleUpload(param1, param2);
            }
        }
    }


}
  • 2)别忘了在清单文件里面注册我们的Service
代码语言:javascript
复制
 <service
  android:name=".MyIntentService"
  android:exported="false">
 </service>
  • 3)启动我们的Service,这里使用context.startService(intent)启动,当然你也可以用bindService启动
代码语言:javascript
复制
Intent intent = new Intent(context, MyIntentService.class);
intent.setAction(ACTION_UPLOAD);
intent.putExtra(EXTRA_PARAM1, param1);
intent.putExtra(EXTRA_PARAM2, param2);
context.startService(intent);

测试代码如下

代码语言:javascript
复制
public void onButtonClick(View view) {
    switch (view.getId()) {
        case R.id.btn_download:
            MyIntentService.startActionDownLoad(MainActivity.this, "下载", "发起者主线程");
            break;

        case R.id.btn_upload:
            MyIntentService.startActionUpload(MainActivity.this, "上传", "发起者主线程");
            break;

        default:
            break;
    }
}

运行以上测试程序,依次点击模拟上传和模拟下载,将可在我们的控制台上看到以下的log信息

控制台输出的Log

IntentService源码分析

这里先贴出IntentService的源码

代码语言:javascript
复制
public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

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

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public IntentService(String name) {
        super();
        mName = name;
    }

    /**
     * Sets intent redelivery preferences.  Usually called from the constructor
     * with your preferred semantics.
     *
     * <p>If enabled is true,
     * {@link #onStartCommand(Intent, int, int)} will return
     * {@link Service#START_REDELIVER_INTENT}, so if this process dies before
     * {@link #onHandleIntent(Intent)} returns, the process will be restarted
     * and the intent redelivered.  If multiple Intents have been sent, only
     * the most recent one is guaranteed to be redelivered.
     *
     * <p>If enabled is false (the default),
     * {@link #onStartCommand(Intent, int, int)} will return
     * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
     * dies along with it.
     */
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

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

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

    /**
     * You should not override this method for your IntentService. Instead,
     * override {@link #onHandleIntent}, which the system calls when the IntentService
     * receives a start request.
     * @see android.app.Service#onStartCommand
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

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

    /**
     * Unless you provide binding for your service, you don't need to implement this
     * method, because the default implementation returns null. 
     * @see android.app.Service#onBind
     */
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * This method is invoked on the worker thread with a request to process.
     * Only one Intent is processed at a time, but the processing happens on a
     * worker thread that runs independently from other application logic.
     * So, if this code takes a long time, it will hold up other requests to
     * the same IntentService, but it will not hold up anything else.
     * When all requests have been handled, the IntentService stops itself,
     * so you should not call {@link #stopSelf}.
     *
     * @param intent The value passed to {@link
     *               android.content.Context#startService(Intent)}.
     */
    @WorkerThread
    protected abstract void onHandleIntent(Intent intent);
}

源码分析

分析之前我们先来看一下Service生命周期

这里我们以startService()为例分析,从我们启动一个IntentService,调用的过程大概是这样的,

构造方法 ->onCreate()- >onStartCommand()- >onStart()->Service running–>

  • 1)首先我们先来看一下构造方法里面做了什么事情
代码语言:javascript
复制
public IntentService(String name) {
    super();
    mName = name;
}

其实很简单,只是调用父类的构造方法,并保存我们的那么字段

  • 2)接着我们来看我们的onCreate方法做了什么?
代码语言:javascript
复制
@Override
public void onCreate() {
    super.onCreate();
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();

    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
}

简单来说,就是为我们初始化一个线程thread并启动它,并将线程的looper与我们的mServiceHandler绑定在一起。

  • 3)接着我们来看onStartCommand()方法做了什么?
代码语言:javascript
复制
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    onStart(intent, startId);
    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

我们可以看到在onStartCommand转调了onStart()方法

  • 4)onStart()方法
代码语言:javascript
复制
@Override
public void onStart(Intent intent, int startId) {
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}

在onStart()方法里面其实就是用我们的mServiceHandler发送信息(mServiceHandler.sendMessage(msg);),这样在我们handleMessage()里面讲可以收到我们的信息,在handleMessage()里面有调用onHandleIntent()去处理我们的Intent,这就是为什么我们需要重写onHandleIntent的原因。

代码语言:javascript
复制
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);
    }
}
  • 5)至于上面提到的我们的handleIntent是运行在子线程的,其实也很容易理解,因为我们知道handle运行在主线程还是子线程,是取决于我们与那个线程的looper绑定在一个的,而IntentService在onCreate方法中将我们的mServiceHandler与子线程的looper绑定在一起。核心代码体现如下
代码语言:javascript
复制
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
  • 6)为什么多个请求会按启动的顺序执行,但是一次只会处理一个任务? 我们知道多次调用context.startService方法,不会多次调用我们的onCreate()方法,但会调用我们的onStart()方法,而在我们的onStart()方法里面我们调用mServiceHandler.sendMessage(msg);相当于是向消息队列里面插入一条信息,Looper会不断地从里面取出消息,交给相应 的hanlder处理,直到没有消息为止。如果对Handler消息机制不了解的话,建议先去了解
  • 7)为什么任务执行完毕以后会自动退出Service,不需要我们自己处理? 这个就很简单了,因为在处理完信息以后,会调用stopSelf去停止相应的服务。
代码语言:javascript
复制
public void handleMessage(Message msg) {
    onHandleIntent((Intent)msg.obj);
    stopSelf(msg.arg1);
}

到此IntentService源码分析位置

关于HandlerThread的分析,可以查看我的 这一篇博客 :HandlerThread源码分析

转载请注明原博客地址: http://blog.csdn.net/gdutxiaoxu/article/details/52000680

例子源码下载地址: http://download.csdn.net/detail/gdutxiaoxu/9583047

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年07月23日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • IntentService使用及源码分析
    • 本篇博客主要简介一下三个问题:
      • 1)什么是IntentService?
        • 2)下面我们来看一下我们要怎样使用IntentService?
          • 测试代码如下
          • 运行以上测试程序,依次点击模拟上传和模拟下载,将可在我们的控制台上看到以下的log信息
        • IntentService源码分析
          • 这里先贴出IntentService的源码
          • 源码分析
      相关产品与服务
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档