软件管理
作为安全管家里最为基本的功能之一,软件管家的工作大致包括读取内部存储容量剩余,内存卡容量剩余,系统应用列表,用户应用列表,先来看看我low了一脸的界面:
首先把我们的布局搭起来,整体的布局文件:
<?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" >
<TextView
style="@style/TitleStyle"
android:text="软件管理" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/tv_romfree"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="内存可用XXX" />
<TextView
android:id="@+id/tv_sdfree"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SD卡可用XXX" />
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="@+id/lv_app"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
<TextView
android:id="@+id/tv_app"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff888888"
android:textColor="#fff" />
</FrameLayout>
</LinearLayout>
整个布局使用了垂直方向的线性布局,在软件管理这一标题栏中设置了style,因为每个功能的Activity中都会用到这种Style,所以设置通用的Style可以增加工作效率,TitleStyle内容设置在style.xml文件中
<style name="TitleStyle">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">50dp</item>
<item name="android:background">#8866ff00</item>
<item name="android:gravity">center</item>
<item name="android:textColor">@android:color/black</item>
<item name="android:textSize">22sp</item>
</style>
下面的大部分显示空间使用了帧布局,主要是为了实现用户应用顶栏,系统应用顶栏的顶部停留,喜闻乐见的ListView就不用详细介绍了,下面上ListView的item布局
<?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="horizontal" >
<ImageView
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:id="@+id/iv_icon"
android:layout_width="45dip"
android:layout_height="45dip"
android:src="@drawable/ic_launcher" />
<LinearLayout
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:singleLine="true"
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1.0"
android:ellipsize="end"
android:textSize="20sp"
android:textColor="#000000"
android:gravity="center_vertical"
android:paddingLeft="5.0dip"
android:text="标题" />
<TextView
android:textSize="14sp"
android:textColor="#99000000"
android:id="@+id/tv_apk_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:paddingRight="5.0dip"
android:text="应用程序大小" />
</LinearLayout>
<TextView
android:textSize="14sp"
android:textColor="#99000000"
android:id="@+id/tv_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:paddingLeft="5.0dip" />
</LinearLayout>
</LinearLayout>
大家对照图上的显示就能清楚理解item布局。
说完布局就说一下软件管理的业务逻辑:
看图片我们需要拿到手机的内部存储剩余,外部存储剩余,每个应用的详细信息,我们先写一个类,用来存取传递应用的详细信息
有了应用信息存储传递的地方,我们就要想办法把手机里的所有应用详细信息给获取出来,下面再创建一个类:
利用这个类获取应用信息并返回给Activity。
import android.graphics.drawable.Drawable;
public class AppInfo {
/**
* 软件图标
*/
private Drawable icon;
/**
* 软件名称
*/
private String apkName;
/**
* 软件名字
*/
private long apkSize;
/**
* 是否用户软件
* 是则为true
* 否则为false
*/
private boolean userApp;
/**
* 软件的包名
*/
private String apkPackageName;
/**
* 放置的位置
*/
private boolean isRom;
public Drawable getIcon() {
return icon;
}
public void setIcon(Drawable icon) {
this.icon = icon;
}
public String getApkName() {
return apkName;
}
public void setApkName(String apkName) {
this.apkName = apkName;
}
public long getApkSize() {
return apkSize;
}
public void setApkSize(long apkSize) {
this.apkSize = apkSize;
}
public boolean isUserApp() {
return userApp;
}
public void setUserApp(boolean userApp) {
this.userApp = userApp;
}
public String getApkPackageName() {
return apkPackageName;
}
public void setApkPackageName(String apkPackageName) {
this.apkPackageName = apkPackageName;
}
public boolean isRom() {
return isRom;
}
public void setRom(boolean isRom) {
this.isRom = isRom;
}
@Override
public String toString() {
return "AppInfo [icon=" + icon + ", apkName=" + apkName + ", apkSize="
+ apkSize + ", userApp=" + userApp + ", apkPackageName="
+ apkPackageName + ", isRom=" + isRom + "]";
}
}
有了应用信息存储传递的地方,我们就要想办法把手机里的所有应用详细信息给获取出来,下面再创建一个类:
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import com.mobileSafe.bean.AppInfo;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
public class AppInfos {
public static List<AppInfo> getAppInfos(Context context) {
/**
* 新建一个list用来存放应用信息
*/
ArrayList<AppInfo> list = new ArrayList<AppInfo>();
/**
* 获取包管理器
* 利用包管理器获取所有安装过应用的包信息并存放在list中
*/
PackageManager pm = context.getPackageManager();
List<PackageInfo> installPackages = pm.getInstalledPackages(0);
/**
* 获取每个PackageInfo中我们需要的信息
*/
for (PackageInfo installPackage : installPackages) {
AppInfo appInfo = new AppInfo();
/**
* 获取app的图标并设置
*/
Drawable loadIcon = installPackage.applicationInfo.loadIcon(pm);
appInfo.setIcon(loadIcon);
/**
* 获取app的名字并设置
*/
String loadLabel = installPackage.applicationInfo.loadLabel(pm).toString();
appInfo.setApkName(loadLabel);
/**
* 获取app的包名并设置
*/
String packageName = installPackage.packageName.toString();
appInfo.setApkPackageName(packageName);
/**
* 获取apk的资源路径
*/
String apkDir = installPackage.applicationInfo.sourceDir.toString();
File file = new File(apkDir);
/**
* 获取app的大小并设置
*/
long length = file.length();
appInfo.setApkSize(length);
// 获取应用标记,标记中存储了大量信息
int flags = installPackage.applicationInfo.flags;
/**
* 利用标记判断应用存放位置
*/
if ((flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
appInfo.setRom(false);
} else {
appInfo.setRom(true);
}
/**
* 利用标记判断用户应用还是系统应用
*/
if ((flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
appInfo.setUserApp(false);
} else {
appInfo.setUserApp(true);
}
list.add(appInfo);
}
return list;
}
}
利用这个类获取应用信息并返回给Activity。
package com.lyang.mobileSafe.Activity;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;
import com.example.mobileSafe.R;
import com.lyang.mobileSafe.bean.AppInfo;
import com.lyang.mobileSafe.engine.AppInfos;
import android.app.Activity;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
public class AppManagerActivity extends Activity {
private TextView romFree;
private TextView sdFree;
private ListView lv;
private TextView tv_app;
private List<AppInfo> appInfos;
private List<AppInfo> userAppInfos;
private List<AppInfo> systemAppInfos;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/**
* 初始化UI
*/
initUI();
initData();
}
/**
* 接受子线程消息
*/
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
AppManagerAdapter adapter = new AppManagerAdapter();
lv.setAdapter(adapter);
}
};
/**
* 获取应用信息为耗时操作,所以要在子线程执行
*/
private void initData() {
new Thread() {
@Override
public void run() {
super.run();
/**
* 获取应用信息
*/
appInfos = AppInfos.getAppInfos(AppManagerActivity.this);
/**
* 新建两个分别存储用户应用信息,系统应用信息
*/
userAppInfos = new ArrayList<AppInfo>();
systemAppInfos = new ArrayList<AppInfo>();
for (AppInfo appInfo : appInfos) {
if (appInfo.isUserApp()) {
userAppInfos.add(appInfo);
} else {
systemAppInfos.add(appInfo);
}
}
/**
* 向主线程发送空消息
*/
handler.sendEmptyMessage(0);
}
}.start();
}
/**
*
* @author
*listview需要用到的adapter,继承自BaseAdapter,更加灵活
*
*/
private class AppManagerAdapter extends BaseAdapter {
/**
* 返回item数量
*/
@Override
public int getCount() {
return appInfos.size() + 2;
}
@Override
public Object getItem(int position) {
if (position == 0) {
return null;
} else if (position == userAppInfos.size() + 1) {
return null;
} else if (position < userAppInfos.size() + 1) {
return userAppInfos.get(position - 1);
} else if (position > userAppInfos.size() + 1) {
return systemAppInfos.get(position - userAppInfos.size() - 2);
}
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
/**
* 这两种情况是显示用户应用,系统应用及其个数的TextView
*/
if (position == 0) {
TextView textView = new TextView(AppManagerActivity.this);
textView.setText("用户应用:" + userAppInfos.size());
textView.setTextColor(Color.WHITE);
textView.setBackgroundColor(Color.GRAY);
return textView;
} else if (position == userAppInfos.size() + 1) {
TextView textView = new TextView(AppManagerActivity.this);
textView.setText("系统应用:" + systemAppInfos.size());
textView.setTextColor(Color.WHITE);
textView.setBackgroundColor(Color.GRAY);
return textView;
}
/**
* 在任一position时要取的appInfo的对应位置
*/
AppInfo appInfo = null;
if (position < userAppInfos.size() + 1) {
appInfo = userAppInfos.get(position - 1);
} else if (position > userAppInfos.size() + 1) {
appInfo = systemAppInfos
.get(position - userAppInfos.size() - 2);
}
View view = null;
ViewHolder holder;
/**
* 优化item的显示,减少findViewById的次数
*/
if (convertView != null && convertView instanceof LinearLayout) {
view = convertView;
holder = (ViewHolder) view.getTag();
} else {
view = View.inflate(AppManagerActivity.this,
R.layout.app_manager_item, null);
holder = new ViewHolder();
holder.icon = (ImageView) view.findViewById(R.id.iv_icon);
holder.apkName = (TextView) view.findViewById(R.id.tv_name);
holder.apkSize = (TextView) view.findViewById(R.id.tv_apk_size);
holder.userApp = (TextView) view.findViewById(R.id.tv_location);
view.setTag(holder);
}
holder.icon.setImageDrawable(appInfo.getIcon());
holder.apkName.setText(appInfo.getApkName());
holder.apkSize.setText(android.text.format.Formatter
.formatFileSize(AppManagerActivity.this,
appInfo.getApkSize()));
if (!appInfo.isRom()) {
holder.userApp.setText("外部存储");
} else {
holder.userApp.setText("手机内存");
}
return view;
}
}
/**
*
* @author
* 设置内部类用于数据的存取
*
*/
static class ViewHolder {
ImageView icon;
TextView apkName;
TextView apkSize;
TextView userApp;
}
private void initUI() {
setContentView(R.layout.activity_app_manager);
lv = (ListView) findViewById(R.id.lv_app);
romFree = (TextView) findViewById(R.id.tv_romfree);
sdFree = (TextView) findViewById(R.id.tv_sdfree);
tv_app = (TextView) findViewById(R.id.tv_app);
/**
* 获取运行内存的剩余空间ROM
*/
long romFreeSpace = Environment.getDataDirectory().getFreeSpace();
romFree.setText("内存可用:"
+ android.text.format.Formatter.formatFileSize(
AppManagerActivity.this, romFreeSpace));
/**
* 获取内存卡剩余空间
*/
long sdcardFreeSpace = Environment.getExternalStorageDirectory()
.getFreeSpace();
sdFree.setText("sd卡可用:"
+ android.text.format.Formatter.formatFileSize(
AppManagerActivity.this, sdcardFreeSpace));
lv.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
/**
* 设置滚动时顶部TextView
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (userAppInfos != null && systemAppInfos != null) {
if (firstVisibleItem > (userAppInfos.size())) {
tv_app.setText("系统进程:" + systemAppInfos.size());
} else {
tv_app.setText("用户进程:" + userAppInfos.size());
}
}
}
});
}
}