前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android开发笔记(八十)运行状态检查

Android开发笔记(八十)运行状态检查

作者头像
aqi00
发布2019-01-18 13:01:02
5830
发布2019-01-18 13:01:02
举报
文章被收录于专栏:老欧说安卓老欧说安卓

大家都知道刻舟求剑的寓言故事,说的是事物是发展变化着的,如果拘泥于原来的情况,那随着情况的改变,就不会得到预期的结果。同样,影响app运行的因素,并不只是外部环境(如硬件、系统、权限等等),还包括app自身的运行信息。如果app的运行状态发生了变化,那么原先处理正确的逻辑也可能处理失败,所以在特定的情况下,我们得对app的运行情况进行检查。

apk安装信息

启动app的时候,常常会检查当前apk的安装信息,以此判断接下来要做哪些准备工作,举例如下: 1、获得apk的版本号,针对不同版本,分别对SQLite的数据库表做相应的变更操作。 2、获得apk的签名,据此判断安装包是否为合法来源。签名的介绍参见《Android开发笔记(七十三)代码混淆与反破解》。 3、获得apk的申请权限,从而判断app是否申请了相应的权限。权限的介绍参见《Android开发笔记(七十九)资源与权限校验》。 PackageManager类便是获取apk安装信息的工具,该类的getPackageInfo方法即可获得相应的安装信息。下面是getPackageInfo方法中常用标志位参数的说明: GET_ACTIVITIES : 获取活动Activity列表。列表信息是PackageInfo对象的activities参数。 GET_RECEIVERS : 获取广播接收器Receiver列表。列表信息是PackageInfo对象的receivers参数。 GET_SERVICES : 获取服务Service列表。列表信息是PackageInfo对象的services参数。 GET_SIGNATURES : 获取签名列表。列表信息是PackageInfo对象的signatures参数。 GET_PERMISSIONS : 获取权限列表。列表信息是PackageInfo对象的requestedPermissions参数。 获得PackageInfo实例的代码如下:

代码语言:javascript
复制
PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), 0);

下面是PackageInfo类常用的通用参数说明: packageName : 包名 versionName : 版本名称 versionCode : 版本代码 firstInstallTime : 首次安装时间 lastUpdateTime : 最后更新时间

多进程时判断是否为主进程

通常我们会在Application的扩展类中初始化全局变量,方便后续的信息交互,Application的介绍参见《Android开发笔记(二十八)利用Application实现内存读写》。有时候我们又会使用多进程模式,让服务运行在单独的进程中,这样就造成一个问题:新进程是由主进程原样fork出来,即新进程也会执行Application的onCreate方法。但是按照我们的本意,新进程只是为了运行单独的服务,并不需要初始化不相关的全局变量,因此这时候就得判断当前进程是否为主进程。 下面是判断是否为主进程的示例代码:

代码语言:javascript
复制
	public static boolean isMainProcess(Context ctx) {
		String processName = "";
		ActivityManager actMgr = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
		for (ActivityManager.RunningAppProcessInfo appProcess : actMgr.getRunningAppProcesses()) {
			if (appProcess.pid == Process.myPid()) {
				processName = appProcess.processName;
				Log.d(TAG, "packageName=" + ctx.getPackageName());
				Log.d(TAG, "processName=" + processName);
			}
		}
		if (ctx.getPackageName().equals(processName)) {
			return true;
		} else {
			return false;
		}
	}

下面是Application扩展类中的调用代码:

代码语言:javascript
复制
public class MainApplication extends Application {
	private final static String TAG = "MainApplication";
	
	@Override
	public void onCreate() {
		super.onCreate();
		if (ActivityUtil.isMainProcess(getApplicationContext()) == true) {
			//下面初始化主进程的参数
			Log.d(TAG, "当前是主进程");
		} else {
			//这里是分支进程,不处理主进程的参数
			Log.d(TAG, "当前是分支进程");
		}
	}
	
}

Activity是否存在

一般在Activity代码中都是直接操作页面上的元素,不过有时候得小心,页面在操作UI前就不存在了,其中的一个例子可见《Android开发笔记(七十五)内存泄漏的处理》。在上面这篇文章中,我们为了防止Handler的内存泄漏,给Activity加了个弱引用对象,由于弱引用是可以被回收的,因此在使用前得判断弱引用对象是否为空,只有对象非空,才能操作其上的UI元素。 除了上面的例子,还有其它情况可能导致操作UI时的页面丢失,基本上都是些异步操作造成的,比如说处理线程消息的Handler,以及广播接收器BroadcastReceiver。这些情况要想判断Activity页面是否存在,就得借助于ActivityManager的getRunningTasks方法,详细代码如下:

代码语言:javascript
复制
	public static boolean isActivityWork(Context ctx, String activityName) {
	    boolean isWork = false;
	    ActivityManager actMgr = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
	    List<RunningTaskInfo> taskList = actMgr.getRunningTasks(1024);
	    for (int i = 0; i < taskList.size(); i++) {
	        String name = taskList.get(i).topActivity.getClassName();
	        Log.d(TAG, "i="+i+", activity name="+name);
	        if (name.equals(activityName) == true) {
	            isWork = true;
	            break;
	        }
	    }
	    return isWork;
	}

Service是否存在

与Activity类似,Service也可能被安全软件杀死,导致使用该服务报空指针异常(比如接收广播后调用startForeground方法)。判断后台服务是否存在,与活动的判断一样,都是采用ActivityManager工具类,不同的是,该工具获取服务列表调用的是getRunningServices方法,详细代码如下:

代码语言:javascript
复制
	public static boolean isServiceWork(Context ctx, String serviceName) {
	    boolean isWork = false;
	    ActivityManager actMgr = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
	    List<RunningServiceInfo> serviceList = actMgr.getRunningServices(1024);
	    for (int i = 0; i < serviceList.size(); i++) {
	        String name = serviceList.get(i).service.getClassName().toString();
	        Log.d(TAG, "i="+i+", service name="+name);
	        if (name.equals(serviceName) == true) {
	            isWork = true;
	            break;
	        }
	    }
	    return isWork;
	}

点击下载本文用到的运行状态检查的工程代码 点此查看Android开发笔记的完整目录

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年03月15日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • apk安装信息
  • 多进程时判断是否为主进程
  • Activity是否存在
  • Service是否存在
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档