Android开发--IntentService的用法,你错过了什么

IntentService是Android中提供的后台服务类,我们在外部组件中通过Intent向IntentService发送请求命令,之后IntentService逐个执行命令队列里的命令,接收到首个命令时,IntentService就开始启动并开始一条后台线程执行首个命令,接着队列里的命令将会被顺序执行,最后执行完队列的所有命令后,服务也随即停止并被销毁。

与Service的不同

  1. Service中的程序仍然运行于主线程中,而在IntentService中的程序运行在我们的异步后台线程中。在接触到IntentService之前,我在项目中大多是自己写一个Service,在Service中自己写一个后台线程去处理相关事务,而这些工作Android其实早已经帮我们封装的很好。
  2. 在Service中当我的后台服务执行完毕之后需要在外部组件中调用stopService方法销毁服务,而IntentService并不需要,它会在工作执行完毕后自动销毁。

IntentService的用法

1.编写自己的Service类继承IntentService,并重写其中的onHandleIntent(Intent)方法,该方法是IntentService的一个抽象方法,用来处理我们通过startService方法开启的服务,传入参数Intent就是开启服务的Intent。在这里我重写了一个MyService类去处理后台事务,每一次调用对count加1,并打印log。

package com.example.intentservicetest;

import android.app.IntentService;
import android.content.Intent;
import android.util.Log;

public class MyService extends IntentService {

    private static final String TAG = MyService.class.getSimpleName();

    private int count = 0;

    public MyService() {
        super(TAG);
        // TODO Auto-generated constructor stub
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // TODO Auto-generated method stub
        //在这里添加我们要执行的代码,Intent中可以保存我们所需的数据,
        //每一次通过Intent发送的命令将被顺序执行
        count ++;
        Log.w(TAG, "count::" + count);
    }
}

2.注册我们的服务:接下来在AndroidManifest文件中的Application标签下添加我们的服务。

<service android:name="com.example.intentservicetest.MyService" />

3.在外部组件中开启服务:在这里我们在Activity中利用Intent循环10次开启服务。

for (int i = 0; i < 10; i++) {
        Intent intent = new Intent(MainActivity.this, MyService.class);
        startService(intent);
}

4.结果输出:

可以看到在MyService中是按照顺序执行我们的请求命令的。

原理分析

1.生命周期函数:

IntentService同样是继承于Service的,它也拥有相同的生命周期函数;

  • onCreate:服务创建时调用;
  • onStartCommand(Intent, int, int)方法:在Service源码可以看到onStart方法是在该方法中被调用的。每次组件通过startService方法启动服务时调用一次,两个int型参数,一个是组标识符,一个是启动ID,组标识符用来表示当前Intent发送是一次重新发送还是一次从没成功过的发送。每次调用onStartCommand方法时启动ID都不同,启动ID也用来区分不同的命令;
  • onDestroy方法:在服务停止时调用。

2.onCreate方法:首先让我们看看IntentService源码中的onCreate方法,

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

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

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

可以看到:在IntentService的onCreate方法中开启了一个异步线程HandlerThread来处理我们的请求,并利用Looper和Handler来管理我们的请求命令队列。关于HandlerThread的用法可以参考以下博文:Android源码分析–Handler和Looper机制详解

3.如何停止服务

看到了onCreate方法我们就可以明白了,IntentService是如何开启异步线程以及如何管理命令队列的,那么我们之前曾提到:当后台服务处理结束后,我们并不需要再调用stopService方法销毁服务,IntentService会自动销毁,它是如何做到的呢?然我们看看ServiceHandler:

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);
        }
    }

在Handler中我们处理完每一个命令都会调用stopSelf(int)方法来停止服务:该方法需要来自onStartCommand方法中的启动ID,只有在接收到最新的启动ID时才会停止服务,就是说,我们的IntentService直到命令队列中的所有命令被执行完后才会停止服务。

setIntentRedelivery方法

在源码中我们可以发现,该方法改变了boolean变量mRedelivery的值,而mRedelivery得值关系到onStartCommand的返回变量:

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

可以看到,mRedelivery不同,会返回两个不同的标志START_REDELIVER_INTENT 和START_NOT_STICKY,那么他们有什么不同呢?

区别就在于如果系统在服务完成之前关闭它,则两种类型就表现出不同了:

  • START_NOT_STICKY型服务会直接被关闭,而START_REDELIVER_INTENT 型服务会在可用资源不再吃紧的时候尝试再次启动服务。
  • 由此我们可以发现,当我们的操作不是十分重要的时候,我们可以选择START_NOT_STICKY,这也是IntentService的默认选项,当我们认为操作十分重要时,则应该选择START_REDELIVER_INTENT 型服务。

non-sticky服务和sticky服务

non-sticky服务会在自己认为任务完成时停止,若一个Service为non-sticky服务则应该在onStartCommand方法中返回START_REDELIVER_INTENT或START_NOT_STICKY标志。

