昨天,我们就已经把那些进程给读取出来,然后再显示到界面上的啦,那么今天,我们就要做一个功能,那就是把进程杀死,达到我们的一键清理的功能
但是在做这个杀死进程的功能之前,我们先来修复一个bug先,大家先看下面的一张图
细心的朋友们可能就会看到的啦,我们在title上面的进程数目显示的是16个,但是在下面的用户进程和系统进程加起来也就只有13个,竟然会少了三个,那是为什么呢
其实,那少了的三个是因为,它是没有界面的,而且是没有对应的ApplicationInfo对象的,所以当我们通过包名来获取到相应的ApplicationInfo对象的时候,就会报错的啦
因为我们try catch了,所以我们的应用才不会挂掉。
那么我们今天就对这些特殊情况进程处理一下就可以的啦,我们就在catch块里面,把它的包名就设置成应用的名字就行啦,然后再给它加一个默认的图标
catch (Exception e) { e.printStackTrace(); //当遇到没有界面的和图标的一些进程时候的处理方式 taskInfo.setName(packageName); taskInfo.setSystemProcess(true); taskInfo.setIcon(defaultIcon); }
com.xiaobin.security.engine.TaskInfoProvider
package com.xiaobin.security.engine; import java.util.ArrayList; import java.util.List; import android.app.ActivityManager; import android.app.ActivityManager.RunningAppProcessInfo; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.os.Debug.MemoryInfo; import com.xiaobin.security.R; import com.xiaobin.security.domain.TaskInfo; public class TaskInfoProvider { private PackageManager packageManager; private ActivityManager activityManager; private Drawable defaultIcon; public TaskInfoProvider(Context context) { defaultIcon = context.getResources().getDrawable(R.drawable.ic_launcher); packageManager = context.getPackageManager(); activityManager = (ActivityManager) context .getSystemService(Context.ACTIVITY_SERVICE); } public List<TaskInfo> getAllTask( List<RunningAppProcessInfo> runningAppProcessInfos) { List<TaskInfo> taskInfos = new ArrayList<TaskInfo>(); for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcessInfos) { TaskInfo taskInfo = new TaskInfo(); int id = runningAppProcessInfo.pid; taskInfo.setId(id); String packageName = runningAppProcessInfo.processName; taskInfo.setPackageName(packageName); try { // ApplicationInfo是AndroidMainfest文件里面整个Application节点的封装 ApplicationInfo applicationInfo = packageManager .getPackageInfo(packageName, 0).applicationInfo; // 应用的图标 Drawable icon = applicationInfo.loadIcon(packageManager); taskInfo.setIcon(icon); // 应用的名字 String name = applicationInfo.loadLabel(packageManager) .toString(); taskInfo.setName(name); // 设置是否为系统应用 taskInfo.setSystemProcess(!filterApp(applicationInfo)); } catch (Exception e) { e.printStackTrace(); //当遇到没有界面的和图标的一些进程时候的处理方式 taskInfo.setName(packageName); taskInfo.setSystemProcess(true); taskInfo.setIcon(defaultIcon); } // 可以返回一个内存信息的数组,传进去的id有多少个,就返回多少个对应id的内存信息 MemoryInfo[] memoryInfos = activityManager .getProcessMemoryInfo(new int[] { id }); // 拿到占用的内存空间 int memory = memoryInfos[0].getTotalPrivateDirty(); taskInfo.setMemory(memory); taskInfos.add(taskInfo); taskInfo = null; } return taskInfos; } // 判断某一个应用程序是不是用户的应用程序,如果是返回true,否则返回false public boolean filterApp(ApplicationInfo info) { // 有些系统应用是可以更新的,如果用户自己下载了一个系统的应用来更新了原来的, // 它就不是系统应用啦,这个就是判断这种情况的 if ((info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { return true; } else if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0)// 判断是不是系统应用 { return true; } return false; } }
那么我们现在就可以来完成我们的杀死后台进程的这个功能啦,这个功能也是非常容易完成的,但在这之前,我们要先来处理一下我们的那个checkbox才行
因为我们是通过点击listview的item来进行选定,然后修改checkbox的状态的,但是现在,我们是无法点击listview里面的item的,因为焦点被checkbox抢过去啦
所以我们要在checkbox的布局文件里面指定两个属性
<CheckBox android:id="@+id/cb_process_manager_state" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginRight="10dip" android:focusable="false" android:clickable="false"/>
那么,我们就可以来完成我们的杀死后台进程的操作啦,首先,我们就先把给我们的listview添加一个点击事件啦
lv_process_list.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // adapter里面的getItem返回的值 Object obj = lv_process_list.getItemAtPosition(position); if (obj instanceof TaskInfo) { cb_process_state = (CheckBox) view .findViewById(R.id.cb_process_manager_state); TaskInfo taskInfo = (TaskInfo) obj; if (taskInfo.isCheck()) { taskInfo.setCheck(false); cb_process_state.setChecked(false); } else { taskInfo.setCheck(true); cb_process_state.setChecked(true); } } } });
为什么要这样子判断呢,那是因为我们有两个标签的嘛,它们也是会返回的,所以就要进行判断啦,如果点击所对应的对象是TaskInfo的对象,那么就根据它的check状态来设置checkbox的状态啦。
这样子,我们通过点击,就能设置好checkbox的状态啦,那么接下来,我们就要根据checkbox的状态,把那些选定了的进程给杀死
其实这个杀死后台进程也是非常简单的,只需要调用activityManager里面的一个方法就可以的啦,但我们麻烦的就是要刷新界面,所以我们写了一个方法
// 一键清理的函数 private void killTask() { int total = 0; int memorySize = 0; for (TaskInfo taskInfo : systemTaskInfos) { if(taskInfo.isCheck()) { // 杀死进程 activityManager.killBackgroundProcesses(taskInfo.getPackageName()); total++; memorySize += taskInfo.getMemory(); taskInfos.remove(taskInfo); } } for (TaskInfo taskInfo : userTaskInfos) { if(taskInfo.isCheck()) { activityManager.killBackgroundProcesses(taskInfo.getPackageName()); total++; memorySize += taskInfo.getMemory(); taskInfos.remove(taskInfo); } } Toast.makeText( this, "已经杀死了" + total + "个进程!释放了" + TextFormater.getSizeFromKB(memorySize) + "空间", Toast.LENGTH_SHORT).show(); //重新加载界面 adapter = new TaskInfoAdapter(); lv_process_list.setAdapter(adapter); }
因为我们要刷新界面嘛,而我们的界面是通过我们的list集合里面的数据进行显示的,所以我们就把用户进程和系统进程这两个集合做成了类的变量,然后遍历这两个集合
如果是选定了的,就杀死对应的进程,并移除掉这个对象,并累计杀死的进程数目与释放的内存空间,最后就是重新new一个adapter出来,然后刷新界面
在这里,我要和大家说一下,这个杀死进程,其实并不是真的可以把进程杀死的,其实有一些重要的进程,你一杀死它,它就会马上再开启的,所以并不可能杀死了,后台就没有的啦,大家要清楚认识到这一点
好啦,讲到这里,我们把后台进程干掉的功能也完成的啦,下一次我们就把一些小问题修复一下,如那个title的更新,下面把完成的activity粘出来
com.xiaobin.security.ui.ProcessManagerActivity
package com.xiaobin.security.ui; import java.util.ArrayList; import java.util.List; import android.annotation.SuppressLint; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.MemoryInfo; import android.app.ActivityManager.RunningAppProcessInfo; import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.Window; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.xiaobin.security.R; import com.xiaobin.security.domain.TaskInfo; import com.xiaobin.security.engine.TaskInfoProvider; import com.xiaobin.security.utils.TextFormater; public class ProcessManagerActivity extends Activity implements OnClickListener { private static final int LOAD_FINISH = 1; private TextView tv_process_count; private TextView tv_process_memory; private LinearLayout ll_process_load; private ListView lv_process_list; private Button bt_process_clear; private Button bt_process_setting; private CheckBox cb_process_state; private ActivityManager activityManager; private List<RunningAppProcessInfo> runningAppProcessInfos; private TaskInfoProvider taskInfoProvider; private List<TaskInfo> taskInfos; private TaskInfoAdapter adapter; private List<TaskInfo> userTaskInfos; private List<TaskInfo> systemTaskInfos; @SuppressLint("HandlerLeak") private Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case LOAD_FINISH: ll_process_load.setVisibility(View.INVISIBLE); adapter = new TaskInfoAdapter(); lv_process_list.setAdapter(adapter); break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); // 请求一个自己定义的title,但有一些Android系统是被修改过的, // 所以有可能是无法请求的,如乐Phone或小米的手机,这些系统是被修改过的, // 所以就要判断一下是否请求成功 boolean flags = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); setContentView(R.layout.process_manager); if (flags) { // 设置自定义的title getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.process_manager_title); } tv_process_count = (TextView) findViewById(R.id.tv_process_count); tv_process_memory = (TextView) findViewById(R.id.tv_process_memory); ll_process_load = (LinearLayout) findViewById(R.id.ll_process_load); lv_process_list = (ListView) findViewById(R.id.lv_process_list); bt_process_clear = (Button) findViewById(R.id.bt_process_clear); bt_process_setting = (Button) findViewById(R.id.bt_process_setting); bt_process_clear.setOnClickListener(this); bt_process_setting.setOnClickListener(this); initData(); lv_process_list.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // adapter里面的getItem返回的值 Object obj = lv_process_list.getItemAtPosition(position); if (obj instanceof TaskInfo) { cb_process_state = (CheckBox) view .findViewById(R.id.cb_process_manager_state); TaskInfo taskInfo = (TaskInfo) obj; if (taskInfo.isCheck()) { taskInfo.setCheck(false); cb_process_state.setChecked(false); } else { taskInfo.setCheck(true); cb_process_state.setChecked(true); } } } }); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.bt_process_clear: killTask(); break; case R.id.bt_process_setting: break; default: break; } } private void initData() { // 因为这个title是要显示当前进程数目和可用内存的,所以我们每次在这里都调用一下,以更新数据 initTitle(); ll_process_load.setVisibility(View.VISIBLE); new Thread(new Runnable() { @Override public void run() { taskInfoProvider = new TaskInfoProvider( ProcessManagerActivity.this); taskInfos = taskInfoProvider.getAllTask(runningAppProcessInfos); Message msg = new Message(); msg.what = LOAD_FINISH; handler.sendMessage(msg); } }).start(); } // 拿到当前运行的进程数目 private int getRunningAppCount() { runningAppProcessInfos = activityManager.getRunningAppProcesses(); return runningAppProcessInfos.size(); } // 拿到系统剩余的内存 private String getAvailMemory() { // new一个内存的对象 MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); // 拿到现在系统里面的内存信息 activityManager.getMemoryInfo(memoryInfo); // 拿到有效的内存空间 long size = memoryInfo.availMem; return TextFormater.dataSizeFormat(size); } // 设置title的信息 private void initTitle() { tv_process_count.setText("进程数目:" + getRunningAppCount()); tv_process_memory.setText("剩余内存:" + getAvailMemory()); } // 一键清理的函数 private void killTask() { int total = 0; int memorySize = 0; for (TaskInfo taskInfo : systemTaskInfos) { if (taskInfo.isCheck()) { // 杀死进程 activityManager.killBackgroundProcesses(taskInfo .getPackageName()); total++; memorySize += taskInfo.getMemory(); taskInfos.remove(taskInfo); } } for (TaskInfo taskInfo : userTaskInfos) { if (taskInfo.isCheck()) { activityManager.killBackgroundProcesses(taskInfo .getPackageName()); total++; memorySize += taskInfo.getMemory(); taskInfos.remove(taskInfo); } } Toast.makeText( this, "已经杀死了" + total + "个进程!释放了" + TextFormater.getSizeFromKB(memorySize) + "空间", Toast.LENGTH_SHORT).show(); // 重新加载界面 adapter = new TaskInfoAdapter(); lv_process_list.setAdapter(adapter); } // =========================================================================== private class TaskInfoAdapter extends BaseAdapter { public TaskInfoAdapter() { // 存放用户的应用进程 userTaskInfos = new ArrayList<TaskInfo>(); // 存放系统的应用进程 systemTaskInfos = new ArrayList<TaskInfo>(); for (TaskInfo taskInfo : taskInfos) { if (taskInfo.isSystemProcess()) { systemTaskInfos.add(taskInfo); } else { userTaskInfos.add(taskInfo); } } } @Override public int getCount() { // 加上两个标签,一个是系统标签,一个是用户标签 return taskInfos.size() + 2; } @Override public Object getItem(int position) { if (position == 0) { return 0; // 显示成用户应用的标签 } else if (position <= userTaskInfos.size()) { return userTaskInfos.get(position - 1); // 用户应用进程的条目 } else if (position == userTaskInfos.size() + 1) { return position; // 显示成系统进程的标签 } else if (position <= taskInfos.size() + 2) { // 系统应用进程的条目 return systemTaskInfos.get(position - userTaskInfos.size() - 2); } else { return position; } } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view; TaskInfoViews views; TaskInfo taskInfo; if (position == 0) { // 显示成用户应用的标签 return newTextView("用户进程(" + userTaskInfos.size() + ")"); } else if (position <= userTaskInfos.size()) { // 用户应用进程的条目 taskInfo = userTaskInfos.get(position - 1); } else if (position == userTaskInfos.size() + 1) { // 显示成系统进程的标签 return newTextView("系统进程(" + systemTaskInfos.size() + ")"); } else if (position <= taskInfos.size() + 2) { // 系统应用进程的条目 taskInfo = systemTaskInfos.get(position - userTaskInfos.size() - 2); } else { taskInfo = new TaskInfo(); } if (convertView == null || convertView instanceof TextView) { view = View.inflate(ProcessManagerActivity.this, R.layout.process_manager_item, null); views = new TaskInfoViews(); views.iv_process_icon = (ImageView) view .findViewById(R.id.iv_process_manager_icon); views.tv_process_name = (TextView) view .findViewById(R.id.tv_process_manager_name); views.tv_process_memory = (TextView) view .findViewById(R.id.tv_process_manager_memory); views.cb_process_state = (CheckBox) view .findViewById(R.id.cb_process_manager_state); view.setTag(views); } else { view = convertView; views = (TaskInfoViews) view.getTag(); } views.iv_process_icon.setImageDrawable(taskInfo.getIcon()); views.tv_process_name.setText(taskInfo.getName()); views.tv_process_memory.setText("占用内存:" + TextFormater.getSizeFromKB(taskInfo.getMemory())); views.cb_process_state.setChecked(taskInfo.isCheck()); return view; } private TextView newTextView(String title) { TextView tv_title = new TextView(ProcessManagerActivity.this); tv_title.setText(title); return tv_title; } } private class TaskInfoViews { ImageView iv_process_icon; TextView tv_process_name; TextView tv_process_memory; CheckBox cb_process_state; } }
最后,和大家说一下
为了方便大家的交流,我创建了一个群,这样子大家有什么疑问也可以在群上交流
群号是298440981
今天源码下载