0. 前言
以前有同学好像做过一个叫“自习君”的App,开启后自动检测用户这一天的自习时间,在学校里宣传广告还打了不少。其实实现原理非常简单,在SQlite数据库(也可以通过文件)先预置众多应用的PackageName,比如QQ,微信等等,然后开启一个线程,不间断的获取到手机里的所有进程信息,如果检测到其中有processInfo.processName和预置的某个应用的PackageName相同,那么就认定为用户没有在“认真学习”,最后通过网络把数据上传到服务器,加上基于好友功能的“学霸时间”排行榜,最后集成社会化SDK的分享功能,这个App就完成了。
(PS:其实很多功能从技术角度来看,真的很简单。做应用还得看创意点,从这个角度来看的话,有些产品经理做的事情,并不是一个开发者那么容易就可以替代的。(*^__^*) )
最后吐槽一下上面的应用,因为它必定是耗电的,检测进程的子进程必定是频繁进行的(至少是一秒检测一次),不过用这个应用的学霸估计也不怎么玩手机,所以那点耗电估计也不会被在意吧。⊙﹏⊙‖∣
废话不多说,介绍本文的主要内容。本文原创,转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/51930645
1. 获取手机里的所有进程信息
以前写过一个ProcessInfoProviderUtil工具类,拿出来分享一个。通过Context.ACTIVITY_SERVICE和PagerManager不仅可以获取上面APP所需的进程名(也是PackageName),判断此进程是否为系统进程,还可以获取到该进程所占用的内存大小,应用名称以及应用图标。代码如下。其中ProcessInfo为自定义的业务类,成员变量即为要获取的信息,加上set/get方法即可。
/** * For Info of Process * Created by Calvin on 2016/4/24. */ public class ProcessInfoProviderUtil { public static List<ProcessInfo> getProcessInfos(Context context){ //创造要返回的集合 List<ProcessInfo> list = new ArrayList<ProcessInfo>(); PackageManager pm = (PackageManager)context.getPackageManager(); //拿到手机里的所有进程信息 ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses(); for(ActivityManager.RunningAppProcessInfo processInfo : runningAppProcesses) { //要添加的对象 ProcessInfo info = new ProcessInfo(); //包名即为进程名字 String packageName = processInfo.processName; info.setPackageName(packageName); //以进程号为参数,获得进程的信息(内存占用的大小) //使用时通过Formatter.formatFileSize(this,SystemProcessUitl.getAvaMemory(this))转换为MB即可 Debug.MemoryInfo[] processMemoryInfo = am.getProcessMemoryInfo(new int[]{processInfo.pid}); long totalPrivateDirty = processMemoryInfo[0].getTotalPrivateDirty()*1024l; info.setSize(totalPrivateDirty); //应用名字和图标 ApplicationInfo applicationInfo = null; try { applicationInfo = pm.getApplicationInfo(packageName, 0); String name = applicationInfo.loadLabel(pm).toString(); info.setName(name); Drawable icon = applicationInfo.loadIcon(pm); info.setIcon(icon); if ( (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)== 0 ){ //用户进程 info.setUesrProcess(true); }else { //系统进程 info.setUesrProcess(false); } } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } if(info.getName()!=null) { list.add(info); } } return list; } }
2. 杀死指定的进程
杀死进程很简单。其实就是调用ActivityManager的killBackgroundProcesses方法,这里我做了一个优化,即监听锁屏广播,在服务里创建内部广播接收者,锁屏后即循环杀死所有的进程。实现代码如下。当然,系统进程是不会被杀死的。这样就做到了一点省电优化。当然,自己需要的,即便是锁屏也想保持运行的后台进程,可以自定义一个集合维护需要被保护的进程,杀死之前自行判断即可。
/** * Service used to kill all user process when lock the phone * Created by user on 2016/4/26. */ public class AutoCleanService extends Service { private ScreenOffReceiver screenOffReceiver; private ActivityManager am; @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { am =(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); screenOffReceiver = new ScreenOffReceiver(); registerReceiver(screenOffReceiver,new IntentFilter(Intent.ACTION_SCREEN_OFF)); super.onCreate(); } @Override public void onDestroy() { unregisterReceiver(screenOffReceiver); screenOffReceiver = null; super.onDestroy(); } private class ScreenOffReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses(); for (ActivityManager.RunningAppProcessInfo info : runningAppProcesses){ //进程名字 即为包名 String processName = info.processName; //杀掉可以杀的 am.killBackgroundProcesses(processName); } } } }