Android Service的解析

人不走空

                                                                      

      🌈个人主页:人不走空      

💖系列专栏:算法专题

⏰诗词歌赋:斯是陋室,惟吾德馨

 

Android服务,即Service,是Android四大组件之一,是一种程序后台运行的方案,用于不需要用户交互,长期运行的任务场景。

Service并不是在单独进程中运行,也是运行在应用程序进程的主线程中,在执行具体耗时任务过程中要手动开启子线程,应用程序进程被杀死,所有依赖该进程的服务也会停止运行。

由于ANR对Activity和BroadcastReceiver响应时间的限制(Activity对事件响应不超过5秒,BroadcastReceiver执行不超过10秒),使得在其中都不适合执行较耗时操作,这样像网络、数据库、复杂计算这类耗时操作的执行就需要一个组件来承担。Service作为Android四大组件之一,其功能之一就是耗时操作的执行,主要功能如下:

  1. 执行需要长时间运行的操作,这个操作不与用户进行交互,如网络下载、大文件I/O、复杂计算。

  2. 应用内或应用间数据通信,Android每个应用程序都在自己的dalvik虚拟机中运行,一个应用是不允许访问其他应用的内存信息的,为此Android引入了Content Provider在不同应用间共享数据,BroadcastReceiver广播信息给不同应用程序,但Content Provider更多用于数据的共享,BroadcastReceiver广播的信息会被所有应用接收较耗费系统资源,对于两个应用间动态的进行交互还需要通过Service来完成。

Service的使用

Service的创建和Activity类似,也是通过Intent来实现的,既然是安卓四大组件之一,那么它也需要在清单文件中进行注册的。具体步骤如下。

Service的创建

新建一个TgsService继承自Service,并重写父类的onCreate()、onStartCommand()和onDestroy()方法,如下面的代码所示:

public class TgsService extends Service {
    public static final String TAG = "TgsService";
    @Override    public void onCreate() {        super.onCreate();        Log.d(TAG, "onCreate");    }
    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.d(TAG, "onStartCommand");        return super.onStartCommand(intent, flags, startId);    }
    @Override    public void onDestroy() {        super.onDestroy();        Log.d(TAG, "onDestroy");    }
    @Override    public IBinder onBind(Intent intent) {        return null;    }}

Service的注册

在清单文件中注册它,如下所示:

<service android:name="com.tgs.demo.TgsService"            android:enabled="true"            android:exported="true"/>
  • enabled属性:是指该服务是否能够被实例化。如果设置为true,则能够被实例化,否则不能被实例化。默认值是true,一般情况下,我们都会需要实例化,所以也可以选择不设置。

  • exported属性:用于指示该服务是否能够被其他应用程序组件调用或跟它交互。如果设置为true,则能够被调用或交互(通常如果一个服务需要跨进程使用需要这么设置),设置为false时,只有同一个应用程序的组件或带有相同用户ID的应用程序才能启动或绑定该服务。

Service的启动

接下来创建一个TgsActivity的测试活动,用于在其中创建TgsService对象,并在点击按钮时启动服务,示例代码如下:

public class TgsActivity extends Activity implements View.OnClickListener {
    private Button startBtn;
    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_start);
        startBtn = (Button) findViewById(R.id.btn_start_service);
        startBtn.setOnClickListener(this);    }
    @Override    public void onClick(View v) {        if (v != null) {            switch (v.getId()) {                case R.id.btn_start_service:                    Intent startIntent = new Intent(this, TgsService.class);                    startService(startIntent);                    break;            }        }    }}

Service和Thread

如第一节所介绍的,Service是一个运行于后台的服务,一些比较耗时的操作也可以放在这里运行。而Thread我们大家都知道,是用于开启一个子线程,在这里去执行一些耗时操作就不会阻塞主线程的运行。这就会让人对这两个概念产生混淆了。

Service和Thread到底有什么关系呢?什么时候应该用Service,什么时候又应该用Thread?答案是:Service和Thread之间没有任何关系!前面有提到,Service其实是运行在主线程里的,因此它和Thread并没有关系。

Service与Thread的区别如下:

  1. Service是android的一种机制,当它运行的时候如果是Local Service,那么对应的Service是运行在主进程的main线程上的。如果是Remote Service,那么对应的Service则是运行在独立进程的main线程上。

  2. Thread是程序执行的最小单元,可以用Thread来执行一些异步的操作。

  3. 在应用中,如果是长时间的在后台运行,而且不需要交互的情况下,使用服务。同样是在后台运行,不需要交互的情况下,如果只是完成某个任务,之后就不需要运行,而且可能是多个任务,需要长时间运行的情况下使用线程。

  4. 如果任务占用CPU时间多,资源大的情况下,要使用线程。

