Android项目实战--手机卫士29--杀死后台进程

昨天,我们就已经把那些进程给读取出来,然后再显示到界面上的啦,那么今天,我们就要做一个功能,那就是把进程杀死,达到我们的一键清理的功能

但是在做这个杀死进程的功能之前,我们先来修复一个bug先,大家先看下面的一张图

Android项目实战--手机卫士29--杀死后台进程_第1张图片

细心的朋友们可能就会看到的啦,我们在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;
	}

}

好啦,就 这样子,我们的这个bug就修复好的啦,大家可以测试一下,这一次拿到的进程数目就会和title上显示的是一致的啦


那么我们现在就可以来完成我们的杀死后台进程的这个功能啦,这个功能也是非常容易完成的,但在这之前,我们要先来处理一下我们的那个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"/>

我们把它的focusable和clickable都设置为false,这样子,它就无法抢夺listview的焦点的啦


那么,我们就可以来完成我们的杀死后台进程的操作啦,首先,我们就先把给我们的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);
					}
				}
			}
		});

首先,我们是会拿到我们所点击的条目所对应的那个对象啦,也就是adapter里面getItem所返回的对象啦,所以我们就判断一下,当它是TaskInfo类型的,那么就进行处理啦

为什么要这样子判断呢,那是因为我们有两个标签的嘛,它们也是会返回的,所以就要进行判断啦,如果点击所对应的对象是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);
	}

大家可以看到,杀死进程,就是调用了ActivityManager里面的一个方法killBackgroundProcesses,传递进去的是一个包名

因为我们要刷新界面嘛,而我们的界面是通过我们的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



今天源码下载



你可能感兴趣的:(Android开发,杀死进程,进程管理,项目实战,手机卫士)