• 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更智能。

  • 相关阅读:
    windows下忘记mysql超级管理员root密码的解决办法
    windows防火墙支持FTP服务的设置方法
    IT人士不得不看的保健手册
    利用Google开发接口获取Google用户信息,OAuth2.0,profiles
    一个简单抓取糗事百科糗事的小程序
    JAVA 数据库编程
    JAVA 数据库编程(1)
    JAVA 数据库编程(2)
    css快速入门
    html5和css3新增特性
  • 原文地址:https://www.cnblogs.com/hebao0514/p/5533796.html
Copyright © 2020-2023  润新知