Android IntentService使用全面介绍及源码解析

一 IntentService介绍

IntentService定义的三个基本点:是什么?怎么用?如何work?

官方解释如下:

//IntentService定义的三个基本点:是什么?怎么用?如何work?*/

1、IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. 2、Clients send requests through startService(Intent) calls;
3、the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.

//解释了IntentService的好处,以及How to use IntentService*/

This "work queue processor" pattern is commonly used to offload tasks from an application‘s main thread. The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.

All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application‘s main loop), but only one request will be processed at a time.

总结IntentService的特点如下:

1、IntentService是Service类的子类,用来处理异步请求。

2、客户端可以通过startService(Intent)方法传递请求给IntentService

3、IntentService在onCreate()函数中通过HandlerThread单独开启一个线程来处理所有Intent请求对象(通过startService的方式发送过来的)所对应的任务,这样以免事务处理阻塞主线程。

4、执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动停止Service;否则执行下一个Intent请求所对应的任务。

5、IntentService在处理事务时,还是采用的Handler方式,创建一个名叫ServiceHandler的内部Handler,并把它直接绑定到HandlerThread所对应的子线程。 ServiceHandler把处理一个intent所对应的事务都封装到叫做onHandleIntent的虚函数;因此我们直接实现虚函数onHandleIntent,再在里面根据Intent的不同进行不同的事务处理就可以了。

IntentService最重要的一个方法onHandleIntent:

This method is invoked on the worker thread with a request to process. Only one Intent is processed at a time, but the processing happens on a worker thread that runs independently from other application logic. So, if this code takes a long time, it will hold up other requests to the same IntentService, but it will not hold up anything else. When all requests have been handled, the IntentService stops itself, so you should not call stopSelf().

1、该函数用于针对Intent的不同进行不同的事务处理.执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,

则自动停止Service;否则ServiceHandler会取得下一个Intent请求传人该函数来处理其所对应的任务。

2、所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),但是同一时间只处理一个请求。

IntentService的特点、优点、缺点?

IntentService的特点:

1、IntentService是借助于消息队列实现的,所以任务的执行顺序就是一个queue的形式;
2、由于是单线程(一个工作线程),所以所有的任务需要排队执行;/
3、避免了我们再去创建线程和管理service的结束工作;

基于以上,IntentService与Service比较的好处有:

第一,使用方便,代码简洁,不再需要我们自己像Service里面还要去手动创建线程;
第二,当操作完成时,我们不用手动停止Service。

当然,IntentService的缺点也是显而易见:

由于是单个的worker thread,所以任务需要排队,不适合大多数的多任务情况;

二 DEMO实践

DEMO场景描述:

主要由MainActivity和MyIntentService构成,在MainActivity中启动服务,并传递两个参数a和b,在MyIntentService中获取参数,求和,并通过发送广播的形式向UI返回结果,然后MainActivity在接收到广播之后更新UI。

MainActivity.java主要做了三件事:

  1. 注册/注销广播接收器;
  2. 创建UI和更新UI;
  3. 传递参数,启动MyIntentService;

代码如下:

public class MainActivity extends AppCompatActivity {

    private LinearLayout ll_container;
    private BroadcastReceiver forSumReceiver=new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i("TAG","onReceive ()");
            if(intent.getAction()==Constans.ACTION_RESULT){
                int a=intent.getIntExtra(Constans.A,0);
                int result=intent.getIntExtra(Constans.RESULT,0);
                Log.i("TAG","onReceive --result:"+result);
                handleResult(a,result);
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ll_container= (LinearLayout)findViewById(R.id.ll_container);
        Log.i("TEST","MainActivity:"+android.os.Process.myTid());
        registerBroadcast();
    }

    private void handleResult(int a,int result){
        TextView textView=(TextView)ll_container.findViewWithTag(a);
        String old=textView.getText().toString();
        String newText=old.replaceAll("  正在计算中...",String.valueOf(result)+"  计算Success");
        textView.setText(newText);
    }

    private void registerBroadcast(){
        IntentFilter intentFilter=new IntentFilter();
        intentFilter.addAction(Constans.ACTION_RESULT);
        registerReceiver(forSumReceiver,intentFilter);
    }

    private int a=1;
    public void addTask(View view){
        int b=new Random().nextInt(101)+1;
        MyIntentService.startMyIntentService(this,a,b);
        TextView textView=new TextView(this);
        textView.setText(a+"+"+b+"= "+ "  正在计算中...");
        textView.setTag(a);
        ll_container.addView(textView);
        a++;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(forSumReceiver);
    }
}

MyIntentService用于接收参数,并返回计算的结果:

public class MyIntentService extends IntentService {

    public MyIntentService() {
        //必须实现父类的构造方法
        super("MyIntentService");
    }

