实现效果如图:
一个标题,一个分割条,两个文本一个用来显示可用内存一个显示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>再编译运行后的效果图: