当前位置: 移动技术网 > 移动技术>移动开发>Android > IntentService 原理详解

IntentService 原理详解

2020年07月27日  | 移动技术网移动技术  | 我要评论

1 简单介绍
IntentService是一个继承自Service的抽象类,是一种特殊的Service。所以两者的基本配置和启动方式都是一样的,区别是IntentService创建了自己的特有方法onHandleIntent(),可以用来处理异步请求,实现多线程,因此用来执行后台耗时操作任务,而每一个耗时操作都会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个。

2 使用方式步骤
① 定义IntentService的子类:传入线程名称、复写onHandleIntent()方法
② 在Manifest.xml中注册服务
③ 在Activity中开启Service服务

public class MyIntentService extends IntentService {
    private static final String TAG = MyIntentService.class.getSimpleName();

    /**
        Java基础知识
     *  为什么必须要重写? 父类只有带参数的构造器(无参构造器没有),则子类必须有相同参数的构造方法,并且还需要调用super(参数),如果父类中含有无参构造函数,则super可以省略不写
     *  调用父类的构造函数
     *  构造函数参数=工作线程的名字
     */
    public MyIntentService() {
        super("MyIntentService");
    }


    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate: ");
    }

    /**
     * 执行耗时操作  必须判断intent是否为空
     * @param intent
     */
    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            String tag = intent.getStringExtra("task");
            switch (tag) {
                case "task1":
                    Log.i(TAG, "onHandleIntent: " + "正在执行task1");
                    break;
                case "task2":
                    Log.i(TAG, "onHandleIntent: " + "task1已执行完毕 开始执行task2");
                    break;
            }
        }
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy: ");
    }
}

<!--        exported-->
<!--        是否其它应用组件能调用这个service或同它交互,如果能则为true,否则为false-->
<!--        当值为false时,只有同一个应用的组件或有相同用户ID的应用能启动这个服务或绑定它。-->
<!--        默认值依赖于服务是否包含intent filters。-->
<!--        没有intent filters意味着它只能通过指定它的准确类名来调用它,这就意味着这个服务只能在应用内部被使用(因为其它应用不知道这个类的类名)。因此,在这种情况下,默认值是false-->
<!--        至少有一个intent filters意味着这个服务可以在外部被使用,因此,默认值为true-->
        <service
            android:name=".test.MyIntentService"
            android:exported="false"
            tools:ignore="Instantiatable">
            <intent-filter>
                <action android:name="com.adnonstop.myintentservice"/>
            </intent-filter>
        </service>
//同一服务只会开启一个工作线程
//在onHandleIntent函数里依次处理intent请求。
Intent i = new Intent("com.adnonstop.myintentservice");
i.putExtra("task", "task1");
i.setPackage(getPackageName());
startService(i);

Intent i2 = new Intent("com.adnonstop.myintentservice");
i2.putExtra("task", "task2");
i2.setPackage(getPackageName());
startService(i2);
//多次启动
for (int j = 0; j < 50; j++) {
    if (j % 2 == 0) {
        startService(i);
    } else {
        startService(i2);
    }
} 

打印数据发现会永远按照队列的方式按照顺序来执行耗时操作

onHandleIntent: 正在执行task1
onHandleIntent: task1已执行完毕 开始执行task2

3 .为什么在onHandleIntent 中可以进行耗时操作,内部原理是如何实现的?

private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
    
IntentService里面的onCreate()方法
@Override
    public void onCreate() {
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

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

分析1; HandlerThread 继承自Thread,首先开启了一个名为mName的子线程thread ,然后获取子线程中的looper赋值给mServiceLooper,再创建一个handler并且与mServiceHandler绑定,所以现在的mServiceHandler属于工作线程的

HandlerThread 中是如何维护了一个looper?

HandlerThread 里面重写的run方法
@Override
    public void run() {
        //这个是在子线程中创建handler的完成部分
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

分析2: 我们在分析handler的原理时,分析过在子线程中创建handler的过程
首先要创建一个Looper ,即调用Looper.prepare();,然后将创建的looper赋值给本地维护的mLooper ,加了一个同步锁,这也就保证了我们在多线程操作时保证执行的顺序

获取和子线程绑定的looper的方法
public Looper getLooper() {
//如果线程没有启动或者时因为某些原因,线程杀掉 返回为null
   if (!isAlive()) {
       return null;
   }
   //如果线程已经启动,则会一直等到创建looper为止
   synchronized (this) {
       while (isAlive() && mLooper == null) {
           try {
               wait();
           } catch (InterruptedException e) {
           }
       }
   }
   return mLooper;
}

分析3 创建mServiceHandler之后,就是发送消息了

多次启动同一个service,只会多次执行onStartCommand方法,只会执行一次oncreate方法,
保证只创建了一个mServiceHandler,所有的发送消息和处理消息都会交给他处理
 @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 onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }
处理消息的方法
private final class ServiceHandler extends Handler {
    public ServiceHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
    //抽象方法 onHandleIntent ,所以我们重写即可
    //protected abstract void onHandleIntent(@Nullable Intent intent);
        onHandleIntent((Intent)msg.obj);
    //onHandleIntent 处理完成后 IntentService会调用 stopSelf() 自动停止。
        stopSelf(msg.arg1);
    }
}

工作队列中的任务是顺序执行的。因为onCreate() 方法只会调用一次,所以只会创建一个工作线程,多次开启服务只会多次执行onStartCommand方法,不会创建更多的线程,只是将消息添加到消息队列的等待执行。
但如果服务停止的话,会清空队列里的消息,不再执行。

Handler 对象在哪个线程下构建(Handler的构造函数在哪个线程下调用),那么Handler 就会持有这个线程的Looper引用和这个线程的消息队列的引用。因为持有这个线程的消息队列的引用,意味着这个Handler对象可以在任意其他线程给该线程的消息队列添加消息,也意味着Handler的handleMessage 肯定也是在该线程执行的。handler对象所绑定的线程其实并不取决于该handler对象由哪个线程构建,而是取决于该handler对象所绑定的Looper属于哪个线程。

本文地址:https://blog.csdn.net/yangsenhao211423/article/details/107576636

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网