上一篇详细介绍了Android——HandlerThread浅析

1. 简介

在Android应用的程序中,如果Service中处理耗时的操作,很容易出现ANR的现象,通常的做法就是,在onStartCommon方法中开启一个子线程然后内部执行耗时的操作,在执行完毕后如果停止服务,还需要手动的在子线程的run方法中调用stopSelf()来停止服务。

这里有一个问题,频繁的创建关闭子线程,对系统资源开销是非常大的,于是引入了IntentService,其实IntentService,就是Service 和 HandlerThread 的结合体

区别service:

  • IntentService是继承Service的,那么它包含了Service的全部特性,也包含service的生命周期。
  • 与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去执行耗时操作
  • IntentService:异步处理服务,新开一个线程:handlerThread在线程中发消息,然后接受处理完成后,会清理线程,并且关掉服务

特点:

  • IntentService是Service类的子类,用来处理异步请求
  • IntentService是借助于消息队列实现的,所以任务的执行顺序就是一个queue单链表的形式
  • 由于是单线程(一个工作线程),所以所有的任务需要排队执行
    (多次启动IntentService,每个耗时操作将以队列的方式在IntentService的onHandleIntent回调方法中依次执行,执行完自动结束。)

优缺点:

  • 1、使用方便,代码简洁,不再需要我们自己像Service里面还要去手动创建线程;
  • 2、当操作完成时,我们不用手动停止Service
  • 1、由于是单个的worker thread,所以任务需要排队,不适合大多数的多任务情况
  • 2、不适合用于bindService()这样的启动方式的

工作流程图:

android service中可以开启线程么 android service handler_ide


实现步骤:

  • 1、定义IntentService的子类:传入线程名称、复写onHandleIntent()方法
  • 2、在Manifest.xml中注册服务
  • 3、在Activity中开启Service服务

2. 举个例子

步骤1:定义IntentService的子类:传入线程名称、复写onHandleIntent()方法

package com.example.xxx;
import android.app.IntentService;
import android.content.Intent;
import android.util.Log;

public class myIntentService extends IntentService {
	 public MyIntentService() {
	 	//构造函数,继承父类方法
	 	//参数=工作线程的名字
        super("MyIntentService");
    }
	@Override
	protected void onHandleIntent(Intent intent) {
		//重写onHandleIntent()方法,实现耗时任务的操作
		//根据Intent的不同进行不同的事务处理
		String taskName = intent.getExtras().getString("taskName");
		switch (taskName) {
			case "task1":
				Log.i("myIntentService", "do task1");
				break;
			case "task2":
				Log.i("myIntentService", "do task2");
				break;
			default:
				break;
		}
	}
	@Override
	public void onCreate() {
		Log.i("myIntentService", "onCreate");
		super.onCreate();		//单独开了个线程处理
	}

	/*复写onStartCommand()方法*/
	//默认实现将请求的Intent添加到工作队列里
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.i("myIntentService", "onStartCommand");
		return super.onStartCommand(intent, flags, startId);
	}
	@Override
	public void onDestroy() {
		Log.i("myIntentService", "onDestroy");
		super.onDestroy();
	}
}

步骤2:在AndroidManifest.xml中注册服务

<service android:name=".myIntentService">
<intent-filter>
<action android:name="cn.scu.finch"/>
</intent-filter>
</service>

步骤3:在Activity中开启Service服务

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);
	//同一服务只会开启一个工作线程
	//在onHandleIntent函数里依次处理intent请求。
	Intent i = new Intent("cn.scu.finch");
	Bundle bundle = new Bundle();
	bundle.putString("taskName", "task1");
	i.putExtras(bundle);
	startService(i);
	Intent i2 = new Intent("cn.scu.finch");
	Bundle bundle2 = new Bundle();
	bundle2.putString("taskName", "task2");
	i2.putExtras(bundle2);
	startService(i2);
	startService(i); //多次启动
}

结果

android service中可以开启线程么 android service handler_工作线程_02

