不知不觉已经写到了第八篇了,手机卫士作为一个复习基础的项目,我基本也快做完了,如果大家继续看完的话,基本做东西有思路了。
怎么让手机加入加速呢,其实安卓系统是本身不会这么卡的,只因为国内软件太过流氓了,导致内存占用很大,所以手机加速 就说下内存清理
如果看过上一节的软件管理器,应该会很快学懂,因为布局都差不多,还是一个复杂的listview布局
本章涉及到知识点:
1.你猜
2.SP的使用
3.listview的复杂布局
OK ,我还是按照我写教程的思路,先看布局
①.布局的编写
布局就和软件管理器差不多,我就不叙述了。直接看代码吧,源代码在后面供下载,因为在一个测试项目中写的,所以只贴这一部分代码。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/tv_process_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="运行中的进程:"
android:textColor="#000000" />
<TextView
android:id="@+id/tv_mem_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="剩余/总内存"
android:textColor="#000000" />
</RelativeLayout>
<FrameLayout
android:layout_weight="9999"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="@+id/ll_loading"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="invisible" >
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在加载程序信息..." />
</LinearLayout>
<ListView
android:id="@+id/lv_task_manager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fastScrollEnabled="true"
android:overScrollMode="never" >
</ListView>
<TextView
android:id="@+id/tv_status"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#ff888888"
android:textColor="#ffffff" />
</FrameLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:onClick="selectAll"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="全选" />
<Button
android:onClick="selectOppo"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="反选" />
<Button
android:onClick="killAll"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="清理" />
<Button
android:onClick="enterSetting"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="设置" />
</LinearLayout>
</LinearLayout>
② 编写获取进程,内存的工具类
既然是工具类,就单独建立,也是单独抽出来,以后用到这部分就直接调用就行了。
在安卓系统里面,manager 管理器有很多, PackageManager ActivityManager 本章只用到了这两个,我就说下他在安卓系统里面的应用吧。
1 .PackageManager //包管理器 相当于程序管理器。静态的内容。
2.ActivityManager 进程管理器。管理的手机的活动信息。动态的内容。
一 获取正在运行的进程的数量
既然是进程了,就是动态的内容了,我们就用ActivityManager
/**
* 获取正在运行的进程的数量
* @param context 上下文
* @return
*/
public static int getRunningProcessCount(Context context){
ActivityManager am =(ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
//获得正在运行的进程
List<RunningAppProcessInfo> infos = am.getRunningAppProcesses();
return infos.size();
}
二,获取手机可用剩余内存
内存也是动态内容不是,SO 我们也用ActivityManager
/**
* 获取手机可用的剩余内存
* @param context 上下文
* @return
*/
public static long getAvailMem(Context context){
ActivityManager am =(ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
//得到内存要存在MemoryInfo中
MemoryInfo outInfo = new MemoryInfo();
am.getMemoryInfo(outInfo);
return outInfo.availMem;
}
三,获取手机可用总内存
这个时候,因为要考虑到 2.3和4.0的兼容,如果只考虑4.0的话 很简单就是和上面的思路基本一样
// ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
// MemoryInfo outInfo = new MemoryInfo();
// am.getMemoryInfo(outInfo);
// return outInfo.totalMem;
但是呢,这中方法在4.0以下的手机实现不了 得用下面方法
try {
File file = new File("/proc/meminfo");
FileInputStream fis = new FileInputStream(file);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
String line = br.readLine();
//MemTotal: 513000 kB
StringBuilder sb = new StringBuilder();
for(char c: line.toCharArray()){
if(c>='0'&&c<='9'){
sb.append(c);
}
}
return Long.parseLong(sb.toString())*1024;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
利用这个类,可以将UI界面最上面的 数据获取到了 。OK,我们继续
③,编写提供手机信息的进程工具类
这个和上一节或许手机软件信息类一样的思路
县建立实体类,存储东西
package com.example.Darkbutton.TaskmanagerDemo;
import android.graphics.drawable.Drawable;
/**
* @author xiaoxin007
* 2014-12-7上午2:26:48
* TODO 进程信息的业务bean
*/
public class TaskInfo {
//应用图标
private Drawable icon;
//应用名字
private String name;
//包名
private String packname;
//内存大小
private long memsize;
//是否选中
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
}
private boolean checked;
/**
* true用户进程 false系统进程
*/
private boolean userTask;
public Drawable getIcon() {
return icon;
}
public void setIcon(Drawable icon) {
this.icon = icon;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPackname() {
return packname;
}
public void setPackname(String packname) {
this.packname = packname;
}
public long getMemsize() {
return memsize;
}
public void setMemsize(long memsize) {
this.memsize = memsize;
}
public boolean isUserTask() {
return userTask;
}
public void setUserTask(boolean userTask) {
this.userTask = userTask;
}
@Override
public String toString() {
return "TaskInfo [name=" + name + ", packname=" + packname
+ ", memsize=" + memsize + ", userTask=" + userTask + "]";
}
}
利用获取的到信息 储存起来
package com.example.Darkbutton.TaskmanagerDemo;
import java.util.ArrayList;
import java.util.List;
import com.example.Darkbutton.R;
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.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable;
import android.os.Debug.MemoryInfo;
/**
* @author xiaoxin007
* 2014-12-7上午2:25:27
* TODO 提供手机里面的进程信息
*/
public class TaskInfoProvider {
public static List<TaskInfo> getTaskInfos(Context context){
PackageManager pm = context.getPackageManager();
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
List<TaskInfo> taskInfos = new ArrayList<TaskInfo>();
for(RunningAppProcessInfo processInfo : processInfos){
TaskInfo taskInfo = new TaskInfo();
//得到应用程序的包名。
String packname = processInfo.processName;
//设置包名
taskInfo.setPackname(packname);
//得到内存大小
MemoryInfo[] memoryInfos = am.getProcessMemoryInfo(new int[]{processInfo.pid});
long memsize = memoryInfos[0].getTotalPrivateDirty()*1024l;
taskInfo.setMemsize(memsize);
try {//下面步骤和软件管理器那个类是一样的
ApplicationInfo applicationInfo = pm.getApplicationInfo(packname, 0);
//得到程序图标
Drawable icon = applicationInfo.loadIcon(pm);
//设置图标
taskInfo.setIcon(icon);
//得到名字
String name = applicationInfo.loadLabel(pm).toString();
//设置名字
taskInfo.setName(name);
//分离出那些事用户进程那些是系统进程
if((applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0){
//用户进程
taskInfo.setUserTask(true);
}else{
//系统进程
taskInfo.setUserTask(false);
}
} catch (NameNotFoundException e) {
e.printStackTrace();
//系统进程得不到的默认设置其图片
taskInfo.setIcon(context.getResources().getDrawable(R.drawable.ic_launcher));
taskInfo.setName(packname);
}
taskInfos.add(taskInfo);
}
return taskInfos;
}
}
④利用获取的信息,在ui界面更新
基本也就是初始化组件,初始化数据,给Listview填充数据,主要是adapter 那里逻辑有点复杂
一 初始化控件
/**
* 初始化控件
*/
private void initView() {
//剩余/总内存
tv_mem_info = (TextView) findViewById(R.id.tv_mem_info);
//运行中的进程:
tv_process_count = (TextView) findViewById(R.id.tv_process_count);
ll_loading = (LinearLayout) findViewById(R.id.ll_loading);
lv_task_manager = (ListView) findViewById(R.id.lv_task_manager);
//占位条
tv_status = (TextView) findViewById(R.id.tv_status);
}
二,设置标题
/**
* 设置标题
*/
private void setTitle() {
processCount = SystemInfoUtils.getRunningProcessCount(this);
tv_process_count.setText("运行中的进程:" + processCount + "个");
availMem = SystemInfoUtils.getAvailMem(this);
totalMem = SystemInfoUtils.getTotalMem(this);
tv_mem_info.setText("剩余/总内存:"
+ Formatter.formatFileSize(this, availMem) + "/"
+ Formatter.formatFileSize(this, totalMem));
}
三,给Listview填充数据
因为这里是一个耗时操作,所以为了用户体验,应该加入一个progressbar 进行显示,填充数据放在线程里面,然后用 runOnUiThread 进行界面更新
/**
* 填充Listview数据
*/
private void fillData() {
ll_loading.setVisibility(View.VISIBLE);
new Thread() {
public void run() {
allTaskInfos = TaskInfoProvider
.getTaskInfos(getApplicationContext());
userTaskInfos = new ArrayList<TaskInfo>();
systemTaskInfos = new ArrayList<TaskInfo>();
//遍历获得用户进程和系统进程
for (TaskInfo info : allTaskInfos) {
if (info.isUserTask()) {
userTaskInfos.add(info);
} else {
systemTaskInfos.add(info);
}
}
// 更新设置界面。
runOnUiThread(new Runnable() {
@Override
public void run() {
ll_loading.setVisibility(View.INVISIBLE);
if (adapter == null) {
adapter = new TaskManagerAdapter();
lv_task_manager.setAdapter(adapter);
} else {
adapter.notifyDataSetChanged();
}
setTitle();
}
});
};
}.start();
}
四,adapter的复杂逻辑
/**
* @author xiaoxin007
* 2014-12-7上午3:04:53
* TODO 减少控件findbyid的次数
*/
static class ViewHolder {
ImageView iv_icon;
TextView tv_name;
TextView tv_memsize;
CheckBox cb_status;
}
private class TaskManagerAdapter extends BaseAdapter {
//因为在下方有一个设置界面 设置显示系统应用 所以在这里进行设置
SharedPreferences sp = getSharedPreferences("config", MODE_PRIVATE);
@Override
public int getCount() {
if (sp.getBoolean("showsystem", false)) {
return userTaskInfos.size() + 1 + systemTaskInfos.size() + 1;
}else{
return userTaskInfos.size() + 1 ;
}
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TaskInfo taskInfo;
if (position == 0) {// 用户进程的标签
TextView tv = new TextView(getApplicationContext());
tv.setBackgroundColor(Color.GRAY);
tv.setTextColor(Color.WHITE);
tv.setText("用户进程:" + userTaskInfos.size() + "个");
return tv;
} else if (position == (userTaskInfos.size() + 1)) {
TextView tv = new TextView(getApplicationContext());
tv.setBackgroundColor(Color.GRAY);
tv.setTextColor(Color.WHITE);
tv.setText("系统进程:" + systemTaskInfos.size() + "个");
return tv;
}else if (position <= userTaskInfos.size()) {
taskInfo = userTaskInfos.get(position - 1);
} else {
taskInfo = systemTaskInfos.get(position - 1
- userTaskInfos.size() - 1);
}
View view;
ViewHolder holder;
if (convertView != null && convertView instanceof RelativeLayout) {
view = convertView;
holder = (ViewHolder) view.getTag();
} else {
view = View.inflate(getApplicationContext(),
R.layout.list_item_taskinfo, null);
holder = new ViewHolder();
holder.iv_icon = (ImageView) view
.findViewById(R.id.iv_task_icon);
holder.tv_name = (TextView) view
.findViewById(R.id.tv_task_name);
holder.tv_memsize = (TextView) view
.findViewById(R.id.tv_task_memsize);
holder.cb_status = (CheckBox) view.findViewById(R.id.cb_status);
view.setTag(holder);
}
holder.iv_icon.setImageDrawable(taskInfo.getIcon());
holder.tv_name.setText(taskInfo.getName());
holder.tv_memsize.setText("内存占用:"
+ Formatter.formatFileSize(getApplicationContext(),
taskInfo.getMemsize()));
holder.cb_status.setChecked(taskInfo.isChecked());
//如果是本机就会隐藏其checkbox
if (getPackageName().equals(taskInfo.getPackname())) {
holder.cb_status.setVisibility(View.INVISIBLE);
} else {
holder.cb_status.setVisibility(View.VISIBLE);
}
return view;
}
}
五,接下来是下方四个button的点击事件处理
/**
* 选中全部
*
* @param view
*/
public void selectAll(View view) {
for (TaskInfo info : allTaskInfos) {
if (getPackageName().equals(info.getPackname())) {
continue;
}
info.setChecked(true);
}
adapter.notifyDataSetChanged();
}
/**
* 选中相反的
*
* @param view
*/
public void selectOppo(View view) {
for (TaskInfo info : allTaskInfos) {
if (getPackageName().equals(info.getPackname())) {
continue;
}
info.setChecked(!info.isChecked());
}
adapter.notifyDataSetChanged();
}
/**
* 一键清理
*
* @param view
*/
public void killAll(View view) {
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int count = 0;
long savedMem = 0;
// 记录那些被杀死的条目
List<TaskInfo> killedTaskinfos = new ArrayList<TaskInfo>();
for (TaskInfo info : allTaskInfos) {
if (info.isChecked()) {// 被勾选的,杀死这个进程。
am.killBackgroundProcesses(info.getPackname());
if (info.isUserTask()) {
userTaskInfos.remove(info);
} else {
systemTaskInfos.remove(info);
}
killedTaskinfos.add(info);
count++;
savedMem += info.getMemsize();
}
}
allTaskInfos.removeAll(killedTaskinfos);
adapter.notifyDataSetChanged();
Toast.makeText(
this,
"杀死了" + count + "个进程,释放了"
+ Formatter.formatFileSize(this, savedMem) + "的内存", 1)
.show();
processCount -= count;
availMem += savedMem;
tv_process_count.setText("运行中的进程:" + processCount + "个");
tv_mem_info.setText("剩余/总内存:"
+ Formatter.formatFileSize(this, availMem) + "/"
+ Formatter.formatFileSize(this, totalMem));
}
/**
* 进入设置
*
* @param view
*/
public void enterSetting(View view) {
Intent intent = new Intent(this, TaskSettingActivity.class);
startActivityForResult(intent, 0);
}
因为设置了 系统应用再返回,我们就要刷新一下数据所以 ,要加入一个 onActivityResult
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
adapter.notifyDataSetChanged();
super.onActivityResult(requestCode, resultCode, data);
}
⑤ 设置页面的简单业务逻辑
基本就是checkbox的按钮 sp缓存 用服务检测是否存在去检验是否被选中
package com.example.Darkbutton.TaskmanagerDemo;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import com.example.Darkbutton.R;
import com.example.Darkbutton.Utils.ServiceUtils;
public class TaskSettingActivity extends Activity {
private CheckBox cb_show_system;
private CheckBox cb_auto_clean;
private SharedPreferences sp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_task_setting);
sp = getSharedPreferences("config", MODE_PRIVATE);
cb_show_system = (CheckBox) findViewById(R.id.cb_show_system);
cb_auto_clean = (CheckBox) findViewById(R.id.cb_auto_clean);
cb_show_system.setChecked(sp.getBoolean("showsystem", false));
cb_show_system
.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
Editor editor = sp.edit();
editor.putBoolean("showsystem", isChecked);
editor.commit();
}
});
cb_auto_clean.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// 锁屏的广播事件是一个特殊的广播事件,在清单文件配置广播接收者是不会生效的。
// 只能在代码里面注册里面才会生效。
Intent intent = new Intent(TaskSettingActivity.this,
AutoCleanService.class);
if (isChecked) {
startService(intent);
} else {
stopService(intent);
}
}
});
};
@Override
protected void onStart() {
boolean running = ServiceUtils.isServiceRunning(this,
"com.example.Darkbutton.TaskmanagerDemo.AutoCleanService");
cb_auto_clean.setChecked(running);
super.onStart();
}
}
检测服务是否存在工具类
package com.example.Darkbutton.Utils;
import java.util.Iterator;
import java.util.List;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.Context;
public class ServiceUtils {
/**
* 检验某个服务是否活着
* @param context
* @param service 服务的包名
* @return
*/
public static boolean isServiceRunning(Context context ,String service){
ActivityManager am=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningServiceInfo> infos = am.getRunningServices(100);
for (RunningServiceInfo info : infos) {
String name = info.service.getClassName();
if (service.equals(name)) {
return true;
}
}
return false;
}
}
接着就是 锁屏清理内存 建立一个服务,在里面手动注册一个广播,因为 安卓规定了 在配置文件中注册是无法生效的 只能代码中手动注册
package com.example.Darkbutton.TaskmanagerDemo;
import java.util.List;
import android.app.ActivityManager;
import android.app.Service;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.util.Log;
public class AutoCleanService extends Service {
private ScreenOffReceiver receiver;
private ActivityManager am;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
registerReceiver(receiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
super.onCreate();
}
@Override
public void onDestroy() {
unregisterReceiver(receiver);
receiver = null;
super.onDestroy();
}
private class ScreenOffReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Log.i("ScreenOffReceiver","屏幕锁屏了。。。");
List<RunningAppProcessInfo> infos = am.getRunningAppProcesses();
for(RunningAppProcessInfo info:infos){
am.killBackgroundProcesses(info.processName);
}
}
}
}
点击下载源码