转载请注明出处:http://blog.csdn.net/l1028386804/article/details/47277691
这篇文章是基于上一篇文章《Android之——获取进程、内存、任务列表》完善的,大家可以先阅读一下上一篇博文《Android之——获取进程、内存、任务列表》,做到心中有数。这篇文章中我主要向大家介绍,如何杀死我们在列表中选中的进程,释放进程所占用的空间。好了,不废话了,咱们直接进入主题吧。
老规矩,还是先唠叨一下这个原理级别的东东吧。
基于上一篇文章,我们在这篇博文中,为ListView中每个条目,增加一个CheckBox,同时,我们为获取到的每一个进程信息增加一个属性,标识是否为选中的状态。为了方便起见,我在这里创建两个上下文菜单,一个是全选功能,当点击这个菜单的时候,列表中除了当前应用的进程以外所有的进程信息,标注为选中状态;一个是“取消选择按钮”,当点击这个按钮的时候,取消所有应用进程的选中状态。点击UI最下方的“一键清理按钮”,则会杀死选中的应用程序进程,释放进程占用的资源。
原理唠叨完了,是不是很简单呢?下面,就让我们一起来实现这些功能吧!
这些功能实现起来并不困难,都是基于上一篇博文《Android之——获取进程、内存、任务列表》完善的,大家如果还没有阅读上一篇博文,请先阅读上一篇博文,这样才能充分理解这篇博文的内容。
这个类中,我们主要是更新了下获取系统所有的进程信息列表的方法getTaskInfos(),上一篇博文中,存在一个问题就是,Android系统中一个应用是由C或者C++编写的时候,它可能没有图标和名称,这时列表中就不会显示这些信息,这样给用户的体验不是很好,所有我在这个方法的异常捕获代码块中,为这样的应用程序设置了默认的图标和名称。
具体代码如下
/**
* 获取系统所有的进程信息列表
* @param context
* @return
*/
public static List<TaskInfo> getTaskInfos(Context context){
List<TaskInfo> taskInfos = new ArrayList<TaskInfo>();
PackageManager pm = context.getPackageManager();
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses();
for(RunningAppProcessInfo info : runningAppProcesses){
TaskInfo taskInfo = new TaskInfo();
//进程名称
String packageName = info.processName;
taskInfo.setPackageName(packageName);
try {
ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, 0);
//图标
Drawable task_icon = applicationInfo.loadIcon(pm);
if(task_icon == null){
taskInfo.setTask_icon(context.getResources().getDrawable(R.drawable.ic_launcher));
}else{
taskInfo.setTask_icon(task_icon);
}
//名称
String task_name = applicationInfo.loadLabel(pm).toString();
taskInfo.setTask_name(task_name);
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
taskInfo.setTask_icon(context.getResources().getDrawable(R.drawable.ic_launcher));
taskInfo.setTask_name(packageName);
}
//进程id
int pid = info.pid;
taskInfo.setPid(pid);
//获取进程占用的内存
android.os.Debug.MemoryInfo[] processMemoryInfo = am.getProcessMemoryInfo(new int[]{pid});
android.os.Debug.MemoryInfo memoryInfo = processMemoryInfo[0];
long totalPrivateDirty = memoryInfo.getTotalPrivateDirty(); //KB
taskInfo.setTask_memory(totalPrivateDirty);
taskInfos.add(taskInfo);
}
return taskInfos;
}
在这个类中,我新增一个boolean类型的字段,标识当前这个应用程序是否被选中了。
具体代码如下:
//选中状态
private boolean isChecked = false;
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean isChecked) {
this.isChecked = isChecked;
}
这个文件是ListView显示Item条目信息,我在这个文件中,新增了一个CheckBox按钮,使UI上能够直接看到当前应用程序是否被选中的状态,这样就可以一目了然了。
注意:CheckBox会抢夺屏幕焦点事件和点击事件,我们点击ListView条目时,不能改变CheckBox的选中状态,所有我在这个控件中加入了两个属性:
android:focusable="false"
android:clickable="false"这样就解决问题了。具体代码如下:
<!-- 新增checkBox控件 -->
<CheckBox
android:id="@+id/cb_task_manager_selected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:focusable="false"
android:clickable="false"
android:layout_alignParentRight="true"/>
这个文件主要是显示进程信息的主界面,在这个界面中我们主要的改动是,调整显示进程信息的列表高度,下面放置两个按钮,一个是“一键清理”,一个是“程序设置”,这里我们只对“一键清理”作事件处理,“程序设置”下篇博文将会涉及,敬请期待。
具体代码如下:
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="kill_process"
android:text="一键清理"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="程序设置"/>
</LinearLayout>
可以说,这个类是我们这个程序的主界面,这个类中,我增加一个一个属性字段ActivityManager,以它来调用杀死后台进程的方法,增加了两个常量,标识上下文菜单的id;在自定义适配器类TaskManagerAdapter中增加了CheckBox信息;同时创建了上下文菜单,一个是“全选”,一个是“取消选择”,分别处理了它们的点击事件;为ListView设置了条目点击事件;最后,重写了“一键清理”按钮的点击事件。
private static final int ALL_SELECTED_ID = 1; private static final int CANCEL_SELECTED_ID = 2; private ActivityManager am;
这个是我们新增的功能,这里,我自定义了一个类来实现OnItemClickListener接口,重写了onItemClick方法,具体的逻辑是:当应用程序原有的状态是选中时,我们将应用程序的状态设置为未选中,同时将CheckBox设置为未选中状态;当应用程序原有的状态是未选中时,我们将应用程序的状态设置为选中,同时将CheckBox设置为选中状态。
具体实现代码如下:
//ListView条目点击事件
private class MyOnItemClickListener implements OnItemClickListener{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
Log.i("i", "position ====== " +position);
CheckBox checkBox = ((ViewHolder) view.getTag()).cb_task_manager_selected;
TaskInfo taskInfo = (TaskInfo) mAdapter.getItem(position);
//如果是自身应用程序,则直接不执行下面的操作
if(taskInfo.getPackageName().equals(getPackageName())){
return;
}
if(taskInfo.isChecked()){
taskInfo.setChecked(false);
checkBox.setChecked(false);
}else{
taskInfo.setChecked(true);
checkBox.setChecked(true);
}
}
}之后,我们在onCreate()方法中,为ListView注册条目点击事件。
具体代码如下:
//设置条目点击事件 lv_taskmanage.setOnItemClickListener(new MyOnItemClickListener());
我在这里新增了CheckBox的信息,同时要注意无论怎么选择,当前应用程序是不能被选中的,否则当前应用程序的进程也会被杀死。所以,我在这里做了个判断,如果列进程列表中的某一个进程是当前应用程序的进程,则将CheckBox设置为不可见状态,这样就不能选中当前应用程序的进程了。
具体代码如下:
(1)自定义适配器的getView方法
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
ViewHolder holder = null;
if(convertView != null){
view = convertView;
holder = (ViewHolder) view.getTag();
}else{
view = mInflater.inflate(R.layout.task_manager_item, null);
holder = new ViewHolder();
holder.iv_task_manager_icon = (ImageView) view.findViewById(R.id.iv_task_manager_icon);
holder.iv_task_manager_name = (TextView) view.findViewById(R.id.tv_task_manager_name);
holder.iv_task_manager_memory = (TextView) view.findViewById(R.id.tv_task_manager_memory);
<span style="color:#FF0000;">//获取到UI上的CheckBox控件
holder.cb_task_manager_selected = (CheckBox) view.findViewById(R.id.cb_task_manager_selected);</span>
view.setTag(holder);
}
TaskInfo taskInfo = taskInfos.get(position);
holder.iv_task_manager_icon.setImageDrawable(taskInfo.getTask_icon());
holder.iv_task_manager_memory.setText("占用的内存:"+TextFormat.formatByte(taskInfo.getTask_memory()*1024));
holder.iv_task_manager_name.setText(taskInfo.getTask_name());
String packageName = taskInfo.getPackageName();
//应用程序是当前运行的程序
if(packageName.equals(getPackageName())){
holder.cb_task_manager_selected.setVisibility(View.GONE);
}else{
holder.cb_task_manager_selected.setVisibility(View.VISIBLE);
}
//获取条目的选中状态
boolean isChecked = taskInfo.isChecked();
if(isChecked){
holder.cb_task_manager_selected.setChecked(true);
}else{
holder.cb_task_manager_selected.setChecked(false);
}
return view;
}(2)更新ViewHolder /**
* ViewHolder
* @author liuyazhuang
*
*/
static class ViewHolder{
ImageView iv_task_manager_icon;
TextView iv_task_manager_name;
TextView iv_task_manager_memory;
//新增CheckBox属性
CheckBox cb_task_manager_selected;
}
这个方法是Android系统自带的一个回调方法,我们只需要重写这个方法即可
具体代码如下:
//创建上下文菜单的回调
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// TODO Auto-generated method stub
menu.add(0, ALL_SELECTED_ID, 0, "全选");
menu.add(0, CANCEL_SELECTED_ID, 0, "取消选择");
return super.onCreateOptionsMenu(menu);
}
这个方法,同样是Android系统自带的一个回调方法,我们只需要重写这个方法即可。当我们点击“全选”菜单时,除了当前应用程序以外的进程全部标注为选中状态,当我们点击“取消选择”按钮时,取消所有进程的选中状态,并通知ListView更新列表显示内容。
具体代码如下:
//上下文菜单的点击事件
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
int id = item.getItemId();
switch (id) {
case ALL_SELECTED_ID:
//将每个条目设置为选中状态
for(TaskInfo taskInfo : taskInfos){
//不修改自身应用程序的状态
if(!taskInfo.getPackageName().equals(getPackageName())){
taskInfo.setChecked(true);
}
}
//刷新列表
mAdapter.notifyDataSetChanged();
break;
case CANCEL_SELECTED_ID:
//将每个列表设置为不选中状态
for(TaskInfo taskInfo : taskInfos){
taskInfo.setChecked(false);
}
//刷新列表
mAdapter.notifyDataSetChanged();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
这个方法很简单,就是遍历所有的进程集合,杀死被选中的进程,释放进程所占用的资源。
具体代码实现如下:
/**
* 杀死进程
* @param v
*/
public void kill_process(View v){
for(TaskInfo taskInfo : taskInfos){
if(taskInfo.isChecked()){
//杀死选中的进程
am.killBackgroundProcesses(taskInfo.getPackageName());
}
}
}
杀死应用程序是需要权限的,我们需要在AndroidManifest.xml中配置相应的权限。
具体要配置的权限如下:
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
1、程序运行界面
2、选中某一个条目中的进程
3、取消选中某一个条目中的进程
4、上下文菜单
5、全选
6、取消全选
7、选择短信应用进行清理
8、清理结果
本实例中,为了方面,我把一些文字直接写在了布局文件中和相关的类中,大家在真实的项目中要把这些文字写在string.xml文件中,在外部引用这些资源,切记,这是作为一个Android程序员最基本的开发常识和规范,我在这里只是为了方便直接写在了类和布局文件中。
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文:http://blog.csdn.net/l1028386804/article/details/47277691