Android(java)学习笔记210:Android线程形态之 IntentService

1. IntentService原理

IntentService是一种特殊的Service,既然是Service,使用的时候记得在AndroidManifest清单文件中注册

并且它是一个抽象类,因此必须创建它的子类才能使用IntentService,IntentService可用于执行后台耗时的任务,当任务执行后它会自动停止,同时由于IntentService是服务的原因,这导致它的优先级比单纯的线程要高级很多,所以IntentService比较适合执行高优先级的后台任务,因为它的优先级高不容易被系统杀死。

在实现上,IntentService封装了HandlerThread Handler,这一点我们可以在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 thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

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

当IntentService被第一次启动时候,它的onCreate方法会被调用,onCreate方法会创建一个HandlerThread,然后利用它的Looper构造一个Handler对象mServiceHandler(ServiceHandler继承自HandlerServiceHandler是IntentService内部类 

我们来到IntentService中的内部类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);
        }
    }

 

这样通过mServiceHandler发送的消息都会最终在HandlerThread中执行,从这个角度来看,IntentService也可以用于执行后台任务。

每次启动IntentService,它的onStartCommand方法就会调用一次,IntentService在onStartCommand中处理每个后台任务的Intent。

 

接下来我们要看一下IntentService在OnStartCommand方法是如何处理外界的Intent的,如下:

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

在上面源码中可以知道onStartCommand调用了onStart,我们再看看IntentService中onStart方法的实现如下所示:

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

上面的源码可以看出,在onStart方法之中,IntentService仅仅是通过mServiceHandler发送了一个消息,而mServiceHandler录属于HandlerThread的,所以这个消息会在HandlerThread这个线程之中被处理。

mServiceHandler收到消息之后,会将Intent对象传递给onHandleIntent方法去处理。

需要特别注意

  这里的Intent对象的内容 和 外界的StartService(intent)中的intent的内容是完全一致的,通过这个Intent对象即可解析出外界启动IntentService时候所传递的参数,通过这些参数就可以区分具体的后台任务,这样在onHandleIntent方法中就可以对不同的后台任务做处理了。

 

当onHandleIntent方法执行结束之后,IntentService会通过stopSelf(int startId)方法尝试停止服务。这里之所以采用stopSelf(int startId)而不是stopSelf()来停止服务,那是因为stopSelf()会立刻停止服务,而这个时候可能还有其他消息未处理,stopSelf(int startId)则会等待所有的消息都处理完毕之后才终止服务。一般来说,stopSelf(int startId)在尝试停止服务之前会判断最近启动服务的次数是否和startId相等,如果相等就立刻停止服务不相等则不停止服务

 

IntentService的onHandleIntent方法是一个抽象方法,它需要在子类中实现,它的作用是从Intent参数中区分具体的任务并执行这些任务。如果目前只存在一个后台任务,那么onHandleIntent方法执行完整个任务之后,stopSelf(int startId)就会直接停止服务;如果目前存在多个后台任务,那么当onHandleIntent方法执行完最后一个任务时候,stopSelf(int startId)才会直接停止服务。

另外,由于每执行一个后台任务必须启动一次IntentService,而IntentService内部则可以通过消息的方式向HandlerThread请求执行任务,Handler中的Looper是顺序处理消息的,这就意味着IntentService也是顺序执行后台任务的,当有多个后台任务同时存在,这些后台任务会按照外界发起的顺序排队执行。

 

总而言之,流程如下:

2. IntentService使用示例:

(1)新建Android工程如下:

 

(2)首先我们来到主Activity,如下:

package com.himi.intentservicedemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /**
         * 可以启动多次,每启动一次,就会新建一个work thread
         * 但IintentService的实例始终只有一个
         */
        // Operation 1
        Intent startServiceIntent = new Intent(this,MyIntentService.class);
        Bundle bundle = new Bundle();
        bundle.putString("param", "oper1");
        startServiceIntent.putExtras(bundle);
        startService(startServiceIntent);

        // Operation 2
        Intent startServiceIntent2 = new Intent(this,MyIntentService.class);
        Bundle bundle2 = new Bundle();
        bundle2.putString("param", "oper2");
        startServiceIntent2.putExtras(bundle2);
        startService(startServiceIntent2);
    }
}

 

(3)其次这里在MainActivity中开启IntentService服务,但是它是个抽象类需要一个IntentService具体实现子类,这里为MyIntentService,如下:

package com.himi.intentservicedemo;

import android.app.IntentService;
import android.content.Intent;
import android.os.IBinder;

public class MyIntentService extends IntentService {

    public MyIntentService() {
        // 必须实现父类的构造方法
        super("IntentServiceDemo");
    }

    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("onBind");
        return super.onBind(intent);
    }

    @Override
    public void onCreate() {
        System.out.println("onCreate");
        super.onCreate();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        System.out.println("onStart");
        super.onStart(intent, startId);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void setIntentRedelivery(boolean enabled) {
        super.setIntentRedelivery(enabled);
        System.out.println("setIntentRedelivery");
    }

    @Override
    protected void onHandleIntent(Intent intent) { //这个方法在子线程中执行,因此需要用到handler跟主线程进行通信
        // Iintent是从Activity发过来的,携带识别参数,根据参数不同执行不同的任务
        String action = intent.getExtras().getString("param");
        if (action.equals("oper1")) {
            System.out.println("Operation1");
        } else if (action.equals("oper2")) {
            System.out.println("Operation2");
        }

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroy() {
        System.out.println("onDestroy");
        super.onDestroy();
    }

}

(4)最后很重要一步,别忘了配置IntentService,因为它继承于Service,所以,它还是一个Service,一定要配置,否则是不起作用的,在清单文件中配置一下IntentService,如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.himi.intentservicedemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <service 
            android:name="MyIntentService">
        </service>
        
    </application>

</manifest>

 

(5)部署程序到手机上,观察Logcat如下:

 

  从结果可以看到,onCreate方法只执行了一次,而onStartCommand和onStart方法执行了两次,开启了两个Work Thread,这就证实了之前所说的,启动多次,但IntentService的实例只有一个,这跟传统的Service是一样的。Operation1也是先于Operation2打印,并且我让两个操作间停顿了2s,最后是onDestroy销毁了IntentService

这就是IntentService,一个方便我们处理业务流程的类,它是一个Service,但是比Service更智能。

posted on 2016-05-27 10:43  鸿钧老祖  阅读(213)  评论(0编辑  收藏  举报

导航