欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

IntentService 原理详解

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

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

相关标签: Android Handler