手机卫士
讲师:杨光福
Day8
72_ 进程管理器的标题栏_41
1、参照金山手机卫士的进程管理
2、创建TaskManagerActvity并在功能清单文件注册。
布局文件基于软件管理界面修改一下。并且修改对应的文字和ID;
运行中的内存:tv_process_count
剩余/总内存:tv_mem_info --memory内存
初始化两个TextView
初始化ActivityManager am;看一看里面要用到的方法;
3.在com.itheima.mobilesafe.utils目录下创建SystemInfoUtils工具类
获取正在运行中进程的总个数:
public static int getRunningProcessCount(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
return am.getRunningAppProcesses().size();
}
获取手机可用的内存信息ram
public static long getAvailRam(Context context){
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
MemoryInfo outInfo = new MemoryInfo();
am.getMemoryInfo(outInfo);
return outInfo.availMem;//byte 为单位的long类型的可用内存大小}
获取手机可用的总内存信息ram
public static long getTotalRam(Context context){
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
MemoryInfo outInfo = new MemoryInfo();
am.getMemoryInfo(outInfo);
return outInfo.totalMem;
}
4、正在运行进程数量、可用ram内存、总内存定义成成员变量
//正在运行的进程数量
private int runningProcessCount ;
//可用内存ram
private long availRam ;
//总的内存ram
private long totalRam;
显示部分代码
tv_process_count.setText("运行中的进程:" + runningProcessCount + "个");
tv_mem_info.setText("剩余/总内存:"
+ Formatter.formatFileSize(this, availRam) + "/"
+ Formatter.formatFileSize(this, totalRam));
5、解决API不兼容报错
Problems 问题
A,讲解报错的原因:在16版本才能用这个API,我们清单文件最低支持9
B,解决方式--直接删除,运行正常显示;
C,人为造错误,删除,运行演示,进入页面崩溃;
6、了解处理器信息命令
查看设备命名:adb devices
进入某一个设备:adb -s emulator-5554 shell
看目录结构:ls
进入proc:cd proc
查看里面文件:ls
Bingder说明:绑定一个服务,返回一个binder,虚拟的设备用它来表示;
cpuinfo:处理器信息;
详细列出文件信息命令:ls -l
查看打开处理器文件信息命令:cat cpuinfo
处理器是奔腾4 1500兆赫兹相当于2004年2005年左右主流的处理器;所以我们模拟器运行起来比默认的要快得多。
切换到arm模拟器:ctrl+c
进入arm模拟器:adb -s emulator-5556 shell
打开cpuinfo处理器文件:cat /proc/cpuinfo
处理器是393.21兆赫兹,比加速的处理器速度慢 5倍左右
7.查看内存信息meminfo 和cpuinfo在同一目录
查看命令:cat meminfo
到电脑打开计算器命令:calc
计算可用总内存信息和金山手机计算出来的比较一下是否一样;
MemFree 可用的内存空间
Cached 缓存内存
8、写具体读去meminfo文件得到内存大小
public static long getTotalRam(Context context) {
try {
File file = new File("/proc/meminfo");
FileInputStream fis = new FileInputStream(file);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(fis));
// MemTotal: 516452 kB * 1024 = byte
String line = bufferedReader.readLine();
StringBuffer buffer = new StringBuffer();
for (char c : line.toCharArray()) {
if (c >= '0' && c <= '9') {
buffer.append(c);
}
}
return (Integer.parseInt(buffer.toString()) * 1024l);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
知识拓展,有限山寨手机人为修改配置。就是修改设置页面的信息展示。市面上的软件,得到手机内存大小和信息也是读取这些文件的信息;
例如:鲁大师,安兔兔
73_得到所有进程信息并显示_30
1、在com.ithiema.mobilesafe.engine目录下创建TaskInfoProvider
A:创建方法getTaskInfos(Context context)用于得到系统正在运行的进程信息。
B:创建实例TaskInfo
public class TaskInfo {
private Drawable icon;
private String name;
/**
* byte 为单位
*/
private long memsize;
private boolean userTask;
private String packageName;
}
2、得到系统正在运行的进程信息
public static List
List
ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List
// 得到包管理器
PackageManager pm = context.getPackageManager();
for (RunningAppProcessInfo info : processInfos) {
TaskInfo taskInfo= new TaskInfo();
// 注意导包android.os.Debug.MemoryInfo
MemoryInfo[] memoryInfo = am
.getProcessMemoryInfo(new int[] { info.pid });
//进程在虚拟机的大小
// memoryInfo[1].dalvikPrivateDirty;
//进程在本地运行的大小-jni调用的C代码运行的大小
// memoryInfo[1].nativePrivateDirty;
// 单位是kb
int memory = memoryInfo[0].getTotalPrivateDirty();
// 内存占用大小
long memorySize = memory * 1024L;
taskInfo.setMemSize(memorySize);
// 包名、进程名
String packageName = info.processName;
taskInfo.setPackageName(packageName);
try {
PackageInfo packInfo = pm.getPackageInfo(packageName, 0);
// 图标
Drawable icon = packInfo.applicationInfo.loadIcon(pm);
taskInfo.setIcon(icon);
// 软件名称
String name = packInfo.applicationInfo.loadLabel(pm).toString();
taskInfo.setName(name);
int falgs = packInfo.applicationInfo.flags;
if ((falgs & ApplicationInfo.FLAG_SYSTEM) == 0) {
// 用户进程
taskInfo.setUserTask(true);
} else {
// 系统进程
taskInfo.setUserTask(false);
}
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
infos.add(taskInfo);
}
return infos;
}
3、在界面上显示信息
A:初始化ListView,和加载效果布局
list_task_item = (ListView) findViewById(R.id.list_task_item);
ll_loading = (LinearLayout) findViewById(R.id.ll_loading);
B:在onCreate()创建方法fillData()并在里面创建线程,初始化数据。
private void fillData() {
ll_loading.setVisibility(View.VISIBLE);
new Thread(){
public void run() {
infos= TaskInfoProvider.getTaskInfos(TaskManagerActivity.this);
handler.sendEmptyMessage(0);
};
}.start();
}
C:数据加载好后,通知主线程更新界面。
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
adapter = new TaskInfoAdapter();
ll_loading.setVisibility(View.INVISIBLE);
list_task_item.setAdapter(adapter);
};
};
D:定义简单的TextView做Item先演示数据;
4、解决部分程序进程没有名称的问题--指定默认名称和图片;
原理是:绝大多数应用都是标准的应用,对应APK文件,是有名称和包名的;
但有些系统应用,是内核进程;是比较底层的,不是纯Java写的。主要是C写的。他们是没有名称的;所以获取名称失败;
例如:
system_process 系统内核进程
Android.process.acore 内核进程
Android.process.media 多媒体内核进程
拷贝一张名字叫:default.png图片到drawble-hdpi目录下提示invalid symbol 无效的符号
原因是:default与Java预留的关键字重名了,解决方案是改名一下;解决部分程序进程没有名称的问题
getTaskInfos()方法在异常代码处加上下面两行代码
//系统内核进程没有名称,我们就指定包名为它的名称
taskInfo.setName(packageName);
taskInfo.setIcon(context.getResources().getDrawable(R.drawable.defau lt_icon));
74_带CheckBox的ListView_30
1、自定义每条的item布局文件
基于软件管理的Item修改一下名称和ID
在基础上增加CheckBox
xmlns:android="https://www.wendangku.net/doc/6912082191.html,/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> android:id="@+id/iv_icon" android:layout_width="50dip" android:layout_height="50dip" android:src="@drawable/app"/> android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dip" android:layout_marginTop="3dip" android:layout_toRightOf="@id/iv_icon" android:text="软件名称" android:textColor="#000000" android:textSize="20sp"/> android:id="@+id/tv_memsize" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/tv_name" android:layout_marginLeft="5dip" android:layout_marginTop="1dip" android:layout_toRightOf="@id/iv_icon" android:text="内存占用:" android:textColor="#88000000" android:textSize="16sp"/> android:id="@+id/cb" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="5dip"/>
2、在适配器的个体View里面初始化并完成代码
A:容器
static class ViewHolder{
ImageView iv_icon;
TextView tv_name;
TextView tv_memsize;
CheckBox cb;
}
B:getVeiw具体代码
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
ViewHolder holder = null;
if(convertView != null&&convertView instanceof RelativeLayout){ view = convertView;
holder = (ViewHolder) view.getTag();
}else{
view = View.inflate(TaskManagerActivity.this, https://www.wendangku.net/doc/6912082191.html,yout.list_task_item, null);
holder = new ViewHolder();
holder.iv_icon= (ImageView) view.findViewById(R.id.iv_icon);
https://www.wendangku.net/doc/6912082191.html,_name= (TextView) view.findViewById(https://www.wendangku.net/doc/6912082191.html,_name);
https://www.wendangku.net/doc/6912082191.html,_memsize= (TextView) view.findViewById(https://www.wendangku.net/doc/6912082191.html,_memsize);
holder.cb = (CheckBox) view.findViewById(R.id.cb);
view.setTag(holder);
}
//取出进程信息
TaskInfo info = infos.get(position);
holder.iv_icon.setImageDrawable(info.getIcon());
https://www.wendangku.net/doc/6912082191.html,_name.setText(info.getName());
https://www.wendangku.net/doc/6912082191.html,_memsize.setText(Formatter.formatFileSize(TaskManagerActivi ty.this, info.getMemSize()));
return view;
}
3、用户进程和系统进程区分显示
A:定义两个集合
private List
private List
B:数据初始化,在fillData()里面加载数据;
private void fillData() {
ll_loading.setVisibility(View.VISIBLE);
new Thread(){
public void run() {
userTaskinfos = new ArrayList
systemTaskinfos = new ArrayList
infos=
TaskInfoProvider.getTaskInfos(TaskManagerActivity.this);
for(TaskInfo info : infos){
if(info.getUserTask()){
//用户进程
userTaskinfos.add(info);
}else{
//系统进程
systemTaskinfos.add(info);
}
}
handler.sendEmptyMessage(0);
};
}.start();
}
C:在适配器里getCount()里加上+1 +1
@Override
public int getCount() {
return userTaskinfos.size()+1+systemTaskinfos.size()+1; }
D:在getView里面增加两个TextView
TaskInfo info = null;
if(position ==0){
TextView tv = new TextView(TaskManagerActivity.this);
tv.setBackgroundColor(Color.GRAY);
tv.setTextColor(Color.WHITE);
tv.setTextSize(20);
tv.setText("用户进程("+userTaskinfos.size()+")");
return tv;
}else if(position == (userTaskinfos.size() +1)){
TextView tv = new TextView(TaskManagerActivity.this);
tv.setBackgroundColor(Color.GRAY);
tv.setTextColor(Color.WHITE);
tv.setTextSize(20);
tv.setText("系统进程("+systemTaskinfos.size()+")");
return tv;
}else if(position <= userTaskinfos.size()){
int newposition = position-1;
info = userTaskinfos.get(newposition);
}else{
info = systemTaskinfos.get(position-1-userTaskinfos.size()-1);
}
E:切换用户进程和系统进程数据
if (userTaskinfos != null && systemTaskinfos != null) {
if (firstVisibleItem > userTaskinfos.size()) {
tv_status.setText("系统进程:" + systemTaskinfos.size());
} else {
tv_status.setText("用户进程:" + userTaskinfos.size());
}
}
4、勾选CheckBox拖动,会出现bug,每7条就会自动勾选;
A:讲解原理,为什么会导致这样;
是历史缓存View对象重复利用导致;
B:要想解决该问题,在TaskInfo 增加字段,并添加get和set方法;
//是否被选中
private boolean isChecked;
C:点击每条没有效果--禁用CheckBox点击事件
android:clickable="false"
android:focusable="false"
运行演示,已经有了点击效果
D:设置点击每条事件,点击事件实现如下
点击每条事件代码实现
Object obj = list_task_item.getItemAtPosition(position);
if(obj !=null){
CheckBox cb = (CheckBox) view.findViewById(R.id.cb);
TaskInfo taskInfo = (TaskInfo) obj;
if(taskInfo.isChecked()){
cb.setChecked(false);
taskInfo.setChecked(false);
}else{
cb.setChecked(true);
taskInfo.setChecked(true);
}
}
E:在适配器getItem方法里修改成
public Object getItem(int position) {
TaskInfo info = null;
if(position ==0){
return null;
}else if(position == (userTaskinfos.size() +1)){
return null;
}else if(position <= userTaskinfos.size()){
int newposition = position-1;
info = userTaskinfos.get(newposition);
}else{
info =
systemTaskinfos.get(position-1-userTaskinfos.size()-1);
}
return info;
}
运行演示,还出现重复勾选的问题;
F:在getView()方法里加上校验代码
holder.cb.setChecked(info.isChecked());
运行演示看效果,已经解决重复勾选问题;
75_进程管理器的实现_35
1、在布局文件里面,增加全选、反选、一键清理、设置按钮
android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> android:id="@+id/textView1" android:layout_width="fill_parent" android:layout_height="55dip" android:background="#8866ff00" android:gravity="center" android:text="进程管理" android:textColor="#000000" android:textSize="22sp"/> android:layout_width="match_parent" android:layout_height="wrap_content"> android:id="@+id/tv_process_count" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dip" android:layout_marginTop="5dip" android:text="运行中进程:" android:textColor="#000000" android:textSize="14sp"/> android:id="@+id/tv_mem_info" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginLeft="5dip" android:layout_marginTop="5dip" android:text="剩余/总内存:" android:textColor="#000000" android:textSize="14sp"/> android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="50" > android:id="@+id/list_task_item" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:id="@+id/ll_loading" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" android:orientation="vertical" android:visibility="invisible"> android:layout_width="wrap_content" android:layout_height="wrap_content"/> android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="给力加载中..."/> android:id="@+id/tv_status" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#ff888888" android:text="用户进程(6)" android:textColor="#ffffff" android:textSize="20sp"/> android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal">
2、代码实现全选、反选
/**
*全选
*/
public void selectAll(View view){
for(TaskInfo info : userTaskinfos){
info.setChecked(true);
}
for(TaskInfo info : systemTaskinfos){
info.setChecked(true);
}
adapter.notifyDataSetChanged();
}
/**
*反选
*/
public void unSelect(View view){
for(TaskInfo info : userTaskinfos){
info.setChecked(!info.isChecked());
}
for(TaskInfo info : systemTaskinfos){
info.setChecked(!info.isChecked());
}
adapter.notifyDataSetChanged();
}
运行演示看一下效果。
/**
* 杀死选中的进程
*
* @param view
*/
public void killAll(View view) {
for (TaskInfo info : userTaskinfos) {
if (info.isChecked()) {
// android.os.Process.killProcess(pid);//自杀
am.killBackgroundProcesses(info.getPackageName());
}
}
for (TaskInfo info : systemTaskinfos) {
if (info.isChecked()) {
am.killBackgroundProcesses(info.getPackageName());
}
}
//重新加载数据就可以了
fillData();
}
杀进程需要加权限
android:name="android.permission.KILL_BACKGROUND_PROCESSES"/> 运行演示看效果; 对应DDMS看到进行,演示杀死进程; 系统进程杀死后重启。 知识拓展:杀死进程自杀:android.os.Process.killProcess(pid); 3、杀死进程效果优化&提示杀死了多少个进程和内存信息 查看金山手机卫士、和腾讯管家效果。 public void killAll(View view) { int total = 0; long saveMem = 0; for (TaskInfo info : userTaskinfos) { if(info.isChecked()) { // android.os.Process.killProcess(pid);//自杀 am.killBackgroundProcesses(info.getPackageName()); total ++; saveMem +=info.getMemSize(); userTaskinfos.remove(info); } } for (TaskInfo info : systemTaskinfos) { if (info.isChecked()) { am.killBackgroundProcesses(info.getPackageName()); total ++; saveMem +=info.getMemSize(); systemTaskinfos.remove(info); } } // 重新加载数据就可以了 // fillData(); Toast.makeText(this, "杀死了"+total+"个进程,释放了"+Formatter.formatFileSize(this, saveMem), 1).show(); adapter.notifyDataSetChanged(); } 运行演示:先杀最后一个,再杀中间进程报错。 4、解决错误问题 A:看日志: https://www.wendangku.net/doc/6912082191.html,ng.IllegalStateException: Could not execute method of the activity 不能执行activity这个方法