    @Override
    public void onCreate() {
        Log.i("TEST","onCreate()");
        super.onCreate();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        Log.i("TEST","onStart()");
        super.onStart(intent, startId);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("TEST","onStartCommand()");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i("TEST", "onBind()");
        return super.onBind(intent);
    }

    @Override
    public void onDestroy() {
        Log.i("TEST","onDestroy()");
        super.onDestroy();
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.i("TEST","onHandleIntent():"+android.os.Process.myTid());
        if (intent!=null){
            String action=intent.getAction();
            if(Constans.ACTION_FOR_SUM.equals(action)){
                int a=intent.getIntExtra(Constans.A,0);
                int b=intent.getIntExtra(Constans.B,0);
                int result=a+b;
                Log.i("TEST","result: "+result);
                handleResult(a,result);
            }
        }
    }

    private void handleResult(int a,int result){
        try{
            //模拟计算耗时
            Thread.sleep(3000);
            Intent intent=new Intent(Constans.ACTION_RESULT);
            intent.putExtra(Constans.RESULT,result);
            intent.putExtra(Constans.A,a);
            sendBroadcast(intent);
        }catch (InterruptedException e){
            e.printStackTrace();;
        }
    }

    public static void startMyIntentService(Context context,int a,int b){
        Intent intent=new Intent(context,MyIntentService.class);
        intent.setAction(Constans.ACTION_FOR_SUM);
        intent.putExtra(Constans.A,a);
        intent.putExtra(Constans.B,b);
        context.startService(intent);
    }

}

IntentService生命周期方法执行顺序如下:

07-08 10:18:51.579 com.troy.intentservicedemo I/TEST: MainActivity:30060
07-08 10:19:26.009 com.troy.intentservicedemo I/TEST: onCreate()
07-08 10:19:26.009 com.troy.intentservicedemo I/TEST: onStartCommand()
07-08 10:19:26.009 com.troy.intentservicedemo I/TEST: onStart()
07-08 10:19:26.039 com.troy.intentservicedemo I/TEST: onHandleIntent():30223
07-08 10:19:26.039 com.troy.intentservicedemo I/TEST: result: 23
07-08 10:19:29.100 com.troy.intentservicedemo I/TEST: onDestroy()
07-08 10:19:31.839 com.troy.intentservicedemo I/TEST: onCreate()
07-08 10:19:31.849 com.troy.intentservicedemo I/TEST: onStartCommand()
07-08 10:19:31.849 com.troy.intentservicedemo I/TEST: onStart()
07-08 10:19:31.869 com.troy.intentservicedemo I/TEST: onHandleIntent():30305
07-08 10:19:31.869 com.troy.intentservicedemo I/TEST: result: 52
07-08 10:19:34.899 com.troy.intentservicedemo I/TEST: onDestroy()

从上面Log中可以看出:

  1. UI线程的线程ID=30060,而onHandleIntent()的线程ID分别是30223,30305;由此知道onHandleIntent()方法是执行在工作线程中的;
  2. 并且IntentService的所有请求如果是在一个生命周期中完成的话,则所有请求是在一个工作线程中顺序执行的。否则,是在不同的工作线程中完成。
  3. 同时验证了:执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动停止Service;

运行效果如图:

三 IntentService源码简单解析

IntentService是Service的子类,拥有Service的所有生命周期方法;同时还有自己的ServiceHandler;

ServiceHandler相关源码如下:

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;//volatile关键字保证同步,保证可见性
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

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

IntentService 实际上是Looper,Handler,Service 的集合体,他不仅有服务的功能,还有处理和循环消息的功能。

onCreate()的源码:创建了一个HandlerThread

 @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对象来初始化IntentService的mServiceLooper,接着创建mServicehandler对象。

下面是onStart()的源码: 调用mServiceHandler

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

                mServiceHandler.sendMessage(msg);
        }

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

handleMessage处理的代码如下:

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

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

stopSelf(msg.arg1):

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

当所有的工作执行完后:就会执行onDestroy方法。

onDestroy源码如下:

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

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

最后总结一下上述的分析:

1、 IntentService是一个基于消息的服务,每次启动该服务并不是马上处理你的工作,而是首先会创建对应的Looper,Handler并且在MessageQueue中添 加的附带客户Intent的Message对象, 当Looper发现有Message的时候接着得到Intent对象通过在 onHandleIntent((Intent)msg.obj)中调用你的处理程序. 处理完后即会停止自己的服务. 意思是Intent的生命周期跟你的 处理的任务是一致的. 所以这个类用下载任务中非常好,下载任务结束后服务自身就会结束退出。

