【Android】之【Service】
创始人
2025-05-29 06:38:30
0

一、代码示例

如下代码监听开机广播,启动一个Service

AndroidManifest.xml



AppService

package com.android.demo.service;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;import com.android.demo.util.ShellUtils;import java.util.ArrayList;
import java.util.List;public class AppService extends Service {private final static String TAG = "AppService";private boolean isServiceStarted = false;private Intent startIntent = null;@Overridepublic IBinder onBind(Intent arg0) {return null;}@Overridepublic void onCreate() {super.onCreate();Log.e(TAG, "AppService onCreate");}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.e(TAG, "AppService onStartCommand");//onStart(intent, startId);//return super.onStartCommand(intent, flags, startId);//START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。//随后系统会尝试重新创建service,由于服务状态为开始状态,//所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。//如果在此期间没有任何启动命令被传递到service,那么参数Intent将为nullreturn START_STICKY;}@Overridepublic void onStart(Intent intent, int startId) {// TODO Auto-generated method stubstartIntent = intent;Log.e(TAG, "AppService, onStart");if (!isServiceStarted) {isServiceStarted = true;}}@Overridepublic void onDestroy() {// TODO Auto-generated method stubLog.e(TAG, "AppService, onDestroy");isServiceStarted = false;//在销毁的时候,重新开启if (startIntent != null) {startService(startIntent);}}
}

BootBroadcastReceiver

package com.android.demo.broadcast;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;import com.android.demo.service.AppService;public class BootBroadcastReceiver extends BroadcastReceiver {private static final String TAG = "BootBroadcastReceiver";private static Context mContext;@Overridepublic void onReceive(Context context, Intent intent) {mContext = context;String action = intent.getAction();Log.e(TAG, "BootBroadcastReceiver action  = " + action);if (action == null) {return;}if (action.equals("android.intent.action.BOOT_COMPLETED")) {Log.i(TAG, "BOOT_COMPLETED");Intent i = new Intent(context, AppService.class);i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startService(i);}}}

二、 Service简介

Service是Android 系统中的四大组件之一(Activity、Service、BroadcastReceiver、ContentProvider),它跟Activity的级别差不多,但不能自己运行只能后台运行,并且可以和其他组件进行交互。service可以在很多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务总是藏在后台的。
Service的启动有两种方式:context.startService() 和 context.bindService()

三、 Service启动流程

context.startService() 启动流程:
context.startService() -> onCreate() -> onStart() -> Service running -> context.stopService() -> onDestroy() -> Service stop

onstart()方法是在android2.0一下的版本中使用。而在android2.0以上则使用onstartCommand()方法。

如果Service还没有运行,则android先调用onCreate(),然后调用onStart();
如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。
如果stopService的时候会直接onDestroy,如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行,该Service的调用者在启动起来后可以通过stopService关闭Service。
所以调用startService的生命周期为:onCreate --> onStart (可多次调用) --> onDestroy

context.bindService()启动流程:
context.bindService() -> onCreate() -> onBind() -> Service running -> onUnbind() -> onDestroy() -> Service stop

onBind()将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service的实例、运行状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。
所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。
在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。

四、 Service生命周期

Service的生命周期并不像Activity那么复杂,它只继承了onCreate()、onStart()、onDestroy()三个方法
当我们第一次启动Service时,先后调用了onCreate()、onStart()这两个方法;当停止Service时,则执行onDestroy()方法。
这里需要注意的是,如果Service已经启动了,当我们再次启动Service时,不会在执行onCreate()方法,而是直接执行onStart()方法。
在这里插入图片描述

它可以通过Service.stopSelf()方法或者Service.stopSelfResult()方法来停止自己,只要调用一次stopService()方法便可以停止服务,无论调用了多少次的启动服务方法。

五、 关于怎样让服务不被杀死

① 添加android:persistent=“true”

