引言

Service服务是Android四大组件之中的一个,在Android中有着举足重轻的作用。Service服务是工作的UI线程中,当你的应用须要下载一个文件或者播放音乐等长期处于后台工作而有没有UI界面的时候,你肯定要用到Service+Thread来实现。

因此你须要自己在Service服务里面实现一个Thread工作线程来下载文件或者播放音乐。然而你每次都须要自己去写一个Service+Thread来处理长期处于后台而没有UI界面的任务。这样显得非常麻烦,不是必需每次都去构建一个Service+Thread框架处理长期处于后台的任务。Googleproject师给我们构建了一个方便开发人员使用的这么一个框架—IntentService。

IntentService简单介绍

IntentService是一个基础类,用于处理Intent类型的异步任务请求。当client调用android.content.Context#startService(Intent)发送请求时,Service服务被启动,且在其内部构建一个工作线程来处理Intent请求。当工作线程运行结束,Service服务会自己主动停止。IntentService是一个抽象类,用户必须实现一个子类去继承它,且必须实现IntentService里面的抽象方法onHandleIntent来处理异步任务请求。

IntentServic演示样例

Client代码

public class ClientActivity extends AppCompatActivity {

    @Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} //client同一时候发送两个任务到IntentService服务端运行
public void send(View view) {
Intent intent = new Intent(this, DownLoadService.class);
intent.putExtra("key", 1);
intent.putExtra("value", "the first task1");
startService(intent); Intent intent1 = new Intent(this, DownLoadService.class);
intent1.putExtra("key", 2);
intent1.putExtra("value", "the second task2");
startService(intent1);
}
}

模拟两个异步任务同一时候请求,通过Intent实例携带数据启动Service服务。

Serviceclient

public class DownLoadService extends IntentService {

    public static final String TAG = "DownLoadService";
//重写默认的构造方法
public DownLoadService() {
super("DownLoadService");
} //在后台线程运行
@Override
protected void onHandleIntent(Intent intent) {
int key = intent.getIntExtra("key", 0);
String value = intent.getStringExtra("value");
switch (key) {
case 1:
//模拟耗时任务1
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
case 2:
//模拟耗时任务1
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
default:
break;
} Log.e(TAG, "\nthe current time is: " + System.currentTimeMillis()/1000
+ "\nthe Thread id is " + Thread.currentThread().getId()
+ "\nthe current task is " + value);
}
}

DownLoadService子类继承IntentService类,然后实现onHandleIntent抽象方法进行处理Intent请求的异步任务。在服务端DownLoadService类中。我们并没有创建Thread线程去运行异步耗时任务请求。

全部的异步耗时任务都是在onHandleIntent抽象方法中实现了。言外之意是IntentService类内部已经帮开发人员搭建好了一个异步任务处理器,用户仅仅需实现当中的onHandleIntent抽象方法去处理异步任务就可以。从而让开发人员更加简单方便的使用IntentService处理后台异步任务请求。那么IntentService内部是怎么搭建异步任务处理器的呢?我们最好还是查看源代码来窥探个到底。

IntentService源代码分析

IntentService构造方法

 /**
* 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对象。參数name用于定义工作线程的名称,仅仅用于调式作用。我们知道Service服务的生命周期是从onCreate方法開始的。那么就来看看IntentService#onCreate方法吧。

IntentService#onCreate方法

 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();
mServiceHandler = new ServiceHandler(mServiceLooper);
}

分析:该方法首先利用HandlerThread类创建了一个循环的工作线程thread,然后将工作线程中的Looper对象作为參数来创建ServiceHandler消息运行者。由还有一篇博客Android HandlerThread 源代码分析可知。HandlerThread+Handler构建成了一个带有消息循环机制的异步任务处理机制。

因此开发人员就能够将异步任务封装成消息的形式发送到工作线程中去运行了。

Service服务生命周期第二步运行IntentService#onStartCommand方法。

IntentService#onStartCommand方法

    /**
* 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(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

分析:在IntentService子类中你无需重写该方法。

然后你须要重写onHandlerIntent方法。系统会在IntentService接受一个请求開始调用该方法。我们看到在该方法中仅仅是调用了onStart方法而已。跟踪代码:

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

分析:该方法中通过mServiceHandler获得一个消息对象msg。然后将startId作为该消息的消息码,将异步任务请求intent作为消息内容封装成一个消息msg发送到mServiceHandler消息运行者中去处理,那么我们来看看mServiceHandler的实现吧!

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

分析:实现也比較简单。ServiceHandler是IntentService的内部类,在重写消息处理方法handlerMessage里面调用了onHandlerIntent抽象方法去处理异步任务intent的请求,当异步任务请求结束之后。调用stopSelf方法自己主动结束IntentService服务。看过博客Android HandlerThread 源代码分析的人都应该知道,此处handleMessage方法是在工作线程中调用的,因此我们子类重写的onHandlerIntent也是在工作线程中实现的。我们来看看onHandlerIntent方法:

/**
* 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 {@link #stopSelf}.
*
* @param intent The value passed to {@link
* android.content.Context#startService(Intent)}.
*/
protected abstract void onHandleIntent(Intent intent);

分析:该方法用于处理intent异步任务请求,在工作线程中调用该方法。每个时刻仅仅能处理一个intent请求,当同一时候又多个intent请求时。也就是client同一时候多次调用Content#startService方法启动同一个服务时。其它的intent请求会临时被挂起。直到前面的intent异步任务请求处理完毕才会处理下一个intent请求。

直到全部的intent请求结束之后,IntentService服务会调用stopSelf停止当前服务。

也就是当intent异步任务处理结束之后。相应的IntentService服务会自己主动销毁。进而调用IntentService#onDestroy方法:

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

该方法中调用HandlerThread工作线程中Looper对象的quit方法让当前工作线程HandlerThread退出当前Looper循环。进而结束线程。

进而结束当前IntentService服务。到此,整个IntentService服务结束。如今能够用一张流程图来描写叙述整个步骤例如以下:

IntentService总结

  1. 子类需继承IntentService而且实现里面的onHandlerIntent抽象方法来处理intent类型的任务请求。

  2. 子类须要重写默认的构造方法,且在构造方法中调用父类带參数的构造方法。

  3. IntentService类内部利用HandlerThread+Handler构建了一个带有消息循环处理机制的后台工作线程。client仅仅需调用Content#startService(Intent)将Intent任务请求放入后台工作队列中,且client无需关注服务是否结束,非常适合一次性的后台任务。比方浏览器下载文件,退出当前浏览器之后,下载任务依旧存在后台。直到下载文件结束,服务自己主动销毁。
  4. 仅仅要当前IntentService服务没有被销毁,client就能够同一时候投放多个Intent异步任务请求,IntentService服务端这边是顺序运行当前后台工作队列中的Intent请求的。也就是每一时刻仅仅能运行一个Intent请求。直到该Intent处理结束才处理下一个Intent。由于IntentService类内部利用HandlerThread+Handler构建的是一个单线程来处理异步任务。

【转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树】

Android IntentService的使用和源代码分析的更多相关文章

  1. Android IntentService的使用和源码分析

    引言 Service服务是Android四大组件之一,在Android中有着举足重轻的作用.Service服务是工作的UI线程中,当你的应用需要下载一个文件或者播放音乐等长期处于后台工作而有没有UI界 ...

  2. Android Debuggerd 简要介绍和源码分析(转载)

    转载: http://dylangao.com/2014/05/16/android-debuggerd-%E7%AE%80%E8%A6%81%E4%BB%8B%E7%BB%8D%E5%92%8C%E ...

  3. Android AsyncTask运作原理和源码分析

    自10年大量看源码后,很少看了,抽时间把最新的源码看看! public abstract class AsyncTask<Params, Progress, Result> {     p ...

  4. quartz群调查调度机制和源代码分析

    pageId=85056282#quartz集群调度机制调研及源代码分析-quartz2.2.1集群调度机制调研及源代码分析" style="color:rgb(59,115,17 ...

  5. Android IntentService全然解析 当Service遇到Handler

    转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/47143563: 本文出自:[张鸿洋的博客] 一 概述 大家都清楚.在Andro ...

  6. Android代码分析工具lint学习

    1 lint简介 1.1 概述 lint是随Android SDK自带的一个静态代码分析工具.它用来对Android工程的源文件进行检查,找出在正确性.安全.性能.可使用性.可访问性及国际化等方面可能 ...

  7. android widget 开发实例 : 桌面便签程序的实现具体解释和源代码 (上)

    如有错漏请不吝拍砖指正,转载请注明出处,很感谢 桌面便签软件是android上经常使用软件的一种,比方比較早的Sticky Note,就曾很流行, Sticky Note的介绍能够參见 http:// ...

  8. Android艺术——Bitmap高效加载和缓存代码分析(2)

    Bitmap的加载与缓存代码分析: 图片的压缩 比如有一张1024*768像素的图像要被载入内存,然而最终你要用到的图片大小其实只有128*96,那么我们会浪费很大一部分内存,这显然是没有必要的,下面 ...

  9. Java太阳系小游戏分析和源代码

    Java太阳系小游戏分析和源代码 -20150809 近期看了面向对象的一些知识.然后跟着老师的解说做了一个太阳系各行星绕太阳转的小游戏,来练习巩固一下近期学的知识: 用到知识点:类的继承.方法的重载 ...

随机推荐

  1. Android圆弧背景

    代码改变世界 Android圆弧背景 <?xml version="1.0" encoding="utf-8"?><shape xmlns:a ...

  2. leetcode 349 map

    只需要用map来标记1,今儿通过map的值来得到重叠的部分 class Solution { public: vector<int> intersection(vector<int& ...

  3. java面试题之hashcode相等两个类一定相等吗?equals呢?相反呢?

    答:hashcode相等,两个类不一定相等,equals也不一定相等: 反过来,equals相等,hashcode一定相等

  4. bzoj3196 二逼平衡树 树套树(线段树套Treap)

    Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 4697  Solved: 1798[Submit][Status][D ...

  5. android开发里跳过的坑——TimePickerDialog onTimeSet不回调

    在android6.0.1上测试发现TimePickerDialog的onTimeSet和DatePickerDialog的onDateSet不回调,查看SDK源码发现,TimePickerDialo ...

  6. MATLAB(1)

    前言 之前经常用MATLAB,却不小心停留在了舒适区,连基本的调试方法都没有掌握.本文主要是对MATLAB程序调试中的一般方法进行总结,也是自己学习的记录.全文大致分为三个段落: 1)代码内调试: 2 ...

  7. spring 容器bean

    bean配置信息----> 读取bean的配置信息到bean的注册表中---> 根据注册表的信息实例化bean---> 将bean的实例放到spring的容器中---> 应用程 ...

  8. android图片上传

    package com.example.center; import java.io.ByteArrayOutputStream;import java.io.InputStream; import ...

  9. mac 获得进程信息的方法

    NSProcessInfo可以获得当前进程的信息.获得所有活动进程信息可以尝试使用下面的方法. 进程的信息可以通过ps命令得到也可以通过sysctl方法得到. 但是我总是不能获取进程的流量信息,关于这 ...

  10. codevs——2370 小机房的树

    2370 小机房的树  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题解       题目描述 Description 小机房有棵焕狗种的树,树上有N个 ...