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); } } }}