Android之——杀死选中的进程(释放进程占用的空间)

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/47277691

这篇文章是基于上一篇文章《Android之——获取进程、内存、任务列表》完善的,大家可以先阅读一下上一篇博文《Android之——获取进程、内存、任务列表》,做到心中有数。这篇文章中我主要向大家介绍,如何杀死我们在列表中选中的进程,释放进程所占用的空间。好了,不废话了,咱们直接进入主题吧。

一、原理

老规矩,还是先唠叨一下这个原理级别的东东吧。

基于上一篇文章,我们在这篇博文中,为ListView中每个条目,增加一个CheckBox,同时,我们为获取到的每一个进程信息增加一个属性,标识是否为选中的状态。为了方便起见,我在这里创建两个上下文菜单,一个是全选功能,当点击这个菜单的时候,列表中除了当前应用的进程以外所有的进程信息,标注为选中状态;一个是“取消选择按钮”,当点击这个按钮的时候,取消所有应用进程的选中状态。点击UI最下方的“一键清理按钮”,则会杀死选中的应用程序进程,释放进程占用的资源。

原理唠叨完了,是不是很简单呢?下面,就让我们一起来实现这些功能吧!

二、实现

这些功能实现起来并不困难,都是基于上一篇博文《Android之——获取进程、内存、任务列表》完善的,大家如果还没有阅读上一篇博文,请先阅读上一篇博文,这样才能充分理解这篇博文的内容。

1、更新TaskUtils类

这个类中,我们主要是更新了下获取系统所有的进程信息列表的方法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;
	}

2、更新实体类TaskInfo

在这个类中,我新增一个boolean类型的字段,标识当前这个应用程序是否被选中了。

具体代码如下:

//选中状态
	private boolean isChecked = false;
	
	public boolean isChecked() {
		return isChecked;
	}

	public void setChecked(boolean isChecked) {
		this.isChecked = isChecked;
	}

3、更新task_manager_item.xml

这个文件是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"/>

4、更新task_manager.xml

这个文件主要是显示进程信息的主界面,在这个界面中我们主要的改动是,调整显示进程信息的列表高度,下面放置两个按钮,一个是“一键清理”,一个是“程序设置”,这里我们只对“一键清理”作事件处理,“程序设置”下篇博文将会涉及,敬请期待。

具体代码如下:

1)对FrameLayout的改动

 <FrameLayout
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1" >

2)底部新增按钮

 <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>

5、更新TaskManagerActivity

可以说,这个类是我们这个程序的主界面,这个类中,我增加一个一个属性字段ActivityManager,以它来调用杀死后台进程的方法,增加了两个常量,标识上下文菜单的id;在自定义适配器类TaskManagerAdapter中增加了CheckBox信息;同时创建了上下文菜单,一个是“全选”,一个是“取消选择”,分别处理了它们的点击事件;为ListView设置了条目点击事件;最后,重写了“一键清理”按钮的点击事件。

1)新增字段

	private static final int ALL_SELECTED_ID = 1;
	private static final int CANCEL_SELECTED_ID = 2;
	private ActivityManager am;

2)新增ListView条目点击事件

这个是我们新增的功能,这里,我自定义了一个类来实现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());

3)更新自定义适配器和ViewHolder

我在这里新增了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;
	}

4)新增创建上下文菜单方法

这个方法是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);
	}

5)新增自定义菜单点击事件

这个方法,同样是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);
	}

6)实现“一键清理”按钮的点击事件

这个方法很简单,就是遍历所有的进程集合,杀死被选中的进程,释放进程所占用的资源。

具体代码实现如下:

	/**
	 * 杀死进程
	 * @param v
	 */
	public void kill_process(View v){
		for(TaskInfo taskInfo : taskInfos){
			if(taskInfo.isChecked()){
				//杀死选中的进程
				am.killBackgroundProcesses(taskInfo.getPackageName());
			}
		}
	}

6、注册权限

杀死应用程序是需要权限的,我们需要在AndroidManifest.xml中配置相应的权限。

具体要配置的权限如下:

<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>

三、运行效果

1、程序运行界面

2、选中某一个条目中的进程

3、取消选中某一个条目中的进程

4、上下文菜单

5、全选

6、取消全选

7、选择短信应用进行清理

8、清理结果

四、温馨提示

有关本文实例的优化方案,请大家阅读下一篇博文《Android之——杀死用户选中的进程优化》一文。

本实例中,为了方面,我把一些文字直接写在了布局文件中和相关的类中,大家在真实的项目中要把这些文字写在string.xml文件中,在外部引用这些资源,切记,这是作为一个Android程序员最基本的开发常识和规范,我在这里只是为了方便直接写在了类和布局文件中。

冰 河 CSDN认证博客专家 分布式与微服务 大数据与云计算 云原生
微信搜一搜【冰河技术】 ,关注后回复【PDF】领取冰河原创超硬核PDF电子书,海量面试资料和简历模板。冰河,《海量数据处理与大数据技术实战》,《MySQL技术大全:开发、优化与运维实战》作者,【冰河技术】公号作者,基于最终消息可靠性的开源分布式事务框架mykit-transaction-message作者。多年来致力于分布式系统架构、微服务、分布式数据库、分布式事务与大数据技术的研究。在高并发、高可用、高可扩展性、高可维护性和大数据等领域拥有丰富的架构经验。对Hadoop,Storm,Spark,Flink等大数据框架源码进行过深度分析,并具有丰富的实战经验。
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页
实付 9.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值