不知不觉已经写到了第八篇了,手机卫士作为一个复习基础的项目,我基本也快做完了,如果大家继续看完的话,基本做东西有思路了。
怎么让手机加入加速呢,其实安卓系统是本身不会这么卡的,只因为国内软件太过流氓了,导致内存占用很大,所以手机加速 就说下内存清理
如果看过上一节的软件管理器,应该会很快学懂,因为布局都差不多,还是一个复杂的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); } } } }