IntentService源码解析及使用注意事项

在说IntentService 之前我们先来了解下Service,Service 是长期运行在后台的应用程序组件。Service 不是一个单独的进程,它和应用程序在同一个进程中,它也不是一个线程,它和线程没有半毛钱关系,所以它不能处理耗时操作。如果直接把耗时操作放在 Service 的 onStartCommand() 中,很容易引起 ANR。如果有耗时操作就必须开启一个单独的线程来处理。

IntentService是继承于 Service 并处理异步请求的一个类。在他的内部有一个工作线程来处理耗时操作,启动 IntentService的方式和启动传统Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在IntentService 的 onHandleIntent 回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。而且,所有请求都在一个子线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。

源码分析

IntentService的源码代码量不大,逻辑也很简单:

public abstract class IntentService extends Service {
	private volatile Looper mServiceLooper;
	@UnsupportedAppUsage
	private volatile ServiceHandler mServiceHandler;
	private String mName;
	private boolean mRedelivery;
	//这里自定义一个Handler,他是在IntentService的onCreate方法里面完成初始化的,主要两个
	//作用:一是在在完成初始化之后的onstart()方法里面获取到Message对象,方便后面处理结果的
	//发送,二是在任务完成后将任务结果信息发送出去,也就是调用onHandleIntent方法;
	private final class ServiceHandler extends Handler {
    		public ServiceHandler(Looper looper) {
         		super(looper);
    		}
    		@Override public void handleMessage(Message msg) {
					//调用onHandleIntent方法将任务结果信息发送出去,该方法工作在工作线程
        			onHandleIntent((Intent)msg.obj);
					//onHandleIntent 处理完成后 IntentService会调用 stopSelf() 自动停止。
					stopSelf(msg.arg1)
   	 	}
	}
	public IntentService(String name) {
    		super();
    		mName = name;
	}
	public void setIntentRedelivery(boolean enabled) {
        		mRedelivery = enabled;
	}
	@Override public void onCreate() {
		super.onCreate();
		//这里通过HandlerThread对象巧妙地获取到主线程的Looper对象,用于Handler通信,		
		//并维护自己的工作队列;从这里我们可以知道,IntentService至少是Intent+Service
		//+Handler+Thread组成的一个复杂的具有处理异步任务兼备通信的综合体。
		HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
		thread.start();
		mServiceLooper = thread.getLooper();
		mServiceHandler = new ServiceHandler(mServiceLooper);
	}
	@Override public void onStart(@Nullable Intent intent, int startId) {
		//在这里通过mServiceHandler对象获取到主线程里面的Message对象
    	Message msg = mServiceHandler.obtainMessage();
    	msg.arg1 = startId;
    	msg.obj = intent;
		//这里IntentService通过Handler发生任务(消息)到MessageQueue队列去,然后通过
		//onHandleIntent()去执行。
    	mServiceHandler.sendMessage(msg);
	}
	//通过onStartCommand()调用onStart()方法把工作任务传递给服务intent,依次插入到工作队列
	//中,并逐个发送给onHandleIntent()
	@Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
		//调用onStart()方法开始处理任务,因此多次启动 IntentService 不会重新创建新的服务
		//和新的线程,只是把消息加入消息队列中等待执行,
		//而如果服务停止,会清除消息队列中的消息,后续的事件得不到执行。
    	onStart(intent, startId);
    	return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
	}
	@Override public void onDestroy() {
    		mServiceLooper.quit();
	}
	@Override @Nullable
    	public IBinder onBind(Intent intent) {
			return null;
    	}
	//根据注解,我们可以知道这个方法是在工作线程也就是子线程里面执行的。
	//我门在使用IntentService的时候,这个方法是我们唯一必须实现并重写的一个方法。我们的异步任
	//务逻辑就写在这里,然后将结果通过广播或者EventBus发送出去。
	//当然我们也可以自定义自定义一个IntentService,在里面添加实现逻辑所需要的参数和方法,但对异	
	//步任务的处理方式都大同小异
	@WorkerThread protected abstract void onHandleIntent(@Nullable Intent intent);
}

使用bindService启动IntentService的时候要注意,在该模式下,IntentService执行完耗时操作后不会自动的调用onDestroy()方法自行销毁,这个时候我们需要自己手动调用unbindService()方法解绑并销毁它,以防意外出现而不能销毁服务。

IntentService为什么只能用StartService来开启服务?

因为传递的intent最后都会封装成message由serviceHandler发送到消息队列,而serviceHandler发送的过程是在onStartCommand中完成的,而只有startService方法启动的Service才会执行onStartCommand()方法。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值