Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

IntentService 从使用到源码分析

$
0
0

1. 基本使用

1.1 什么是IntentService

IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。
所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。

1.2 IntentService 的好处

  • 自动开启线程处理耗时任务.
  • 操作完成时自动销毁Service.

1.3 基本使用

  • 创建 IntentService 的子类.
/**
 * @author : Brian
 */

public class MyIntentService extends IntentService {
    private static final String TAG = "MyIntentService";


    /**
     * 默认构造
     */
    public MyIntentService(){
        this("MyIntentService");
    }

    /**
     * 父类构造方法
     */
    public MyIntentService(String name) {
        super(name);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        Log.d(TAG, "onHandleIntent: ");

        String opType = intent.getExtras().getString("param");
        // 分辨任务
        Log.d(TAG, "任务 : " + opType);
        // 延时 3s
        SystemClock.sleep(3 * 1000);
    }

    /**
     * Unless you provide binding for your service,
     * you don't need to implement this method,
     * because the default implementation returns null.
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind: ");
        return super.onBind(intent);
    }

    /**
     * Called by the system when the service is first created.
     */
    @Override
    public void onCreate() {
        Log.d(TAG, "onCreate: ");
        super.onCreate();
    }

    /**
     * Called by the system to notify a Service that
     * it is no longer used and is being removed.
     */
    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy: ");
        super.onDestroy();
    }

    /**
     * You should not override this method for your IntentService.
     */
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * Sets intent redelivery preferences.
     */
    @Override
    public void setIntentRedelivery(boolean enabled) {
        Log.d(TAG, "setIntentRedelivery: ");
        super.setIntentRedelivery(enabled);
    }
}
  • AndroidMenifest.xml 中注册Service
<!-- 注册Intent Service -->
<service android:name="com.brain.interview.intent_service.MyIntentService">
    <intent-filter>
        <action android:name="com.brain.intentservice"/>
    </intent-filter>
</service>
  • 编写测试代码
/**
 * 启动
 */
public void startIntentService1() {
    // 操作一
    Intent intent = new Intent();
    intent.setAction("com.brain.intentservice");
    intent.setPackage(getPackageName());
    Bundle bundle = new Bundle();
    bundle.putString("param", "打球");
    intent.putExtras(bundle);
    startService(intent);

    // 操作二
    Intent intent2 = new Intent();
    intent2.setAction("com.brain.intentservice");
    intent2.setPackage(getPackageName());
    Bundle bundle2 = new Bundle();
    bundle2.putString("param", "吃饭");
    intent2.putExtras(bundle2);
    startService(intent2);
}
  • 输出
onCreate: 
onStartCommand: 
onStartCommand: 
onHandleIntent: 任务 : 打球
onHandleIntent: 任务 : 吃饭
onDestroy: 

从输出可以看出, 在执行完所有的任务后, 销毁了Service.

2. 源码分析

IntentService 源码并不复杂其实, 就是封装了 Handler + ThreadHandler

2.1 HandlerThread

普通的Thread主要用于进行耗时操作.HandlerThread内部常见了消息队列,外界需要通过Handler的消息方式通知HandlerThread来执行一个任务.由于HandlerThread的run() 是一个无限循环(Looper.loop()),因此当明确不需要时需要主动调用,quit() 或者 quitSafely() 来终止线程的执行.

HandlerThread 的run方法的源码如下 :

@Override
public void run() {
    mTid = Process.myTid();
    // 创建和当前线程绑定的Looper对象
    Looper.prepare();
    // 保存当前线程的Looper的一个引用
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    // 使用者,可以重写这个方法进行消息循环开启前的设置.
    onLooperPrepared();
    // 开启消息循环
    Looper.loop();
    mTid = -1;
}

HandlerThread的好处就是他带有Looper, 不用我们手动开启Looper, 有了Looper我们就可以绑定Handler了

2.2 IntentService

  • 首先在来看 onCreate() 方法
@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 并启动, HandlerThread 内部维护这一个Looper.
    // 可以利用这个Looper来使用Handler机制..
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();
    // 保存Looper的引用, 便于在Service退出时.退出Looper
    mServiceLooper = thread.getLooper();
    // 创建Handler
    mServiceHandler = new ServiceHandler(mServiceLooper);
}
  1. 首先创建了一个HandlerThread对象, 并且启动了该对象.
  2. 然后保存了HandlerThread中的Looper对象的一个引用, 便于在IntentService销毁时对出Looper. 否则该子线程将会一直运行.
  3. 创建了一个Handler和创年的HandlerThread绑定在一起.

