当用户强制退出App,清空后台时,Activity和Service的onDestory()方法都将失效。此时若App的Service可以自启动,如何判断此时的Service是重启后的Service,并对其进行特定操作?一般来说我们可以用Service里onStartCommand方法里的参数进行判断,但今天将给出一种通过系统时钟判断的方法。
在此之前我们需要先了解Android框架中两个重要的类:ActivityManager和SystemClock。ActivityManager的功能是与系统所有正运行着的Activity进行交互,对在系统运行中的Activity相关信息进行管理和维护;并提供了相应的接口用户获取这些信息。在此我们通过ActivityManager下的RunningServiceInfo()方法获取正在运行的服务信息。SystemClock类是获取系统运行时间、系统时间的工具类,通过SystemClock下的uptimeMillis()方法和elapsedRealtime()方法,可分别获取系统从启动到当前的非休眠时间和系统从启动到现在的时间。
首先写一个Service的Bean来保存Service的信息:
/** * @classname ServiceBeanSys * @copyright lu.yi * @description App服务的Bean * @history * lu.yi 2014.12.30 16:55 0.5 创建 * * @author lu.yi * @version 0.5 2014.12.30 16:55 */ package com.luyi.model.sys; public class ServiceBeanSys { private String mServiceName; //Service Name private int mServicePid; //Service Pid private String mProcessName; //Process Name private boolean mStarted; //Service是否启动 public long mActiveSince; //Service初次启动的时间 public long mLastActivityTime; //Activity最近一次关联Service的时间 /** * 获取Service名称 * * @return Service名称 */ public String getServiceName() { return mServiceName; } /** * 设置Service名称 * * @param serviceName Service名称 */ public void setServiceName(String serviceName) { this.mServiceName = serviceName; } /** * 获取Service Pid * * @return Service Pid */ public int getServicePid() { return mServicePid; } /** * 设置Service Pid * * @param servicePid Service Pid */ public void setServicePid(int servicePid) { this.mServicePid = servicePid; } /** * 获取进程名称 * * @return 进程名称 */ public String getProcessName() { return mProcessName; } /** * 设置进程名称 * * @param processName 进程名称 */ public void setProcessName(String processName) { this.mProcessName = processName; } /** * 获取Service启动状态 * * @return true:已经启动 false:未启动 */ public boolean getStarted() { return mStarted; } /** * 设置Service启动状态 * * @param start Service启动状态 */ public void setStarted(boolean start) { this.mStarted = start; } /** * 获取Service初次启动的时间 * * @return Service初次启动的时间 */ public long getActiveSince() { return mActiveSince; } /** * 设置Service初次启动的时间 * * @param activeSince Service初次启动的时间 */ public void setActiveSince(long activeSince) { this.mActiveSince = activeSince; } /** * 获取Activity最近一次关联Service的时间 * * @return Activity最近一次关联Service的时间 */ public long getLastActivityTime() { return mLastActivityTime; } /** * 设置Activity最近一次关联Service的时间 * * @param lastActivityTime Activity最近一次关联Service的时间 */ public void setLastActivityTime(long lastActivityTime) { this.mLastActivityTime = lastActivityTime; } }在Service中获取当前系统活动的Service列表:
/** * 获取活动服务列表 * * @return 活动服务列表 */ public List<ServiceBeanSys> getRunningServiceInfo() { List<ServiceBeanSys> mProgressList = new ArrayList<ServiceBeanSys>(); ActivityManager mManager = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE); List<RunningServiceInfo> mRunningServiceList = mManager.getRunningServices(200); //获取当前活动的服务 /** 遍历活动进程列表 */ for (RunningServiceInfo runningServiceInfo : mRunningServiceList) { ServiceBeanSys mServiceBean = new ServiceBeanSys(); mServiceBean.setServiceName(runningServiceInfo.service.toString()); mServiceBean.setServicePid(runningServiceInfo.pid); mServiceBean.setProcessName(runningServiceInfo.process); mServiceBean.setStarted(runningServiceInfo.started); mServiceBean.setActiveSince(runningServiceInfo.activeSince); mServiceBean.setLastActivityTime(runningServiceInfo.lastActivityTime); mProgressList.add(mServiceBean); } /** end of for (RunningAppProcessInfo runningProcessInfo : mRunningProcessList) */ return mProgressList; }
判断当前Service是否是重新启动的Service,如果Service没有主动stop,unbind或通过系统后台强行停止,Service的启动时间只计最初启动时间且不因重新启动重置,但每重启一次Service绑定Activity的时间都会重置。在首次启动时getActiveSince()与getLastActivityTime()的时间差一般小于5,在此多留了余量因此取100。
/** * 判断Service是否重启 * * @param processName Service所在的进程名 * @return true:重启 false:非重启 */ public boolean isServiceRestart(String processName) { List<ServiceBeanSys> mServiceList = mRunningDALSys.getRunningServiceInfo(); /** 遍历当前的活动列表 */ for (ServiceBeanSys serviceBean : mServiceList) { /** 筛选出当前的目标Service */ if ((serviceBean.getProcessName() != null) && serviceBean.getProcessName().equals(processName)) { long mSleepTime = SystemClock.elapsedRealtime() - SystemClock.uptimeMillis(); //计算当前系统休眠的时间 long mRestartTime = serviceBean.getActiveSince() - serviceBean.getLastActivityTime(); //计算Service已经启动的时间 /** 通过时间差判断是否是重新启动的Service */ if (Math.abs(mRestartTime - mSleepTime) < 100) { return true; } /** end of if (Math.abs(mRestartTime - mSleepTime) < 100) */ } /** end of if ((serviceBean.getProcessName() != null) && serviceBean.getProcessName().equals(processName)) */ } /** end of for (ServiceBeanSys serviceBean : mServiceList) */ return false; }
这样就完成了对该Service是否是重启Service的判断。
ActivityManager类是Android中重要但又不常用的类,BAT旗下App的连锁唤醒也是依靠该类实现。其本身通过代理模式完成对Activity的管理,建议熟练掌握该类使用后去阅读其源代码,对于开发者加深对Android系统框架和通信机制的理解大有裨益。