添加android:persistent=“true"到AndroidManifest.xml,
Google文档描述如下:Whether or not the application should remain running at all times-true” if it should, and "false"if not. The default value is “false”. Applications should not normally set this flag; persistence mode is intended only for certain system applications.可见这个属性不能随便用,到目前为止,我所发现使用该属性的应用只有Phone,而且使用是要求权限的,所以这个属性对第三方应用来说意义不是很大;常驻内存属性对第三方app无效

② 重写service的onStartCommand方法

设置onStartCommand()的返回值 。

@Override   public int onStartCommand(Intent intent, int flags, int startId) {   return START_STICKY;   
}  

简单介绍下这个方法,在Android开发的过程中,每次调用startService(Intent)的时候,都会调用该Service对象的onStartCommand(Intent,int,int)方法,然后在onStartCommand方法中做一些处理。然后我们注意到这个函数有一个int的返回值,这篇文章就是简单地讲讲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后一定能重启。

③ 在onDestory方法中重启Service服务

一般来说,这样做是可以的。但是如果这样----》设置–>下载–>强制停止。则不会执行ondestory方法,或者通过别人应用,如360直接kill掉我的应用时,也是不会调用Service的ondestory方法的。onDestroy方法里重启serviceservice +broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service;

               //这个就是自定义的action     

在onDestroy时:

@Override  
public void onDestroy() {  stopForeground(true);  Intent intent = new Intent("com.dbjtech.waiqin.destroy");  sendBroadcast(intent);  super.onDestroy();  
}

在BootReceiver里

public class BootReceiver extends BroadcastReceiver {  @Override  public void onReceive(Context context, Intent intent) {  if (intent.getAction().equals("com.dbjtech.waiqin.destroy")) {  //在这里写重新启动service的相关操作  startUploadService(context);  }  }  
}

也可以直接在onDestroy()里startService

@Override  
public void onDestroy() {  Intent sevice = new Intent(this, MainService.class);  this.startService(sevice);  super.onDestroy();  
}

【结论】当在setting里-应用-强制停止时,APP进程可能就直接被干掉了,onDestroy方法都进不来,所以还是无法保证.

④ 修改AndroidManifest.xml

      

如果在加入了此部分代码,表示该程序运行在system进程组中,system进程组是没有权限访问sd卡的,而且service是不会自动重启的。

⑤ 提高service的优先级别

不管你service的优先级别有多高,用户都是可以手动杀死的.
提升service优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。

        

【结论】目前看来,priority这个属性貌似只适用于broadcast,对于Service来说可能无效

⑥ 提升service进程优先级

Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为6个等级,它们按优先级顺序由高到低依次是:
1.前台进程( FOREGROUND_APP)
2.可视进程(VISIBLE_APP )
3.次要服务进程(SECONDARY_SERVER )
4.后台进程 (HIDDEN_APP)
5.内容供应节点(CONTENT_PROVIDER)
6.空进程(EMPTY_APP)
当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以使用startForeground 将service放到前台状态。这样在低内存时被kill的几率会低一些。
在onStartCommand方法内添加如下代码:

Notification notification = new Notification(R.drawable.ic_launcher,  
getString(R.string.app_name), System.currentTimeMillis());  
PendingIntent pendingintent = PendingIntent.getActivity(this, 0,  
new Intent(this, AppMain.class), 0);  
notification.setLatestEventInfo(this, "uploadservice", "请保持程序在后台运行",  
pendingintent);  
startForeground(0x111, notification);

注意在onDestroy里还需要stopForeground(true),运行时在下拉列表会看到自己的APP

⑦ 可以监听Intent.ACTION_TIME_TIC系统时钟广播

启动、网络切换、耳机插入、锁屏,亮屏等系统广播,系统每隔一段时间发送这个广播,当service被杀死的时候,隔一段时间通过广播启动,动态注册android.intent.action.TIME_TICK监听
判断service是否启动

public boolean isServiceRunning(String serviceName) 
{ ActivityManager manager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);   for (RunningServiceInfo service :manager.getRunningServices(Integer.MAX_VALUE))   {   if(serviceName.equals(service.service.getClassName())) {   return true;   }   } return false; 
} 

接受到广播后判断是否启动该service 若没有启动就启动它

if(intent.getAction().equals(Intent.ACTION_TIME_TICK)) 
{         if (!isServiceRunning(name)){   Intent mIntent = new Intent(context, MyService.class);   context.startService(mIntent);   }   
} 

⑧ 增加系统白名单,防止重要应用低内存时被误杀

联系厂商,加入白名单,有童鞋验证把demo工程的包名改成手机QQ的,编译运行在华为的机子上,发现进程杀不死,退到后台oom_adj的值同样不发生变化,而恢复原来的包名就不行了,可见很多大型软件,尤其聊天类的都会和厂商合作,将相关应用加入白名单。

参考

