当前位置: 首页 > news >正文

Android四大组件——Service详解

        Service 为后台运行,不可见,没有界面。优先级高于Activity(内存不足时先杀掉Activity),运行在主线程且不能做耗时操作。

一、Service 启动方式

1、startService()

        通过 startService 启动后,service会一直无限期运行下去,当外部调用了 stopService() 或stopSelf() 方法时,该Service才会停止运行并销毁。当系统资源不足时, 会回收一些不重要的service,service 被系统回收也会停止运行并被销毁。

生命周期

onCreate()

1、如果 service 没被创建过,调用 startService() 后会执行 onCreate() 回调;
2、如果 service 已处于运行中,调用 startService() 不会执行 onCreate() 方法。

        此方法适合完成一些初始化工作。

onStartCommand()

        如果多次执行了 startService() 方法,那么 Service 的 onStartCommand() 方法也会相应的多次调用。

onBind()

        Service中的onBind()方法是抽象方法,Service类本身就是抽象类,所以onBind()方法是必须重写的,即使我们用不到。

         使用 startService 方法启动 Service,onBind() 方法基本用不到,重写时返回一个 null 即可。

onDestory()

        在销毁的时候会执行Service该方法。

代码实例

MainActivity.java

public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 启动serviceIntent intent = new Intent(MainActivity.this, TestService.class);startService(intent);}
}

TestService.java

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

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.xiaoxu.testdemo"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.MainActivity "><serviceandroid:name=".TestService"android:enabled="true"android:exported="true" /><activityandroid:name=".MainActivity"android:exported="true" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application>
</manifest>

2、bindService

        bindService 启动的服务和调用者之间是典型的 client-server 模式。调用者是 client,service则是 server 端。service只有一个,但绑定到 service 上面的 client 可以有一个或多个。这里所提到的 client 指的是组件,比如某个Activity。
        client 可以通过 IBinder 接口获取 Service 实例,从而实现在 client 端直接调用 Service 中的方法以实现灵活交互,这在通过 startService 方法启动中是无法实现的。
        bindService 启动服务的生命周期与其绑定的 client 息息相关。当 client 销毁时,client 会自动与 Service 解除绑定。当然,client 也可以明确调用 Context 的 unbindService() 方法与 Service 解除绑定。当没有任何 client 与 Service 绑定时,Service 会自行销毁。

生命周期

onCreate()

        当服务通过 onStartCommand() 和 onBind() 被第一次创建的时候,系统调用该方法。该调用要求执行一次性安装。

onBind()

        当其他组件想要通过 bindService() 来绑定服务时,系统调用该方法。如果你实现该方法,你需要返回 IBinder 对象来提供一个接口,以便客户来与服务通信。你必须实现该方法,如果你不允许绑定,则直接返回 null。

onUnbind()

        当客户中断所有服务发布的特殊接口时,系统调用该方法。

onRebind()

        当新的客户端与服务连接,且此前它已经通过onUnbind(Intent)通知断开连接时,系统调用该方法。

onDestroy()

        当服务不再有用或者被销毁时,系统调用该方法。你的服务需要实现该方法来清理任何资源,如线程,已注册的监听器,接收器等。

代码实例

MainAcivity.java

public class MainAcivity extends Activity{private TextService mService = null;protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent = new Intent(this, TestService.class);bindService(intent, conn, Context.BIND_AUTO_CREATE);}private ServiceConnection conn = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder binder) {MyBinder mBinder = (MyBinder)binder;mService = mBinder.getService();String name = mService.getUserName();}@Overridepublic void onServiceDisconnected(ComponentName name) {}};@Overrideprotected void onDestroy() {super.onDestroy();unbindService(conn);}
}

MyService.java

public class TestService extends Service{//通过 binder 实现调用者 client 与 Service 之间的通信private MyBinder binder = new MyBinder();// client 可以通过 Binder 获取 Service 实例public class MyBinder extends Binder {public MyService getService() {return TestService.this;}}@Overridepublic void onCreate() {super.onCreate();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return START_NOT_STICKY;}@Overridepublic IBinder onBind(Intent intent) {return binder;}@Overridepublic boolean onUnbind(Intent intent) {return false;}@Overridepublic void onDestroy() {super.onDestroy();}// getUserName 是 Service 暴露出去供 Client 调用的公共方法public int getUserName() {return "XiaoXu";}
}

3、startForegroundService

        Android 8.0 系统不允许后台应用创建后台服务,只能使用 startForegroundService() 启动服务,创建服务后,应用必须在 5 秒内调用该服务的 startForeground() 显示一条可见通知,声明有服务在挂着,不然系统会停止服务 + ANR 提示。
        系统的要求 Notification 要加 Channel,并且要在 onStartCommand 中执行 startForeground(),因为这个主要是针对后台保活的服务,如果在服务运行期间,再次使用 startForegroundService() 启动服务,那么这次就不会调用服务的 onCreate 方法,只会调用onStartCommand 方法。如果不在 onStartCommand 方法里再挂个通知的话,系统会认为你使用了 startForegroundService 却不在 5 秒内给通知,很傻地就停止服务 + ANR 提示。

代码实例

MainActivity.java

public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 启动serviceIntent intent = new Intent(this, TestService.class) ;startForegroundService(intent);}
}

TestService.java

public class TestService extends Service {private static final String TAG = "TestService";private Notification notification;public static final String CHANNEL_ID_STRING = "service_01";@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_STRING,getString(R.string.app_name),NotificationManager.IMPORTANCE_LOW);manager.createNotificationChannel(mChannel);notification = new Notification.Builder(getApplicationContext(), CHANNEL_ID_STRING).build();// 下面第一个参数不能为 0startForeground(1, notification);return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();}
}

        可以看到使用  startForegroundService 启动方式与 startService 基本相同,只是在 Service 的 onStartCommand 增加弹出通知的操作。startForeground 方法中的第一个参数不能为 0,是因为这个通知不能与正常通知 id 相同,否则通知会被“隐藏”,这不是官方想看到的,就会出现 Context.startForegroundService() did not then call Service.startForeground() 异常。

二、其他

1、使用场景

startService

        前台应用调用 startService 启动 Service,Service 独立运行,不需要与 Activity 进行交互。

bindService

        前台应用调用 bindService 启动 Service,Android 与 Service 进行绑定,并且 Activity 可以得到 Service 的实例,实现与 Service 的交互。

startForegroundService

        后台应用调用 startForegroundService 启动 Service,Android 8.0 之后强制要求,以提示用户。例如:在收到开机广播时启动服务,使用 startService 会无法启动,只能使用 startForegroundService 进行启动并弹出通知提示用户。

2、隐藏通知

        有时在使用 startForegroundService 启动服务时,想隐藏常驻通知。

1)显示通知后马上调用 stopForeground(true) 取消通知。在 Android 11 中测试,服务被杀掉。

2)提前注册一个没有声音没有震动的通知channel,注册一个无声无振动的通知渠道。startForeground 时与该通知使用同一个 id,就可以隐藏我们的通知了。(未尝试)

参考:Android8 避免startForeground方法弹出通知

3、AIDL Service死亡监听

        服务的死亡监听我们使用第二种启动方式。

启动 Service

private void bindService(Context context) {Intent serviceIntent = new Intent();serviceIntent.setAction("com.cx.test");serviceIntent.setPackage("com.cx.test.MyService");boolean bindSuccess = context.bindService(serviceIntent, mServiceConnection, Service.BIND_AUTO_CREATE);
}

绑定结果回调

