如何让android的service一直在后台运行
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何让android的service一直在后台运行相关的知识,希望对你有一定的参考价值。
Service组件在android开发中经常遇到,其经常作为后台服务,需要始终保持运行,负责处理一些必要的任务。而一些安全软件,会有结束进程的功能,如果不做Service的保持,就会被其杀掉。如何保持Service的运行,其核心就是利用ANDROID的系统广播,这一不会被其他软件影响的常驻程序触发自己的程序检查Service的运行状态,如果被杀掉,就再起来。
利用的系统广播是Intent.ACTION_TIME_TICK,这个广播每分钟发送一次,可以每分钟检查一次Service的运行状态,如果已经被结束了,就重新启动Service。
下边就是具体的代码和注意事项了:
1、 Intent.ACTION_TIME_TICK的使用
开发人员知道广播的注册有静态注册和动态注册,但此系统广播只能通过动态注册的方式使用。即不能通过在manifest.xml里注册的方式接收到这个广播,只能在代码里通过registerReceiver()方法注册。
在ThisApp extends Application 里注册广播:
IntentFilter filter = newIntentFilter(Intent.ACTION_TIME_TICK);
MyBroadcastReceiver receiver = new MyBroadcastReceiver();
registerReceiver(receiver, filter);
在广播接收器MyBroadcastReceiver extends BroadcastReceiver的onReceive里
if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) //检查Service状态
2、Service的检查与启动
boolean isServiceRunning = false;
ActivityManager manager = (ActivityManager)ThisApp.getContext().getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service :manager.getRunningServices(Integer.MAX_VALUE))
if("so.xxxx.WidgetUpdateService".equals(service.service.getClassName()))
//Service的类名
isServiceRunning = true;
if (!isServiceRunning)
Intent i = new Intent(context, WidgetUpdateService.class);
context.startService(i);
关于Service的开机启动。
实现和上边的类似,也是通过监控开机的系统广播来启动Service。但其实做了上边的检查也就不会做开机启动了,因为过一两分钟就会通过上边的程序启动Service了。代码如下:
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED))
Intent i = new Intent(context, LogService.class);
context.startService(i);
参考技术A Android开发的过程中,每次调用startService(Intent)的时候,都会调用该Service对象的onStartCommand(Intent,int,int)方法,然后在onStartCommand方法中做一些处理。然后我们注意到这个函数有一个int的返回值
从Android官方文档中,我们知道onStartCommand有4种返回值:
START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
现在的安卓手机,只要一长按home键,通常都会列出近期任务,这里可以干掉所有进程
所以一直不断的在后台运行是不行的,但是你可以通常广播来激活你的service本回答被提问者和网友采纳
让IPFS一直在后台运行,顺带学习如何创建一个service服务
在使用IPFS遇到一个问题,就是在服务器端启动了ipfs daemon
命令后,关闭终端对应守护进程也会停止,但我并不想让他停止运行,所以就查到相关信息资料,如下分享:
当我们需要让IPFS一直在后台保持运行时,可以创建一个ipfs.service服务
基于Linux服务器创建一个服务。
cd /lib/systemd/system/
vim ipfs.service
粘贴以下代码让IPFS遇到故障后能自动重启服务。
[Unit]
Description=IPFS
[Service]
ExecStart=/usr/local/bin/ipfs daemon
Restart=always
User=root
Group=root
[Install]
WantedBy=multi-user.target
保存退出后执行命令
systemctl start ipfs
此时ipfs就在后台已经启动了,可以随意关闭窗口了
可以通过这个顺带学习一下Linux中service文件
这个脚本分为3个部分:[Unit] [Service] [Install]。
Unit
Unit表明该服务的描述,类型描述。我们称之为一个单元。比较典型的情况是单元A要求在单元B启动之后再启动。这种设置是通过Unit下面的Requires、After、Before、Wants
来调整的。比如上述场景的编写可以这样(在A中编写):
Requires=B
After=B
这段设置表明了A的启动依赖于B,同时有要求在B启动之后启动自己。设置十分简介。需要注意的是,依赖关系通常用在服务(Service)而不是目标(Target)上。
Service
Service是脚本的关键部分,这个字段主要给出服务的启动行为,如何启动、重启、停止。这一部分用于设置一些关键参数:
Type=forking
: 后台运行模式
PIDFile=/xxx/xxx.xxx
:存放PID文件的位置
ExecStart=/bin/echo xxx
:这是服务运行的具体执行命令
ExecReload=/bin/echo xxx
:这是服务重启的执行命令
EexcStop=/bin/echo xxx
: 这是服务停止的执行命令
Service的启动方式,在Service段中,启动方式使用Type指定。具体可以参考man systemd.service。
值得注意的是,在脚本中关于服务启动、重启、关闭的指令需要使用绝对路径,否则会出现无法识别的情况。
当完成一个服务脚本后,我们就可以使用systemctl start|stop|restart xxx.service
等指令了。若要开机启动这个服务我们使用如下的指令:
systemctl enable xxx.service
若要关闭开机启动:
systemctl disable xxx.service
当我们需要查看服务信息的使用可以使用如下指令:
systemctl list-units --type=service
: 列出正在运行的服务
在service片段中有几个概念很重要,这直接影响到实践中创建自定义服务的最终结果。以下内容根据linux系统
中man systemd.service用户手册说明经过翻译和整理而得。
service配置之Type
首先是Type配置,在service片段中有Type的配置,这个配置给当前的服务单元用于设置进程的启动类型。
Type有如下几种可选项:
- simple
- forking
- oneshot
- dbus
- notify
- idel
simple
,这是默认的Type,当Type和BusName配置都没有设置,指定了ExecStart设置后,simple就是默认的Type设置。simple使用ExecStart创建的进程作为服务的主进程。在此设置下systemd会立即启动服务,如果该服务要启动其他服务(simple不会forking),它们的通讯渠道应当在守护进程启动之前被安装好(e.g. sockets,通过sockets激活)。
forking
,如果使用了这个Type,则ExecStart的脚本启动后会调用fork()函数创建一个进程作为其启动的一部分。当一切初始化完毕后,父进程会退出。子进程会继续作为主进程执行。这是传统UNIX主进程的行为。如果这个设置被指定,建议同时设置PIDFile选项来指定pid文件的路径,以便systemd能够识别主进程。
oneshot
,onesh的行为十分类似simple,但是,在systemd启动之前,进程就会退出。这是一次性的行为。可能还需要设置RemainAfterExit=yes,以便systemd认为j进程退出后仍然处于激活状态。
dbus
,这个设置也和simple很相似,该配置期待或设置一个name值,通过设置BusName=设置name即可。
notify
,同样地,与simple相似的配置。顾名思义,该设置会在守护进程启动的时候发送推送消息(通过sd_notify(3))给systemd。
Service其他配置节点
-
RemainAfterExit
:默认值no
默认值为no,这个设置采用booleean值,可以是0、no、off、1、yes、on等值。它表明服务是否应当被视为激活的,即便当它所有的进程都退出了。简言之,这个设置用于告诉systemd服务是否应当是被视为激活状态,而不管进程是否退出。当为true时,即便服务退出,systemd依然将这个服务视为激活状态,反之则服务停止。 -
GuessMainPID
采用boolean值指定systemd在无法确切的查明服务的时候是否需要猜测服务的main pid。除非Type=forking被采用并且PIDFile没有被设置,否则这个选项会被忽略。因为当设置为Type的其他选项,或者显示的指定了PID文件后,systemd总是能够知道main pid。 -
PIDFile
采用一个绝对路径的文件名指定守护进程的PID文件。当Type=forking被设置的时候,建议采取这个设置。当服务启动后,systemd会读取守护进程的主进程id。systemd不会对该文件写入数据。 -
BusName
使用一个D-Bus的总线名称,作为该服务的可访问名称。当Type=dbus的时候,该设置被强制使用。 -
BusPolicy
如果该选项被指定,一个自定义的kdbus终结点将会被创建,并且会被指定为默认的dbus节点安装到服务上。这样的自定义终结点自身持有一个策略规则集合。这些规则将会在总线范围内被强制指定。该选项只有在kdbus被激活时有效。 -
ExecStart
当服务启动的时候(systemctl start youservice.service),会执行这个选项的值,这个值一般是“ExecStart=指令 参数”的形式。当Type=oneshot的时候,只有一个指令可以并且必须给出。原因是oneshot只会被执行一次。 -
ExecStartPre、ExecStartPost
顾名思义,这两个设置的意义在于ExecStart被执行之前和之后被执行。 -
ExecReload
服务重启时执行。 -
ExecStop
服务停止时执行。 -
ExecStopPost
服务停止后执行。
Install
WantedBy字段
:表示该服务所在的Target
。
Target的含义是服务组,表示一组服务。WantedBy=multi-user.target
指的是服务所在的Target
是multi-user.target
Systemd 有默认的启动 Target。就是multi-user.target
,在这个组里的所有服务,都将开机启动。
查看 multi-user.target
包含的所有服务
systemctl list-dependencies multi-user.target
参考链接:
置于服务脚本编写,借鉴了https://blog.csdn.net/guiziwen/article/details/80291702
脚本理解原文链接https://www.jianshu.com/p/92208194d700
以上是关于如何让android的service一直在后台运行的主要内容,如果未能解决你的问题,请参考以下文章
怎么让 Android 程序一直后台运行,像 QQ 一样不被杀死