  • Android之Service全面解析,关于Service你所需要知道的一切

  • Android Service完全解析,关于服务你所需知道的一切(上)

  • Android Service完全解析,关于服务你所需知道的一切(下)

  • 务必知道的Android service的完全详解

  • Android之Service设置android:process作用

相关内容

热门资讯

arcpy基础篇(2)-访问空... 1.检查数据的存在性 在Python脚本中,可以使用Exists函数来检查当前工作空间...
幼儿园毕业典礼活动方案 关于幼儿园毕业典礼活动方案(通用10篇)  为有力保证事情或工作开展的水平质量,常常需要预先准备方案...
消防应急培训演练方案 消防应急培训演练方案  为了确保工作或事情顺利进行,通常需要预先制定一份完整的方案,方案是综合考量事...
同学聚会活动方案 同学聚会活动方案(精选15篇)  为了确保工作或事情能高效地开展,预先制定方案是必不可少的,方案的内...
国务院关于职工工作时间的规定 (1994年2月3日中华人民共和国国务院令第146号发布 根据1995年3月25日《国...
部门团建活动方案 部门团建活动方案(2篇)  为了确保事情或工作得以顺利进行,常常需要预先制定方案,方案指的是为某一次...
C语言函数:判断字符函数,判断... iscntrl:判断是否是控制字符isspace:判断是否是空白字符...这些函数的参数都是一个字符...
内核实验(八):实现O-NON... 一、篇头 继续使用qemu调试内核的实验。本章复习阻塞与非阻塞IO的概念和机制,然后对...
门店运营计划书 门店运营计划书(通用8篇)  光阴迅速,一眨眼就过去了,又迎来了一个全新的起点,此时此刻我们需要开始...
JavaWeb——Idea模板... Idea模板创建Servlet 第一步  第二步  第三步  此处的Servlet模板也可以定...
综合实践活动方案 综合实践活动方案(通用23篇)  为了确保工作或事情有序地进行,往往需要预先制定好方案,方案是从目的...
青少年体能训练计划方案 青少年体能训练计划方案  青少年体能训练计划方案(通用10篇)  为有力保证事情或工作开展的水平质量...
全国爱牙日活动方案   2014年9月20日是我国第二十四个全国“爱牙日”,为发挥家庭的优势和作用,提高家庭成员口腔保健...
第5讲 cameraserve... 本讲是Android Camera Native Framework专题的第5讲,我们...
11-STM32F1 -DMA... 11-STM32F1 -DMA(1) DMA:Data Memory A...
促销活动方案 实用的促销活动方案集锦9篇  为了确保工作或事情有序地进行,常常需要预先制定方案,方案是书面计划,是...
清明节主题党日活动方案 清明节主题党日活动方案(通用7篇)  为了确保活动有序有效开展,我们需要事先制定活动方案,活动方案是...
施工现场扬尘专项防治方案 施工现场扬尘专项防治方案  什么是方案  方案是从目的、要求、方式、方法、进度等都部署具体、周密,并...
家电促销活动方案 家电促销活动方案通用15篇  为保证事情或工作高起点、高质量、高水平开展,往往需要预先进行方案制定工...
考研408每周一题(2019 ... 2019年(单链表)         41.(13分)设线性表L=(a1,a2...