private IPushInterface mIPushInterface;private ServiceConnection mServiceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) {if (iBinder != null) {//通过AIDL拿到服务mIPushInterface = IPushInterface.Stub.asInterface(iBinder);try {//服务死亡监听if (mIPushInterface != null) {mIPushInterface.asBinder().linkToDeath(mDeathRecipient, 0);}} catch (RemoteException e) {e.printStackTrace();}}}@Overridepublic void onServiceDisconnected(ComponentName componentName) {//连接失败}
};

死亡监听回调

private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {@Overridepublic void binderDied() {if (mContext != null) {//重新绑定服务bindService(mContext);}}
};

相关文章:

Android四大组件——Service详解

Service 为后台运行&#xff0c;不可见&#xff0c;没有界面。优先级高于Activity&#xff08;内存不足时先杀掉Activity&#xff09;&#xff0c;运行在主线程且不能做耗时操作。 一、Service 启动方式 1、startService() 通过 startService 启动后&#xff0c;service会一直…...

svg转png

svg转png写了一个spring boot项目&#xff0c;支持传入svg文件转出png图片&#xff0c;并且自定义转出png的宽和高。主要代码如下&#xff1a;所需依赖如下&#xff1a;演示如下&#xff1a;首先&#xff0c;运行项目使用接口调用工具调用接口发送请求&#xff0c;提取文件1000…...

教你如何搭建人事OA-员工管理系统,demo可分享

1、简介1.1、案例简介本文将介绍&#xff0c;如何搭建人事OA-员工管理。1.2、应用场景人事OA-员工管理应用对员工信息进行管理&#xff0c;可办理入职、转正、离职等流程。2、设置方法2.1、表单搭建1&#xff09;新建表单【员工管理】&#xff0c;字段设置如下&#xff1a;名称…...

C++递推基础知识

文章目录一、递推的概念二、递推和递归的区别三、递推的实例1、最基础的&#xff1a;斐波那契数列2、变形版斐波那契数列3、较复杂的递推式求解&#xff1a;昆虫繁殖4、经典逆推问题&#xff1a;题目数量一、递推的概念 1、什么是递推算法&#xff1f; 递推算法&#xff1a;是…...

【Python入门第十天】Python 布尔

布尔表示两值之一&#xff1a;True 或 False。 布尔值 在编程中&#xff0c;通常需要知道表达式是 True 还是 False。 可以计算 Python 中的任何表达式&#xff0c;并获得两个答案之一&#xff0c;即 True 或 False。 比较两个值时&#xff0c;将对表达式求值&#xff0c;P…...

WebDAV之π-Disk派盘+Piktures

Piktures支持WebDAV方式连接π-Disk派盘。推荐一款简单易用&#xff0c;功能超级强大的智能相册应用。Piktures智能相册是一款简单易用&#xff0c;功能超级强大的智能相册应用&#xff0c;它不仅可以访问本地和云照片&#xff0c;还可以照片编辑器&#xff0c;而且它同时还是一…...

Revit问题:Navisworks中导入的rvt模型角度不正确调整

一、Navisworks中导入的rvt模型角度不正确调整方法 通常情况下&#xff0c;我们做好一个Revit模型&#xff0c;有时候出于成果保护或者鉴于Revit自带的碰撞检测效果不够直观、Revit模型体量太大&#xff0c;需要一个轻量化的模型展示&#xff0c;我们通常情况下会使用Autodesk公…...

最全正则验证

一、校验数字的表达式 1. 数字&#xff1a;^[0-9]*$ 2. n位的数字&#xff1a;^\d{n}$ 3. 至少n位的数字&#xff1a;^\d{n,}$ 4. m-n位的数字&#xff1a;^\d{m,n}$ 5. 零和非零开头的数字&#xff1a;^(0|[1-9][0-9]*)$ 6. 非零开头的最多带两位小数的数字&#xff1a;…...

阿里云服务器入门使用流程 新手学习教程

一、阿里云根据个人需要选合适的云服务器&#xff0c;选好cpu、内存、带宽&#xff0c;地域&#xff0c;这四个是主要的。其他可以默认选择。 二、登陆控制台 输入账号密码&#xff0c;进去看到服务界面&#xff0c;新手可能不容易看懂。点击左侧菜单&#xff0c;点击云服务器…...

git学习

一.实际场景 数据备份代码还原协同开发追溯问题代码的编写人和编写时间 二.Git工作流程图 三.获取本地仓库 四.git add和git commit git status&#xff1a;查看修改的状态&#xff08;暂存区&#xff0c;工作区&#xff09; git add . &#xff1a;通配符&#xff0c;添加当…...

新建一个完整的react项目和完善初始项目

一&#xff1a;新建一个完整的react项目 1.环境准备 目前我的环境是 node&#xff1a;16.17.1 npm&#xff1a; 8.15.0 查看环境&#xff1a;1)&#xff1a;打开命令提示符工具&#xff0c;利用node -v和npm -v 查看一下自己的环境&#xff0c;如果觉得重新卸载、安装node比较…...

HIVE 安装

目录 启动hadoop 把hive压缩包拷贝到虚拟机里面 解压 改名 配置环境变量 新建一个hive-site.xml文件&#xff0c;并编辑 配置文件 添加jar包 初始化mysql 启动hive 创建数据库 使用数据库 创建表 添加数据 查看数据 删除表 安装虚拟机 安装JDK 安装Hadoop …...

jsp游泳馆门票管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 jsp游泳馆门票管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql&#xff0c;…...

C++ ---智能指针详解

文章目录前言一、 为什么需要智能指针&#xff1f;二、内存泄漏2.1 什么是内存泄露?危害是什么?2.2 内存泄露的分类2.3 如何避免内存泄露三、智能指针的使用及原理3.1 RAII3.2 智能指针的原理3.3 std::autoptr3.4 std::unique_ptr3.5 std::shared_ptrstd::shared_ptr的循环引…...

企业带宽控制管理

在企业中保持稳定的网络性能可能具有挑战性&#xff0c;因为采用数字化的网络可扩展性和敏捷性应该与组织的发展同步。随着基础设施的扩展、新应用和新技术的引入&#xff0c;网络的带宽容量也在增加。 停机和带宽过度使用是任何组织都无法避免的两个问题&#xff0c;为了解决…...

MybatisPlus实现分页效果并解决错误:cant found IPage for args!

前言 早就知道MybatisPlus对分页进行了处理&#xff0c;但是一直没有实战用过&#xff0c;用的是自己封装的一个分页组件&#xff0c;虽不说麻烦吧&#xff0c;但是也不是特别简单。 写起来还是比较复杂&#xff0c;但是最近这个组件有了点小小的bug&#xff0c;我决定是时候…...

C语言赋值(关系)运算符和逗号运算符

一.赋值&#xff08;关系&#xff09;运算符 1.关系运算符 高优先级组 < 左边值小于右边值,则返回1。否则返回0 < 左边值小于等于右边值,则返回1。否则返回0 > 左边值大于右边值,则返回1。否则返回0 > 左边值大于等于右边值,则返回1。否则返回0 低优先级组…...

几种在Linux/window下查询外网IP的办法。

hello world curl ifconfig.me/ip如下图 1. 纯文本 https://ifconfig.me/ip https://ipinfo.io/ip 或 https://ipecho.net/ip 或 https://ipecho.net/plain https://www.trackip.net/ip https://icanhazip.com 2. JSON格式 https://ifconfig.me/all.json https://ipi…...

【nodejs-05】黑马nodejs学习笔记05-数据库基本操作01

文章目录3.MySQL的基本使用3.1 使用 MySQL Workbench 管理数据库3.2 使用 SQL 管理数据库3.3 SQL 的 SELECT 语句3.4 SQL 的 INSERT INTO 语句3.5 SQL 的 UPDATE 语句3.6 SQL 的 DELETE 语句3.7 SQL 的 WHERE 子句3.8 SQL 的 AND 和 OR 运算符3.9 SQL 的 ORDER BY 子句3.10 SQL…...

零基础、学历无优势、逻辑能力一般”,能转行做程序员吗?

此前&#xff0c;拉勾数据研究院对程序员群体做了一次深入调查&#xff0c;并发布了《2022程序员群体职场洞察报告》&#xff0c;报告显示&#xff0c;“高薪”依然是程序员的职业标签之一。 在调查的程序员群体中&#xff0c;年薪在10-30万元之间的人数占比为66.7%&#xff0…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

STM32---外部32.768K晶振(LSE)无法起振问题

晶振是否起振主要就检查两个1、晶振与MCU是否兼容&#xff1b;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容&#xff08;CL&#xff09;与匹配电容&#xff08;CL1、CL2&#xff09;的关系 2. 如何选择 CL1 和 CL…...