IntentService源码分析

IntentService源码分析

概述

   在上一篇的文章中介绍过HandlerThread的源码分析【点这里 】,这篇文章介绍下HandlerThread一个典型应用IntentService。

   我们都知道安卓官方是不建议我们在一个Service的主线程里做耗时操作,所以一般都需要去开启子线程去做一些事情,而自己去管理Service的生命周期以及子线程并非是个优雅的做法,所以安卓给我们提供了一个新的派生服务IntentService,接下来我们来看看IntentService的使用以及源码分析。

基本使用

   一般使用IntentService步骤如下:

// 1. 创建继承IntentService的计类,IntentService为抽象类。
public class PhotoLoadService extends IntentService {

    private static final String TAG = PhotoLoadService.class.getName();

    private LoadPhotoEvent mLoadPhotoEvent;
    private NetModel mNetModel;

    public PhotoLoadService() {
        super(TAG);
        EventBus.getDefault().register(this);
        mLoadPhotoEvent = new LoadPhotoEvent();
        mNetModel = NetModel.getNetModel();
    }

    // 4.生命周期结束,释放资源
    @Override
    public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
        Log.e(TAG, "onDestroy");
    }

    // 2. 实现onHandleIntent()方法,该方法调度线程为子线程,可以执行耗时操作
    @Override
    public void onHandleIntent(Intent intent) {
        String photoLoadUrl = null;
        String photoId = null;
        if (intent != null) {
            photoLoadUrl = intent.getStringExtra(PHOTO_LOAD_URL);
            photoId = intent.getStringExtra(PHOTO_ID);
        }
        File file = new File(Environment.getExternalStorageDirectory() + "/WallPager/" + photoId + ".jpg");
        if (file.exists()) {
            mLoadPhotoEvent.setPhotoId("exist");
            EventBus.getDefault().post(mLoadPhotoEvent);//发送事件,图片文件已存在
            return;
        }
        String dir = Environment.getExternalStorageDirectory() + "/WallPager/";
        String name = photoId + ".jpg";
        String finalPhotoId = photoId;
        Log.e(TAG, photoLoadUrl);
        // 注意这里回调可以通过binder通信实现,这个例子我使用的是eventbus来实现回调消息的。
        mNetModel.getHttpHelper().downloadPicFromNet(photoLoadUrl, new DownLoadCallback(dir, name) {

            @Override
            protected void beforeProgress() {
                super.beforeProgress();
                SharePrefUtil.setBoolean(WallPagerApplications.getContext(), Constants.IS_RUNNING, true);
            }

            @Override
            public void progress(long progress, long total) {
                //Log.e(TAG, "Progress " + progress + " " + total);
                mLoadPhotoEvent.setProgress(progress * 100 / total);
                mLoadPhotoEvent.setPhotoId(finalPhotoId);
                EventBus.getDefault().postSticky(mLoadPhotoEvent);//发送事件,更新UI
            }

            @Override
            public void onSuccess(File file) {
                super.onSuccess(file);
                Log.e(TAG, "Success");
                mLoadPhotoEvent.setMessage("success");
                EventBus.getDefault().post(mLoadPhotoEvent);
                SharePrefUtil.setBoolean(WallPagerApplications.getContext(), Constants.IS_RUNNING, false);
                // 最后通知图库更新
                WallPagerApplications.getContext().sendBroadcast(new Intent(Intent
                        .ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" +
                        file.getAbsolutePath())));
            }

            @Override
            public void onFail(String error) {
                super.onFail(error);
                Log.e(TAG, "Error");
                SharePrefUtil.setBoolean(WallPagerApplications.getContext(), Constants.IS_RUNNING, false);
                mLoadPhotoEvent.setMessage("error");
                EventBus.getDefault().post(mLoadPhotoEvent);
            }
        });
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void doNothing(LoadPhotoEvent event) {
    }
}

// 3. 绑定服务,实现后台逻辑
Intent intent = new Intent(getContext(), PhotoLoadService.class);
intent.setAction(Constants.SERVICE_ACTION);
intent.putExtra(Constants.PHOTO_LOAD_URL, mResult.getUrls().getRaw());
intent.putExtra(Constants.PHOTO_ID, mResult.getId());
getActivity().startService(intent);

   对IntentService使用步骤大概如上述4点,使用比较简单,后续的源码分析时,会简单介绍一些步骤的原理。

源码分析

   为了更好的理解IntentService的使用,下面我们来了解下源码。

   首先来看下构造方法。

public abstract class IntentService extends Service {
    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public IntentService(String name) {
        super();
        mName = name;
    }
}

   可以从类的继承关系看出,IntentService的父类是Service并且是个抽象类,所以我们在实现的时候要继承IntentService。从构造方法,我们看不出什么逻辑,只是简单的设置了个工作线程的名字。

   其次既然是Service,我们就来看看其生命周期的调度。

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        // 创建线程
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        // 利用HandlerThread与Handler机制实现子线程调度
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
    
	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);
		}
	}

   从onCreate()方法可以看到,IntentService内部创建了HandlerThread作为工作线程,然后利用HandlerThread的Looper来创建ServiceHandler,目的是为了处理消息调度,这个原理我们在上一篇介绍HandlerThread已经描述,这里不在赘述。

   既然是消息调度,我们来看看它是如何调度的。

    /**
     * You should not override this method for your IntentService. Instead,
     * override {@link #onHandleIntent}, which the system calls when the IntentService
     * receives a start request.
     * @see android.app.Service#onStartCommand
     */
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        /*
        * START_REDELIVER_INTENT 正常启动意图
        * START_NOT_STICKY 表示进程死掉后,该意图也一并销亡
        * */
        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);
    }
    
     /**
     * Unless you provide binding for your service, you don't need to implement this
     * method, because the default implementation returns null.
     * @see android.app.Service#onBind
     */
    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }
    
    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

   我们都清楚,在使用startService()方式启动Service时会调用onStartCommand()方法,而IntentService中对onStartCommand()方法的描述是让我们不要去重写该方法,因为安卓已经给我设计好了IntentService的功能作用,而在该方法中,我们看到主要调用了onStart()方法,而在onStart()内部通过之前创建Handler向工作线程抛出了一个消息,这个消息里封装了Intent以及开始的Id。

   我们在转过来看Handler的handleMessage()方法,首先调用了onHandleIntent()抽象方法,需子类实现,也正是我在前面使用举例时说的可以做耗时操作的方法,到这里IntentService里的HandlerThread与Handler调度介绍差不多了。当然用过IntentService的人都知道,IntentService会在执行完其任务后会自动销毁,其实也不是什么秘密,正是stopSelf()完成这个操作的。最后在onDestroy()方法中,会将HandlerThread中的Looper停止。

   就此对于IntentService源码分析就此结束,由于笔者技术有限,如果分析过程中有出现错误,欢迎指出,谢谢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值