3. 源码分析

1、IntentService是Service的子类,拥有Service的所有生命周期方法,内部还有一个ServiceHandler

// IntentService.java源码

public abstract class IntentService extends Service {
    // ServiceHandler继承Handler,创建时必须传入一个Looper
    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);
        }
    }

    public IntentService(String name) {
        super();
        mName = name;
    }

   protected abstract void onHandleIntent(@Nullable Intent intent);
}

2、onCreate()的源码,创建HandlerThread。

// IntentService.java源码

    @Override
    public void onCreate() {
        super.onCreate();

        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

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

IntentService服务开启后就会创建Handler线程(HandlerThread),并获取当前线程的Looper对象,然后关联到Handler中。

3、接下来是onStart()源码,调用mServiceHandler

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

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

当你启动IntentService的时候,就会产生一条附带startId和Intent的 Message并发送到MessageQueue中,接下来Looper发现MessageQueue中有Message的时候,就会停止Handler 处理消息。

4、handleMessage处理消息的代码

public void handleMessage(Message msg) {
      onHandleIntent((Intent)msg.obj);
      stopSelf(msg.arg1);
 }

接着调用 onHandleIntent((Intent)msg.obj),这是一个抽象的方法,其实就是我们要重写实现的方法,我们可以在这个方法里面处理我们的工作.当任务完成时就会调用stopSelf(msg.arg1)这个方法来结束指定的工作。

5、stopSelf(msg.arg1)

回调完成后回调用 stopSelf(msg.arg1),注意这个msg.arg1是个int值,相当于一个请求的唯一标识。每发送一个请求,会生成一个唯一的标识,然后将请求放入队列,当全部执行完成(最后一个请求也就相当于getLastStartId == startId),或者当前发送的标识是最近发出的那一个(getLastStartId == startId),则会销毁我们的Service.如果传入的是-1则直接销毁。

6、onDestroy()

@Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

服务结束后调用这个方法 mServiceLooper.quit()使looper停下来。

4. 总结

IntentService本质是采用Handler & HandlerThread方式:

  1. 通过HandlerThread单独开启一个名为IntentService的线程
  2. 创建一个名叫ServiceHandler的内部Handler
  3. 把内部Handler与HandlerThread所对应的子线程进行绑定
  4. 通过onStartCommand()传递给服务intent,依次插入到工作队列中,并逐个发送给onHandleIntent()
  5. 通过onHandleIntent()来依次处理所有Intent请求对象所对应的任务

通过复写方法onHandleIntent(),再在里面根据Intent的不同进行不同的线程操作就可以了
注意事项:工作任务队列是顺序执行的。

如果一个任务正在IntentService中执行,此时你再发送一个新的任务请求,这个新的任务会一直等待直到前面一个任务执行完毕才开始执行。

原因:

  1. 由于onCreate() 方法只会调用一次,所以只会创建一个工作线程;
  2. 当多次调用 startService(Intent) 时(onStartCommand也会调用多次)其实并不会创建新的工作线程,只是把消息加入消息队列中等待执行,所以,多次启动 IntentService 会按顺序执行事件;
  3. 如果服务停止,会清除消息队列中的消息,后续的事件得不到执行。

5. IntentService与Service的区别

  • 从属性 & 作用上来说 Service:依赖于应用程序的主线程(不是独立的进程 or线程)
    不建议在Service中编写耗时的逻辑和操作,否则会引起ANR;
  • IntentService:创建一个工作线程来处理多线程任务
  • Service需要主动调用stopSelft()来结束服务,而IntentService不需要(在所有intent被处理完后,系统会自动关闭服务)

6. IntentService与其他线程的区别

  • IntentService内部采用了HandlerThread实现,作用类似于后台线程;
  • 与后台线程相比,IntentService是一种后台服务,优势是:优先级高(不容易被系统杀死),从而保证任务的执行。
    对于后台线程,若进程中没有活动的四大组件,则该线程的优先级非常低,容易被系统杀死,无法保证任务的执行