那么如果用户既想使用Service的优点,又想使用Thread的优点,要怎么实现?关于这一点,Google已经帮我们想到了。即下节要介绍的IntentService。

IntentService

IntentService的概念

IntentService是Android中的一个系统封装类,继承自四大组件之一的Service,主要用于处理异步请求,实现多线程,它有以下特点:

  1. 是一种特殊的Service,继承自Service并且本身就是一个抽象类。

  2. 用于在后台执行耗时的异步任务,当任务完成后会自动停止。

  3. 有较高的优先级,不易被系统杀死(继承自Service的缘故),因此比较适合执行一些高优先级的异步任务。

  4. 内部通过HandlerThread和Handler实现异步操作。

  5. 创建IntentService时,只需实现onHandleIntent和构造方法,onHandleIntent为异步方法,可以执行耗时操作。

IntentService的创建

编写自己的Service类继承IntentService,并重写其中的onHandleIntent(Intent)方法,该方法是IntentService的一个抽象方法,用来处理我们通过startService方法开启的服务,传入参数Intent就是开启服务的Intent,如下所示:

public class TgsIntentService extends IntentService {
    private static final String TAG = TgsIntentService.class.getSimpleName();
    public TgsService() {        super(TAG);    }
    @Override    protected void onHandleIntent(Intent intent) {        // 在这里添加我们要执行的异步代码    }}

IntentService的注册

接下来在AndroidManifest文件中的Application标签下添加刚刚创建的服务,如下所示:

<service android:name="com.tgs.demo.TgsIntentService" />

IntentService的启动

然后创建一个TgsActivity的测试活动,并在点击按钮时调用startService系统函数来开启IntentService的服务,示例代码如下:

public class TgsActivity extends Activity implements View.OnClickListener {
    private Button startIntentServiceBtn;
    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_start);
        startIntentServiceBtn = (Button) findViewById(R.id.btn_start_intent_service);
        startIntentServiceBtn.setOnClickListener(this);    }
    @Override    public void onClick(View v) {        if (v != null) {            switch (v.getId()) {                case R.id.btn_start_intent_service:                    Intent intent = new Intent(TgsActivity.this, TgsIntentService.class);                    startService(intent);                    break;            }        }    }}

Service的终止

一个已经启动了的Service必须管理它自己的生命期,系统不会停止或销毁这种Service,除非内存不够用了。Service在onStartCommand()返回后会继续运行。所以,service必须调用stopSelf()停止自己或由另一个组件调用stopService()来停止它。

一旦通过stopSelf()或stopService()发出了停止请求,系统就会尽可能快地销毁service。

关于Service的终止,需要注意以下几点:

  1. startService要stopSelf或者stopService才能终结。

  2. bindService要组件全部解绑后才会终结。

  3. 低内存的时候系统会主动停止和回收后台Service。

  4. 前台service很少被系统杀死,后台service随着时间推移变得更加可能被系统杀死。

  5. service被杀后会重启,但是取决于onStartCommand的返回值。

接下来创建一个TgsActivity的测试活动,用于在其中创建TgsService对象,并在点击按钮时停止服务,示例代码如下:​​​​​​​

public class TgsActivity extends Activity implements View.OnClickListener {
    private Button stopBtn;
    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_start);
        stopBtn = (Button) findViewById(R.id.btn_stop_service);
        stopBtn.setOnClickListener(this);      }
    @Override    public void onClick(View v) {        if (v != null) {            switch (v.getId()) {                case R.id.btn_stop_service:                    Intent stopIntent = new Intent(this, TgsService.class);                    stopService(stopIntent);                    break;                      }        }    }}

参考链接

  • https://developer.android.com/reference/android/app/Service

  • https://developer.android.com/reference/android/app/Service#WhatIsAService

  • https://developer.android.com/reference/android/app/Service#ServiceLifecycle

  • https://developer.android.com/reference/android/app/Service#Permissions

  • https://developer.android.com/reference/android/app/Service#ProcessLifecycle

  • https://developer.android.com/reference/android/app/Service#LocalServiceSample

  • https://developer.android.com/reference/android/app/Service#RemoteMessengerServiceSample

