IntentService 原理详解
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
上一篇: 02-mui常用代码块
下一篇: P1757 通天之分组背包