通过上面的三步就实现了. 一个可以接收msg的Handler, 并且在绑定的子线程中执行消息处理.之后我们只需要通过Handler发送消息, 通过Intent传送数据就可以实现在子线程中处理数据了.


  • 再看,Service每次启动都会调用的onStartCommand()和onStart()方法,主要看onStart
@Override
public void onStart(@Nullable Intent intent, int startId) {
    // 发送消息.切换线程执行, 将Service的startId 发送过去, 便于stop Service
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}

我们可以看出在onStart() 中的实现也是十分简单, 就是通过之前创建的Handler发送了一个消息.将intent数据发送过去, 同时还携带了一个参数startId . 之所以要携带这个id是因为在Handler中需要调用stopSelf()方法来停止Service, (下面的话有点通俗) 只有当所有的startdid都stop了, Service才会真正的退出.


  • 再来看, Handler的实现
private final class ServiceHandler extends Handler {
    public ServiceHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        // 这个方法需要使用者实现.字节的逻辑, 在子线程中执行
        onHandleIntent((Intent)msg.obj);
        // 这个方法不会立即将Service结束掉, 会等到所有的onStart
        // 注意1 : msg.arg1中保存的Service的startId
        stopSelf(msg.arg1);
    }
}
  1. 首先会调用 onHandleIntent(intent)方法,并将数据传送进去.onHandleIntent(intent)方发是一个虚方法需要子类实现, 使用者的业务逻辑也是写在这个方法中的, 前面说过改Handler是和创建的HandlerThread对象的Looper绑定在一起的因此,次方法在子线程中执行.
  2. onHandleIntent(intent)方法执行完后, 就会调用 stopSelf(msg.arg1), 通过前面的分析可知msg.arg1 中存放给的是startId. 当所有的startId都被stop后Service也就结束了.

  • 继续 onDestroy()方法
@Override
public void onDestroy() {
    // Service 烧毁时, 退出线程
    mServiceLooper.quit();
    super.onDestroy();
}

Service结束后, 对于Service中启动的子线程是没有影响的.在这HandlerThread中有Looper因此不会自动退出, 需要手动调用quit方法.

IntentService注释版本代码如下

/**
 * @author : Brian
 * @date : 2017/6/29
 */
public abstract class IntentService extends Service {

    private static final String TAG = "IntentService";


    /**
     * HandlerThread中获取的Looper, 便于在Service销毁时,退出线程.
     */
    private volatile Looper mServiceLooper;

    /**
     * 该Handler和HandlerThread的Looper线程绑定在一起,
     * 也就是说会在那个线程中执行消息处理.
     */
    private volatile ServiceHandler mServiceHandler;

    /**
     * 线程名称
     */
    private String mName;

    private boolean mRedelivery;

    /**
     * Handler
     */
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            // 这个方法需要使用者实现.字节的逻辑, 在子线程中执行
            onHandleIntent((Intent)msg.obj);
            // 这个方法不会立即将Service结束掉, 会等到所有的onStart
            // 注意1 : msg.arg1中保存的Service的startId
            stopSelf(msg.arg1);
        }
    }

    /**
     * 子类构造方法调用
     */
    public IntentService(String name) {
        super();
        mName = name;
    }

    /**
     *
     */
    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 并启动, HandlerThread 内部维护这一个Looper.
        // 可以利用这个Looper来使用Handler机制..
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
        // 保存Looper的引用, 便于在Service退出时.退出Looper
        mServiceLooper = thread.getLooper();
        // 创建Handler
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        // 发送消息.切换线程执行, 将Service的startId 发送过去, 便于stop Service
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    /**
     * 每次启动Service都会调用这个方法.
     */
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        // Service 烧毁时, 退出线程
        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
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * 这个方法在子线程中被调用, 同一时刻只会有一个Intent请求被处理. 在逻辑上处理过程
     * 在一个独立的子线程中执行.一次如果这个方法中的处理时间太长就会阻塞在同一个IntentService
     * 发起的其他请求. 当所有的请求都处理结束后,IntentService会自动销毁. 因此不需要调用者
     * 手动调用stopSelf()方法
     */
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}
作者:qq_16188829 发表于2017/6/30 11:57:07 原文链接
阅读:27 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>