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 为后台运行,不可见,没有界面。优先级高于Activity(内存不足时先杀掉Activity),运行在主线程且不能做耗时操作。 一、Service 启动方式 1、startService() 通过 startService 启动后,service会一直…...
svg转png
svg转png写了一个spring boot项目,支持传入svg文件转出png图片,并且自定义转出png的宽和高。主要代码如下:所需依赖如下:演示如下:首先,运行项目使用接口调用工具调用接口发送请求,提取文件1000…...
教你如何搭建人事OA-员工管理系统,demo可分享
1、简介1.1、案例简介本文将介绍,如何搭建人事OA-员工管理。1.2、应用场景人事OA-员工管理应用对员工信息进行管理,可办理入职、转正、离职等流程。2、设置方法2.1、表单搭建1)新建表单【员工管理】,字段设置如下:名称…...
C++递推基础知识
文章目录一、递推的概念二、递推和递归的区别三、递推的实例1、最基础的:斐波那契数列2、变形版斐波那契数列3、较复杂的递推式求解:昆虫繁殖4、经典逆推问题:题目数量一、递推的概念 1、什么是递推算法? 递推算法:是…...
【Python入门第十天】Python 布尔
布尔表示两值之一:True 或 False。 布尔值 在编程中,通常需要知道表达式是 True 还是 False。 可以计算 Python 中的任何表达式,并获得两个答案之一,即 True 或 False。 比较两个值时,将对表达式求值,P…...
WebDAV之π-Disk派盘+Piktures
Piktures支持WebDAV方式连接π-Disk派盘。推荐一款简单易用,功能超级强大的智能相册应用。Piktures智能相册是一款简单易用,功能超级强大的智能相册应用,它不仅可以访问本地和云照片,还可以照片编辑器,而且它同时还是一…...
Revit问题:Navisworks中导入的rvt模型角度不正确调整
一、Navisworks中导入的rvt模型角度不正确调整方法 通常情况下,我们做好一个Revit模型,有时候出于成果保护或者鉴于Revit自带的碰撞检测效果不够直观、Revit模型体量太大,需要一个轻量化的模型展示,我们通常情况下会使用Autodesk公…...
最全正则验证
一、校验数字的表达式 1. 数字:^[0-9]*$ 2. n位的数字:^\d{n}$ 3. 至少n位的数字:^\d{n,}$ 4. m-n位的数字:^\d{m,n}$ 5. 零和非零开头的数字:^(0|[1-9][0-9]*)$ 6. 非零开头的最多带两位小数的数字:…...
阿里云服务器入门使用流程 新手学习教程
一、阿里云根据个人需要选合适的云服务器,选好cpu、内存、带宽,地域,这四个是主要的。其他可以默认选择。 二、登陆控制台 输入账号密码,进去看到服务界面,新手可能不容易看懂。点击左侧菜单,点击云服务器…...
git学习
一.实际场景 数据备份代码还原协同开发追溯问题代码的编写人和编写时间 二.Git工作流程图 三.获取本地仓库 四.git add和git commit git status:查看修改的状态(暂存区,工作区) git add . :通配符,添加当…...
新建一个完整的react项目和完善初始项目
一:新建一个完整的react项目 1.环境准备 目前我的环境是 node:16.17.1 npm: 8.15.0 查看环境:1):打开命令提示符工具,利用node -v和npm -v 查看一下自己的环境,如果觉得重新卸载、安装node比较…...
HIVE 安装
目录 启动hadoop 把hive压缩包拷贝到虚拟机里面 解压 改名 配置环境变量 新建一个hive-site.xml文件,并编辑 配置文件 添加jar包 初始化mysql 启动hive 创建数据库 使用数据库 创建表 添加数据 查看数据 删除表 安装虚拟机 安装JDK 安装Hadoop …...
jsp游泳馆门票管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目
一、源码特点 jsp游泳馆门票管理系统 是一套完善的web设计系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql,…...
C++ ---智能指针详解
文章目录前言一、 为什么需要智能指针?二、内存泄漏2.1 什么是内存泄露?危害是什么?2.2 内存泄露的分类2.3 如何避免内存泄露三、智能指针的使用及原理3.1 RAII3.2 智能指针的原理3.3 std::autoptr3.4 std::unique_ptr3.5 std::shared_ptrstd::shared_ptr的循环引…...
企业带宽控制管理
在企业中保持稳定的网络性能可能具有挑战性,因为采用数字化的网络可扩展性和敏捷性应该与组织的发展同步。随着基础设施的扩展、新应用和新技术的引入,网络的带宽容量也在增加。 停机和带宽过度使用是任何组织都无法避免的两个问题,为了解决…...
MybatisPlus实现分页效果并解决错误:cant found IPage for args!
前言 早就知道MybatisPlus对分页进行了处理,但是一直没有实战用过,用的是自己封装的一个分页组件,虽不说麻烦吧,但是也不是特别简单。 写起来还是比较复杂,但是最近这个组件有了点小小的bug,我决定是时候…...
C语言赋值(关系)运算符和逗号运算符
一.赋值(关系)运算符 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…...
零基础、学历无优势、逻辑能力一般”,能转行做程序员吗?
此前,拉勾数据研究院对程序员群体做了一次深入调查,并发布了《2022程序员群体职场洞察报告》,报告显示,“高薪”依然是程序员的职业标签之一。 在调查的程序员群体中,年薪在10-30万元之间的人数占比为66.7%࿰…...
第五章.与学习相关技巧—Batch Normalization
第五章.与学习相关技巧 5.3 Batch Normalization Batch Norm以进行学习时的mini_batch为单位,按mini_batch进行正则化,具体而言,就是进行使数据分布的均值为0,方差为1的正则化。Batch Norm是调整各层激活值的分布使其拥有适当的广…...
Zynq非Video Mixer方案实现视频叠加输出,无需SDK配置,提供工程源码和技术支持
目录1、前言2、Video Mixer的不便之处3、FDMA取代Video Mixer实现视频叠加输出4、Vivado工程详解5、上板调试验证并演示6、福利:工程代码的获取1、前言 关于Zynq使用Video Mixer方案实现视频叠加输出方案请参考点击查看:Video Mixer方案 对于Zynq和Micr…...
从零实现Web服务器(二): 线程池以及线程池的作用,Get和Post的区别,项目中如何编写数据库连接池,定时器优化非活跃连接
文章目录一、线程池以及线程池的作用二、手写线程池三、Get和Post的区别四、如何编写数据库连接池五、定时器优化非活跃连接5.1. 基于排序链表实现。5.2. 基于小根堆实现。5.3. 基于红黑树实现。5.4. 基于时间轮实现。5.4.1 单时间轮实现5.4.2 多时间轮实现一、线程池以及线程池…...
为什么伟大的产品只专注做一件事
uber 不允许你预订出租车。亚马逊一开始只是卖书。谷歌只是一个搜索引擎。麦当劳没有餐具。不知为什么,我们仍然相信一个产品要想成功,它必须做很多事情。这通常发生在两种情况下:当新产品试图让市场相信它们是值得的,或者当公司提…...
pycharm远程连接服务器,并单步调试服务器上的代码
每天都有不同的朋友来Push我 那如果比较健忘的话,为啥不问一下chatGPT呢 问题的缘由在我想在本地单步调试代码。。。 我的代码完全在云端服务器的,还有数据集都是,但实际上本地代码可以通过pycharm给他传上去。 但是在后面配置的时候需要两…...
JVM05 方法区
Person:存放在元空间,也可以说方法区 person:存放在Java栈的局部变量表中 new Person():存放在Java堆中 1.方法区的理解 方法区主要存放的是 Class,而堆中主要存放的是 实例化的对象 方法区(Method Area…...
盘点3个.Net开发的WMS仓库管理系统
更多开源项目请查看:一个专注推荐.Net开源项目的榜单 仓库管理系统在企业中,重要性越来越高,不仅可以提高效率,还能降低企业的压力,企业通过协调和优化资源使用和物料流动,能极大程度地提升了管理效率&…...
Linux下Java项目开机自动启动
Linux下Java项目开机自动启动1、在Linux上设置开机启动Java程序,例如:test.jar在Linux上启动Java程序的命令:2、可以将程序启动的指令做成一个shell脚本,简单的做法创建一个test.sh文件,内容如下:3、最重要的一步就是修…...
基于SpringBoot的智慧社区网站
文末获取源码 开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7/8.0 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven3.3.9 浏…...
数据分析与SAS学习笔记3
SAS在最新的展示图,表现力比较丰富。 SAS的处理流程: 数据步 过程步: ETL是数据分析非常重要的步骤。70%-90%花在收集数据以及整理数据,数据分析数据的时间不是很多的。 一个完整的数据步和过程步: 数据步基本语句总…...
网站流量超标/优化关键词排名软件
贪心算法题目-LeetCode汇总455.分发饼干455.分发饼干 题目描述 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺…...
宜宾seo网站建设/网络推广优化是干啥的
2019独角兽企业重金招聘Python工程师标准>>> 我之前发布了关于java.lang.Object类及其方法的一系列文章。在介绍了Object之后,我们又探究了clone()和euqals()方法。在这篇文章中,我们将继续讨论Object中的finalize()、getClass()和hashCode()…...
物联网项目设计方案/谷歌优化是什么意思
在Visual FoxPro中创建Web服务注:该文章节选自作者的《Visual FoxPro程序设计参考手册》 创建一个Web服务是一个复杂的过程,这涉及到要使用Internet信息服务(IIS)、Visual FoxPro COM服务程序和简单对象访问协议(SOAP…...
做网站大概需要多少钱/万网域名管理平台
455. 分发饼干 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有…...
北京网站开发服务/网络营销公司好不好
在安装KVM虚拟机的时候,在Laptop上进行远程管理的时候,键盘字符都乱了,无法输入正常的信息,这总不是个事,总不能跑到KVM服务器上操作吧,后来放狗查了一下,发现是VNC的键盘布局问题,解…...
wordpress 伪支付宝/微商怎么引流被别人加
一、棋盘的标记象棋的着法表示,简而言之就是某个棋子从什么位置走到什么位置。通常,表示方法可以分为“纵线方式”和“坐标方式”两种,现在作简要说明:1、纵线方式,它是中国象棋常用的表示方法,即棋子从棋盘…...