2、IntentService是不适合用于bindService()这样的启动方式的。其次我们通过startService多次启动Service时,相当于在MessageQueue中添加了多个任务,就可以实现多任务按照顺序执行。

3、只有在onHandleIntent()方法中执行的代码才是在工作线程中运行的。IntentService的停止不是因为在handleMessage() 中执行了stopSelf(msg.arg1);而是系统自己停止的。

友谊致谢:

1 Android Service学习之IntentService 深入分析

2 Android IntentService

3 Android IntentService完全解析 当Service遇到Handler

时间: 2024-08-24 04:26:58

Android IntentService使用全面介绍及源码解析的相关文章

【转载】Android IntentService使用全面介绍及源码解析

一 IntentService介绍 IntentService定义的三个基本点:是什么?怎么用?如何work? 官方解释如下: //IntentService定义的三个基本点:是什么?怎么用?如何work?*/ 1.IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. 2.Clients send requests through

【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源热更新 Android热更新开源项目Tinker源码解析系类之三:so热更新 转载请标明本文来源:http://www.cnblogs

Android网络编程(十一)源码解析Retrofit

相关文章 Android网络编程(一)HTTP协议原理 Android网络编程(二)HttpClient与HttpURLConnection Android网络编程(三)Volley用法全解析 Android网络编程(四)从源码解析volley Android网络编程(五)OkHttp2.x用法全解析 Android网络编程(六)OkHttp3用法全解析 Android网络编程(七)源码解析OkHttp前篇[请求网络] Android网络编程(八)源码解析OkHttp后篇[复用连接池] Andr

Android进阶:五、RxJava2源码解析 2

上一篇文章Android进阶:四.RxJava2 源码解析 1里我们讲到Rxjava2 从创建一个事件到事件被观察的过程原理,这篇文章我们讲Rxjava2中链式调用的原理.本文不讲用法,仍然需要读者熟悉Rxjava基本的用法. 一.Rxjava2 的基本用法 Rxjava是解决异步问题的,它的链式调用让代码看起来非常流畅优.现在我们带上线程切换以及链式调用来看看.下面代码是示例: Observable .create(new ObservableOnSubscribe<String>() {

IPerf——网络测试工具介绍与源码解析(4)

上篇随笔讲到了TCP模式下的客户端,接下来会讲一下TCP模式普通场景下的服务端,说普通场景则是暂时不考虑双向测试的可能,毕竟了解一项东西还是先从简单的情况下入手会快些. 对于服务端,并不是我们认为的直接创建服务端线程,而是先创建一个监听者线程,在本地绑定套接字后进行蹲点监听. 在Listener类中,Run成员函数执行一个do-while循环接收等待来自对端的连接,循环中调用Accept函数,该函数会阻塞,直至接收到对端的连接并通过thread_Settings*类型的指针参数返回客户端的信息,

【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 Android热更新开源项目Tinker源码解析系类之三:so文件热更新 转载请标明本文来源:http://www.cnblogs.com/yyangblog/p/6252855.html更多内容欢迎star作者的github:https://github.com/LaurenceYang/artic

Android培训HandlerThread的使用及源码解析

Android培训HandlerThread的使用及源码解析-北京尚学堂 关于Hanlder的基本使用可以参见博文<Android中Handler的使用>,如果想了解Handler.Looper.Thread等的相互关系以及内部实现原理可以参见博文<深入源码解析Android中的Handler,Message,MessageQueue,Looper>. Android中的API中对HandlerThread的描述是: Handy class for starting a new t

IPerf——网络测试工具介绍与源码解析(1)

IPerf是一个开源的测试网络宽带并能统计并报告延迟抖动.数据包丢失率信息的控制台命令程序,通过参数选项可以方便地看出,通过设置不同的选项值对网络带宽的影响,对于学习网络编程还是有一定的借鉴意义,至少可以玩上一段时间. IPerf开始出现的时候是在03年,版本是1.7.0,在网上找到的仅有的系列源码解析篇 http://blog.chinaunix.net/uid/11568125/cid-131106-abstract-1.html 就是基于1.7.0 进行介绍和解析的,貌似1.7.0还是使用

IPerf——网络测试工具介绍与源码解析(2)

对于IPerf源码解析,我是基于2.0.5版本在Windows下执行的情况进行分析的,提倡开始先通过对源码的简单修改使其能够在本地编译器运行起来,这样可以打印输出一些中间信息,对于理解源码的逻辑,程序实现的过程能够起到事半功倍的效果. IPerf主要分为如下几个模块: 选项参数处理: 线程封装和角色扮演: 四种线程模式(或者说角色): 客户端线程: 服务端线程: 报告者线程: 监听者线程. 套接字选项设置与提取: 链表和数组的封装和维护: 处理多并发Condition条件变量的封装: 时间戳封装