sticky服务会持续存在,直到外部组件调用Context.stopService方法。sticky服务返回标志位START_STICKY。

注意:IntentService不应该处理长时间运行的服务(如音乐播放),长时间运行的服务应该由sticky服务完成。

时间: 2024-11-08 21:25:06

Android开发--IntentService的用法,你错过了什么的相关文章

Android开发资源文件用法小结

本文用来记录在Android开发中经常用到的一些用法 arrays.xml定义数组 例: <resources> <!-- share items --> <string-array name="app_share_items"> <item>新浪微博</item> <item>腾讯微博</item> </string-array> </resources> 纯色圆角背景 <

.Net程序员玩转Android开发---(17)Handler用法

在android开发中,如果在一个线程中想更新主界面中控件显示的数据,直接给主界面控件赋值就会出现异常,android中为了安全起见,是不允许在线程中更新界面控件的数据,遇到这种情况,我们可以使用Handler.  Handler就是处理界面和线程间的消息传递,通信的组件.下面我们演示下handler处理详细的两种办法

android开发中SharedPreferences用法详解(含源代码和运行结果截图)

在Android应用程序开发中,经常需要保存一些类似于配置信息的简单类型数据,比如游戏玩家的积分.是否开启音效等.SharedPreferences类为我们保存.读取这些数据提供了便利. SharedPreferences接口提供以下常用方法来访问SharedPreferences对象中的key-value对: boolean contains(String key):判断SharedPreferences对象是否包含键值为key的数据. boolean getXxx(String key, x

Android开发中XRecyclerview用法及遇到的一些问题

目前通过xrecyclerview的开源代码来实现系列功能,加载数据传入type,值为1,2,3,分别表示初次加载,下拉刷新数据,上拉加载更多数据操作,刷新数据只需要重新放入数据,然后notifyDataSetChanged();即可.加载更多数据只需要在上拉时将获取数据放入之前数据list中刷新数据即可.这么说可能会比较抽象,下面通过代码来具体给大家演示一下是如何实现的吧. 核心代码: 首先需要配置xRecyclerview的属性: xRecyclerView.setPullRefreshEn

Android开发:SurfaceView基本用法总结

本文主要讲解如何使用SurfaceView,旨在帮助大家快速上手SurfaceView开发.由于上篇文章<Android开发:SurfaceView基本用法总结及开发问题分享> 排版不佳,所以另起一篇单独介绍SurfaceView的基本用法总结. 转载请注明作者xiong_it和链接:http://blog.csdn.net/xiong_it/article/details/45966309,谢谢! SurfaceView基本介绍 1.系统给SurfaceView提供了一个专门绘图的Surfa

Android开发技巧之viewstub用法详解及实现延迟加载

这一篇是接着上面的include标签的例子来讲的,地址http://blog.csdn.net/jason0539/article/details/26131831 上一篇的布局中间就用了viewstub这个控件,现在来说一下其作用和用法 " ViewStub 是一个不可见的,大小为0的View,最佳用途就是实现View的延迟加载,避免资源浪费,在需要的时候才加载View " 需要注意的是,加载view之后,viewstub本身就会被新加载进来的view替换掉 上代码了,看完就理解了

围观:开发者不容错过的十二大Android开发资源

摘要:无论你是初出茅庐的新人,还是富有经验的Android开发者,最忌讳的就是闭门造车,作为一个开发者,不能把自己圈在自己的思维模式中,要学会借助外界的资源去协助自己,以助于提高自己的工作效率. 借着周一这个新一周工作的开始,DEV资讯小编在这里给各位Android开发者介绍的资源包括工具.库和网站等.有效地利用它们,将有助于减轻我们的工作量,提高我们的工作效率. 1.OkHttp OkHttp是Square的一款产品,是一个Java的开源HTTP和SPDY客户端开发包,支持Android.An

Android开发之日期、时间选择器(DatePicker和TimePicker)的功能和用法

日期.时间选择器(DatePicker和TimePicker)的功能和用法 DatePicker和TimePicker是两个比较常用的控件,它们都从FrameLayout派生而来,其中DatePicker用于选择日期.TimePicker用于选择时间. DatePicker和TimePicker在FrameLayout的基础上提供了一些方法来获取当前用户所选择的日期.时间:开发者可以通过为DatePicker添加OnDateChangedListener.为TimePicker添加OnTimeC

Android开发实践:实战演练隐式Intent的用法

本文通过完成一个实战任务,来掌握Android开发中隐式Intent的用法. 任务:假设我们已经实现了一个视频播放器(PlayerActivity),我们希望能把它注册到系统中,当用户点击本地视频或者在线视频时,能启动这个视频播放器. (假设该类的全路径为:com.jhuster.videoplayer.PlayerActivity) [注]:本文完整的示例代码请到我的Github下载,地址:VideoPlayer 1. 什么是隐式Intent? Intent是Android中比较重要的组件,常