实现效果如图:
一个标题,一个分割条,两个文本一个用来显示可用内存一个显示sd卡的可用内存,一个列表显示安装的程序。
因此布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView style="@style/title_center_text"
android:text="程序管理器" />
<View style="@style/splitter_view"/>
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent">
<TextView style="@style/content_text"
android:id="@+id/tv_mem_avail"
android:layout_weight="1"
android:text="内存可用:"/>
<TextView style="@style/content_text"
android:id="@+id/tv_sdcard_avail"
android:layout_weight="1"
android:text="SD卡可用:"/>
</LinearLayout>
<RelativeLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_alignParentBottom="true">
<LinearLayout
android:id="@+id/ll_appmanager_loading"
android:orientation="vertical"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_centerHorizontal="true"
android:gravity="center">
<ProgressBar
android:layout_centerHorizontal="true"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
<TextView
android:text="正在加载中……"
android:gravity="center"
android:layout_height="wrap_content"
android:layout_width="match_parent" />
</LinearLayout>
<ListView
android:id="@+id/lv_apps"
android:layout_height="match_parent"
android:layout_width="match_parent">
</ListView>
</RelativeLayout>
</LinearLayout>
这个设计方案和之前的差不多,也就是在listview上还有一个progressbar用来显示“加载中”,因为获取安装的app需要一定的时间。
AppManagerActivity的代码:
package com.example.mobilesafe;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.StatFs;
import android.text.format.Formatter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.example.mobilesafe.engine.AppInfo;
import com.example.mobilesafe.engine.AppInfoProvider;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* Created by sing on 14-1-21.
* desc:程序管理器
*/
public class AppManagerActivity extends Activity {
public static final String TAG = "AppManagerActivity";
public static final int LOAD_FINISHED = 1;
private TextView tv_mem_avail;
private TextView tv_sdcard_avail;
private View ll_appmanager_loading;
private ListView lv_apps;
private List<AppInfo> appInfos;
private List<AppInfo> userappInfos;
private List<AppInfo> systemappInfos;
private BaseAdapter adapter = new AppManagerAdapter();
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what == LOAD_FINISHED) {
ll_appmanager_loading.setVisibility(View.INVISIBLE);
lv_apps.setAdapter(adapter);
}
}
};
private class AppManagerAdapter extends BaseAdapter {
@Override
public int getCount() {
//每个分组多一个标题头
return userappInfos.size() + 1 + systemappInfos.size() + 1;
}
@Override
public Object getItem(int i) {
if (i == 0) {
return i;
}else if (i <= userappInfos.size()) {
return userappInfos.get(i - 1);
} else if (i == userappInfos.size() + 1) {
return i;
} else {
return systemappInfos.get(i - userappInfos.size() - 2);
}
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
View v;
ViewHolder holder;
if (i == 0) {
TextView tv = new TextView(getApplicationContext());
tv.setTextSize(20);
tv.setText("用户程序(" + userappInfos.size() + ")");
return tv;
}else if (i <= userappInfos.size()) {
if (view==null || view instanceof TextView) {
v = View.inflate(getApplicationContext(), R.layout.app_manager_item, null);
holder = new ViewHolder();
holder.iv_icon = (ImageView) v.findViewById(R.id.iv_appmanager_icon);
holder.tv_name = (TextView) v.findViewById(R.id.tv_appmanager_name);
holder.tv_version = (TextView) v.findViewById(R.id.tv_appmanager_version);
v.setTag(holder);
}else{
v = view;
holder = (ViewHolder) view.getTag();
}
AppInfo appInfo = userappInfos.get(i - 1);
holder.iv_icon.setImageDrawable(appInfo.getAppicon());
holder.tv_name.setText(appInfo.getAppname());
holder.tv_version.setText("版本号:" + appInfo.getVersion());
return v;
} else if (i == userappInfos.size() + 1) {
TextView tv = new TextView(getApplicationContext());
tv.setTextSize(20);
tv.setText("系统程序(" + systemappInfos.size() + ")");
return tv;
} else {
if (view==null || view instanceof TextView) {
v = View.inflate(getApplicationContext(), R.layout.app_manager_item, null);
holder = new ViewHolder();
holder.iv_icon = (ImageView) v.findViewById(R.id.iv_appmanager_icon);
holder.tv_name = (TextView) v.findViewById(R.id.tv_appmanager_name);
holder.tv_version = (TextView) v.findViewById(R.id.tv_appmanager_version);
v.setTag(holder);
}else{
v = view;
holder = (ViewHolder) view.getTag();
}
AppInfo appInfo = systemappInfos.get(i - userappInfos.size() - 2);
holder.iv_icon.setImageDrawable(appInfo.getAppicon());
holder.tv_name.setText(appInfo.getAppname());
holder.tv_version.setText("版本号:" + appInfo.getVersion());
return v;
}
}
private class ViewHolder {
ImageView iv_icon;
TextView tv_name;
TextView tv_version;
}
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.appmanager_layout);
tv_mem_avail = (TextView) findViewById(R.id.tv_mem_avail);
tv_sdcard_avail = (TextView) findViewById(R.id.tv_sdcard_avail);
ll_appmanager_loading = findViewById(R.id.ll_appmanager_loading);
lv_apps = (ListView) findViewById(R.id.lv_apps);
tv_mem_avail.setText("内存可用" + getAvailROMSize());
tv_sdcard_avail.setText("SD卡可用" + getAvailSDSize());
ll_appmanager_loading.setVisibility(View.VISIBLE);
new Thread(){
@Override
public void run() {
AppInfoProvider provider = new AppInfoProvider(AppManagerActivity.this);
appInfos = provider.getInstalledApps();
initAppInfo();
Message msg = Message.obtain();
msg.what = LOAD_FINISHED;
handler.sendMessage(msg);
}
}.start();
}
/**
* 获取手机可用内存
* @return
*/
private String getAvailROMSize() {
File path = Environment.getDataDirectory();
StatFs statFs = new StatFs(path.getPath());
long blockSize = statFs.getBlockSize();
long availableBlocks = statFs.getAvailableBlocks();
return Formatter.formatFileSize(this, availableBlocks * blockSize);
}
/**
* 获取SD卡可用内存
* @return
*/
private String getAvailSDSize() {
File path = Environment.getExternalStorageDirectory();
StatFs statFs = new StatFs(path.getPath());
long blockSize = statFs.getBlockSize();
long availableBlocks = statFs.getAvailableBlocks();
return Formatter.formatFileSize(this, availableBlocks * blockSize);
}
/**
* 区分出用户程序和系统程序
*/
private void initAppInfo() {
userappInfos = new ArrayList<AppInfo>();
systemappInfos = new ArrayList<AppInfo>();
for (AppInfo appinfo : appInfos) {
if (appinfo.isUserpp()) {
userappInfos.add(appinfo);
}else {
systemappInfos.add(appinfo);
}
}
}
}
其实可以使用ExpandableListView来显示分组用户程序和系统程序,但是之前有使用过,这里使用listview来显示分组,需要在第一个和用户程序之后显示一个分组的标题,是用textview来实现的,因此BaseAdapter的getView需要特别处理。
每一个item的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_appmanager_icon"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="0"
android:layout_gravity="left"/>
<RelativeLayout
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView style="@style/content_text"
android:id="@+id/tv_appmanager_name"
android:layout_alignParentTop="true"
android:singleLine="true"
android:ellipsize="end"
android:textSize="20sp"/>
<TextView style="@style/content_text"
android:id="@+id/tv_appmanager_version"
android:layout_alignParentBottom="true"
android:textSize="12sp"/>
</RelativeLayout>
</LinearLayout>
要求程序的图标文件是靠左的,右侧的应用程序名是靠顶显示,版本号靠底部显示。
因此把name和version放到一个RelativeLayout,让ImageView与RelativeLayout的layout_weight为0:1,也就是RelativeLayout占满父容器的剩余空间。
然后再在RelativeLayout里分配name和version的布局。
实际运行后发现有的程序的图标格外大:
解决方案是让imageview的高和宽设置为一个固定大小:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_appmanager_icon"
android:layout_height="60dip"
android:layout_width="60dip"
android:layout_weight="0"
android:layout_gravity="left"/>
<RelativeLayout
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView style="@style/content_text"
android:id="@+id/tv_appmanager_name"
android:layout_alignParentTop="true"
android:singleLine="true"
android:ellipsize="end"
android:textSize="30sp"/>
<TextView style="@style/content_text"
android:id="@+id/tv_appmanager_version"
android:layout_alignParentBottom="true"
android:textSize="12sp"/>
</RelativeLayout>
</LinearLayout>
再编译运行后的效果图: