Android 服务之IntentService 详解

2023-12-17 09:38

本文主要是介绍Android 服务之IntentService 详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • 1. IntentService 概述
  • 2.IntentService如何使用
  • 3. IntentService源码解析

1. IntentService 概述

IntentService继承自Service,所以,我们可以用来执行后台耗时任务。那为什么又要封装一个这样的IntentService呢?下面我们来看看IntentService有什么特点。

  1. 它本质是一种特殊的Service,继承自Service并且本身就是一个抽象类
  2. 它可以用于在后台执行耗时的异步任务,当任务完成后会自动停止
  3. 它拥有较高的优先级,不易被系统杀死(继承自Service的缘故),因此比较适合执行一些高优先级的异步任务
  4. 它内部通过HandlerThread和Handler实现异步操作
  5. 创建IntentService时,只需实现onHandleIntent和构造方法,onHandleIntent为异步方法,可以执行耗时操作

2.IntentService如何使用

我们来模拟一个后台加载进度条的例子。为了模拟多任务串行处理,我们进度条会加载两次。
来看看效果:

展示效果

前面我们提到了IntentService是一个抽象类,所以我们第一步就是继承IntentService。
1.我们需要继承IntentService,然后重写onHandleIntent方法。模拟耗时任务就是在onHandleIntent方法中进行处理。下面我们来具体看看这个类,我们取名为:
MyIntentService.java

/*** Created by zhangcong on 2018/3/21.*/public class MyIntentService extends IntentService {private LocalBroadcastManager localBroadcastManager;private boolean isRunning;private int count;/*** Creates an IntentService.**/public MyIntentService() {super("MyIntentService");Log.i("SIMON","MyIntentService");}@Overridepublic void onStart(@Nullable Intent intent, int startId) {super.onStart(intent, startId);Log.i("SIMON","onStart");}@Overridepublic int onStartCommand(@Nullable Intent intent, int flags, int startId) {Log.i("SIMON","onStartCommand");Log.i("SIMON","intent"+intent.getAction());return super.onStartCommand(intent, flags, startId);}@Overridepublic void onCreate() {Log.i("SIMON","onCreate");super.onCreate();localBroadcastManager = LocalBroadcastManager.getInstance(this);}@Overrideprotected void onHandleIntent(@Nullable Intent intent) {Log.i("SIMON","onHandleIntent");//test mutiTaskString firstTask=intent.getStringExtra(MainActivity.INTENT_TAG);Log.i("SIMON",firstTask);try {Thread.sleep(1000);isRunning = true;count = 0;while (isRunning) {count++;if (count >= 100) {isRunning = false;}Thread.sleep(50);sendMessage("线程运行中",count);}} catch (InterruptedException e) {e.printStackTrace();}}/*** send message*/private void sendMessage(String status,int count) {Intent intent=new Intent(MainActivity.ACTION_THREAD);intent.putExtra("status",status);intent.putExtra("count",count);localBroadcastManager.sendBroadcast(intent);}@Overridepublic void onDestroy() {super.onDestroy();Log.i("SIMON","onDestroy");}
}

必须创建一个构造方法,并且调用父类带String的构造方法来创建一个IntentService。
这里我们重写了许多方法,是为了看整个Service的生命周期。后面会贴出log。

2.在activity进行模拟

public class MainActivity extends AppCompatActivity {public final static String ACTION_THREAD = "action.thread";public final static String INTENT_TAG = "com.wind.intent";private TextView textView;private Button button;private ProgressBar progressBar;private TextView percent;private LocalBroadcastManager localBroadcastManager;private MyBroadCastReceiver myBroadCastReceiver;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textView = findViewById(R.id.tv_text);progressBar = findViewById(R.id.pb_progress);percent=findViewById(R.id.tv_percent);button=findViewById(R.id.bt_button);//registerReceiverlocalBroadcastManager = LocalBroadcastManager.getInstance(this);myBroadCastReceiver=new MyBroadCastReceiver();IntentFilter intentFilter=new IntentFilter();intentFilter.addAction(ACTION_THREAD);localBroadcastManager.registerReceiver(myBroadCastReceiver,intentFilter);//initViewtextView.setText("线程状态:未运行");progressBar.setMax(100);progressBar.setProgress(0);percent.setText("0%");button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.i("SIMON","SIMON");Intent intent = new Intent(MainActivity.this, MyIntentService.class);intent.setAction("sss");intent.putExtra(INTENT_TAG,"firstintent");startService(intent);intent.putExtra(INTENT_TAG,"secondintent");startService(intent);//模拟多任务}});}//define broadcastreceiverpublic class MyBroadCastReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {switch (intent.getAction()) {case ACTION_THREAD:int progress = intent.getIntExtra("count", 0);String text = intent.getStringExtra("status");textView.setText(text);percent.setText(progress + "%");progressBar.setProgress(progress);if (progress >= 100) {textView.setText("线程结束");break;}default:break;}}}
}

调用
这里用了一个广播,是用来传递数据的,然后在主线程进行UI的更新。

我们来看下log:

03-22 05:22:11.373 19700-19700/com.wind.intentservice I/SIMON: SIMON
03-22 05:22:11.401 19700-19700/com.wind.intentservice I/SIMON: MyIntentService
03-22 05:22:11.401 19700-19700/com.wind.intentservice I/SIMON: onCreate
03-22 05:22:11.403 19700-19700/com.wind.intentservice I/SIMON: onStartCommand
03-22 05:22:11.403 19700-19700/com.wind.intentservice I/SIMON: onStart
03-22 05:22:11.403 19700-19723/com.wind.intentservice I/SIMON: onHandleIntent
03-22 05:22:11.403 19700-19723/com.wind.intentservice I/SIMON: firstintent
03-22 05:22:11.406 19700-19700/com.wind.intentservice I/SIMON: onStartCommand
03-22 05:22:11.406 19700-19700/com.wind.intentservice I/SIMON: onStart
03-22 05:22:17.562 19700-19723/com.wind.intentservice I/SIMON: onHandleIntent
03-22 05:22:17.562 19700-19723/com.wind.intentservice I/SIMON: secondintent
03-22 05:22:23.746 19700-19700/com.wind.intentservice I/SIMON: onDestroy

这里我们通过startService来启动两次服务,但是我们可以看到,只会实例化一次Service,而是通过onStart和onStartCommand方法来进行多任务的执行。是按照任务的顺序来执行的,最后判断没有任务了,再把服务进行关闭。这里可能会有点困惑,这个是怎么实现的,后面我们会进行源码分析。

3. IntentService源码解析

我们从startService()开始分析,首先调用构造方法来创建IntentService。
然后调用IntentService的onCreate方法:

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

  当第一启动IntentService时,它的onCreate方法将会被调用,其内部会去创建一个HandlerThread并启动它,接着创建一个ServiceHandler(继承Handler),传入HandlerThread的Looper对象,这样ServiceHandler就变成可以处理异步线程的执行类了(因为Looper对象与HandlerThread绑定,而HandlerThread又是一个异步线程,我们把HandlerThread持有的Looper对象传递给Handler后,ServiceHandler内部就持有异步线程的Looper,自然就可以执行异步任务了),那么IntentService是怎么启动异步任务的呢?其实IntentService启动后还会去调用onStartCommand方法,而onStartCommand方法又会去调用onStart方法,我们看看它们的源码:

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

调用onStart方法:

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

  从源码我们可以看出,在onStart方法中,IntentService通过mServiceHandler的sendMessage方法发送了一个消息,这个消息将会发送到HandlerThread中进行处理(因为HandlerThread持有Looper对象,所以其实是Looper从消息队列中取出消息进行处理,然后调用mServiceHandler的handleMessage方法),我们看看ServiceHandler的源码:

 private final class ServiceHandler extends Handler {public ServiceHandler(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message msg) {onHandleIntent((Intent)msg.obj);stopSelf(msg.arg1);}}

 这里其实也说明onHandleIntent确实是一个异步处理方法(ServiceHandler本身就是一个异步处理的handler类),在onHandleIntent方法执行结束后,IntentService会通过 stopSelf(int startId)方法来尝试停止服务。这里采用stopSelf(int startId)而不是stopSelf()来停止服务,是因为stopSelf()会立即停止服务,而stopSelf(int startId)会等待所有消息都处理完后才终止服务。最后看看onHandleIntent方法的声明:

 protected abstract void onHandleIntent(@Nullable Intent intent);

到此我们就知道了IntentService的onHandleIntent方法是一个抽象方法,所以我们在创建IntentService时必须实现该方法,通过上面一系列的分析可知,onHandleIntent方法也是一个异步方法。这里要注意的是如果后台任务只有一个的话,onHandleIntent执行完,服务就会销毁,但如果后台任务有多个的话,onHandleIntent执行完最后一个任务时,服务才销毁。最后我们要知道每次执行一个后台任务就必须启动一次IntentService,而IntentService内部则是通过消息的方式发送给HandlerThread的,然后由Handler中的Looper来处理消息,而Looper是按顺序从消息队列中取任务的,也就是说IntentService的后台任务时顺序执行的,当有多个后台任务同时存在时,这些后台任务会按外部调用的顺序排队执行。到这里我们就彻底明白了IntentService是怎么保证任务按照顺序来执行的。

到这里,我们就讲IntentService的源码分析完了。

这篇关于Android 服务之IntentService 详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/503905

相关文章

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动