客户端27

Android开发12

客户端 · 目录

上一篇Android多线程的种类及使用方法下一篇Android组件之ContentProvider


作者其他作品:

【Java】Spring循环依赖:原因与解决方法

OpenAI Sora来了,视频生成领域的GPT-4时代来了

[Java·算法·简单] LeetCode 14. 最长公共前缀 详细解读

【Java】深入理解Java中的static关键字

[Java·算法·简单] LeetCode 28. 找出字a符串中第一个匹配项的下标 详细解读

了解 Java 中的 AtomicInteger 类

算法题 — 整数转二进制,查找其中1的数量

深入理解MySQL事务特性:保证数据完整性与一致性

Java企业应用软件系统架构演变史​​​​​​​ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/46566.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新增支持GIS地图、数据模型引擎升级、增强数据分析处理能力

为了帮助企业提升数据分析处理能力&#xff0c;Smartbi重点围绕产品易用性、用户体验、操作便捷性进行了更新迭代&#xff0c;同时重磅更新了体验中心。用更加匹配项目及业务需求的Smartbi&#xff0c;帮助企业真正发挥数据的价值&#xff0c;赋能决策经营与管理。 Smartbi用户…

js中使用原型链增加方法后,遍历对象的key-value时会遍历出方法

原因&#xff1a;js使用原型链实现方法时&#xff0c;这个方法默认是可迭代的&#xff0c;所以在遍历时就会被遍历出来&#xff0c; 例&#xff1a; Array.prototype.remove function(n){return this.slice(0,n).concat(this.slice(n1,this.length));}var cc ["cccaaaa…

wifi信号处理的CRC8、CRC32

&#x1f9d1;&#x1f3fb;个人简介&#xff1a;具有3年工作经验&#xff0c;擅长通信算法的MATLAB仿真和FPGA实现。代码事宜&#xff0c;私信博主&#xff0c;程序定制、设计指导。 &#x1f680;wifi信号处理的CRC8、CRC32 目录 &#x1f680;1.CRC概述 &#x1f680;1.C…

定时器的计数模式 定时器中断时钟配置

目录 一&#xff0c;定时器的计数模式 二&#xff0c;定时器中断时钟的配置 三&#xff0c;输入和输出原理 四&#xff0c;PWM波的小简介 一&#xff0c;定时器的计数模式 1.1 定时器的计数模式分别有三种 1.2 定时器溢出的时间&#xff08;中断&#xff0c;事件产生的时间…

QT多线程下,信号槽分别在什么线程中执行,如何控制?

可以通过connect的第五个参数进行控制信号槽执行时所在的线程 connect有几种连接方式&#xff0c;直接连接、队列连接和 自动连接 直接连接&#xff08;Qt::DirectConnection&#xff09;&#xff1a;信号槽在信号发出者所在的线程中执行 队列连接&#xff08;Qt::QueuedConn…

python初学者知识点笔记更新

文章目录 1.main函数入口2.__init__.py 文件作用3.from .applications import server解释4.变量没有修饰&#xff0c;直接创建使用1. 内置数据类型和函数2. 类和对象3.总结 5.mod app.__module__6.集合对比区分集合类型&#xff1a;混合集合类型 7.安装包失败 1.main函数入口 …

vitest 单元测试应用与配置

vitest 应用与配置 一、简介 Vitest 旨在将自己定位为 Vite 项目的首选测试框架&#xff0c;即使对于不使用 Vite 的项目也是一个可靠的替代方案。它本身也兼容一些Jest的API用法。 二、安装vitest // npm npm install -D vitest // yarn yarn add -D vitest // pnpm pnpm …

Linux 06-01:简易shell编写

考虑一下这个与shell典型的互动&#xff1a;ls、ps 用下图的时间轴来表示事件的发生次序。其中时间从左向右。shell由标识为sh的方块代表&#xff0c;它随着时间的流逝从左向右移动。shell从用户读入字符串"ls"。shell建立一个新的进程&#xff0c;然后在那个进程中运…

vs code 启动react项目,执行npm start报错原因分析

1.执行 npm start错误信息&#xff1a;npm : 无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写&#xff0c;如果包括路径&#xff0c;请确保路径正确&#xff0c;然后再试一次。 所在位置 行:1 字符: 1 npm start ~~~ CategoryInfo …

2024年5000元投影仪推荐:五千元最值得买的三款家用激光投影推荐

五千元是很多家庭购买投影仪会选择的价位&#xff0c;这个价位的投影一般属于中高端产品&#xff0c;如果懂配置&#xff0c;知道怎么选的朋友可以选到一款性价比颇高的投影&#xff0c;但是如果不会选不懂配置可能会花冤枉钱。所以五千元价位的投影该如何选择&#xff1f;市面…

企业知识库用不起来?试一下用HelpLook同步钉钉组织架构

提升企业管理和协同效率已成为增强竞争力的关键。企业通过知识管理&#xff0c;搭建内部知识库&#xff0c;将分散的经验和知识转化为系统化流程&#xff0c;减少重复解释&#xff0c;促进业务高效运作。这为企业提供了坚实的基础。 企业知识库面临的挑战 尽管传统知识库内容丰…

Jeecgboot vue3的选择部门组件JSelectDept如何实现只查询本级以及子级的部门

jeecgboot vue3的文档&#xff1a;地址 JSelectDept组件实现了弹窗然后选择部门返回的功能&#xff0c;但部门是所有数据&#xff0c;不符合需求&#xff0c;所以在原有代码上稍微改动了一下 组件属性值如下&#xff1a; 当serverTreeDatafalse的时候&#xff0c;从后端查询…

2024年7月9日~2024年7月15日周报

目录 一、前言 二、完成情况 2.1 特征图保存方法 2.1.1 定义网络模型 2.1.2 定义保存特征图的钩子函数 2.1.3 为模型层注册钩子 2.1.4 运行模型并检查特征图 2.2 实验情况 三、下周计划 一、前言 本周的7月11日~7月14日参加了机器培训的学习讨论会&#xff0c;对很多概…

通过MATLAB控制TI毫米波雷达的工作状态之TLV数据解析及绘制

前言 前一章博主介绍了如何基于设计视图中的这些组件结合MATLAB代码来实现TI毫米波雷达数据的实时采集。这一章将在此基础上实现TI毫米波雷达的TLV数据解析。过程中部分算法会涉及到一些简单的毫米波雷达相关算法,需要各位有一定的毫米波雷达基础。 TLV数据之协议解析 紧着…

数字孪生技术如何助力低空经济飞跃式发展?

一、什么是低空经济&#xff1f; 低空经济&#xff0c;是一个以通用航空产业为主导的经济形态&#xff0c;它涵盖了低空飞行、航空旅游、航空物流、应急救援等多个领域。它以垂直起降型飞机和无人驾驶航空器为载体&#xff0c;通过载人、载货及其他作业等多场景低空飞行活动&a…

React 实现五子棋

简介 本文将会基于React 实现五子棋小游戏&#xff0c;游戏规则为先让5颗棋子连成1线的一方获胜。 实现效果 技术实现 页面布局 <div><table style{{border: 1px solid #000, borderCollapse: collapse, backgroundColor: lightgray}}><tbody>{squares.ma…

普中51单片机:定时器与计数器详解及应用(七)

文章目录 引言定时器工作原理TMOD定时器/计数器工作模式寄存器定时器工作模式模式0(13位定时器/计数器)模式1(16位定时器/计数器)模式2(8位自动重装模式)模式3(两个8位计数器) 定时器配置流程代码演示——LED1间隔1秒闪烁代码演示——按键1控制LED流水灯状态代码演示——LCD160…

GaussDB DWS 详解

文章目录 GaussDB DWS 详解一、简介二、DWS的分布式架构架构概述关键组件 三、分布式查询数据查询流程SQL执行的示例 批注&#xff1a;本文引鉴了Forlogen博主的一些内容&#xff0c;并加以补充&#xff0c;以供学习了解。 GaussDB DWS 详解 一、简介 DWS(Data Warehouse Ser…

免费分享一套SpringBoot+Vue农产品在线销售(在线商城)管理系统【论文+源码+SQL脚本】,帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue农产品在线销售(在线商城)管理系统&#xff0c;分享下哈。 项目介绍 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发…

alike-cpp 编译

1. 源码链接&#xff1a; https://github.com/Shiaoming/ALIKE-cpp 2.已经安装好显卡驱动&#xff0c;cuda&#xff0c;cudnn,没安装的参考&#xff1a; 切记装cuda-11.x的版本&#xff0c;最好cuda11.3的版本 ubuntu重装系统后&#xff0c;安装cuda,cudnn-CSDN博客 3.安装…