MLManager 一个简单的app管理器
MLManager是一个简单的app管理器。如果你想学习如何得到安装在设备中的app的详细信息,那么这个app对你而言是个理想的选择。
这个app的编码风格非常好,值得借鉴。它还有助于你理解如何设计一个遵循Material Design规范的app。
获取 app 信息
通过PackageManager获取手机已安装apk文件信息
final PackageManager packageManager = getPackageManager();
List<PackageInfo> packages = packageManager.getInstalledPackages(PackageManager.GET_META_DATA);
AsyncTask异步获取
class getInstalledApps extends AsyncTask<Void, String, Void> {
private Integer totalApps;
private Integer actualApps;
public getInstalledApps() {
actualApps = 0;
appList = new ArrayList<>();
appSystemList = new ArrayList<>();
appHiddenList = new ArrayList<>();
}
@Override
protected Void doInBackground(Void... params) {
final PackageManager packageManager = getPackageManager();
List<PackageInfo> packages = packageManager.getInstalledPackages(PackageManager.GET_META_DATA);
Set<String> hiddenApps = appPreferences.getHiddenApps();
totalApps = packages.size() + hiddenApps.size();
// Get Sort Mode
switch (appPreferences.getSortMode()) {
default:
// Comparator by Name (default)
Collections.sort(packages, new Comparator<PackageInfo>() {
@Override
public int compare(PackageInfo p1, PackageInfo p2) {
return packageManager.getApplicationLabel(p1.applicationInfo).toString().toLowerCase().compareTo(packageManager.getApplicationLabel(p2.applicationInfo).toString().toLowerCase());
}
});
break;
case "2":
// Comparator by Size
Collections.sort(packages, new Comparator<PackageInfo>() {
@Override
public int compare(PackageInfo p1, PackageInfo p2) {
Long size1 = new File(p1.applicationInfo.sourceDir).length();
Long size2 = new File(p2.applicationInfo.sourceDir).length();
return size2.compareTo(size1);
}
});
break;
case "3":
// Comparator by Installation Date (default)
Collections.sort(packages, new Comparator<PackageInfo>() {
@Override
public int compare(PackageInfo p1, PackageInfo p2) {
return Long.toString(p2.firstInstallTime).compareTo(Long.toString(p1.firstInstallTime));
}
});
break;
case "4":
// Comparator by Last Update
Collections.sort(packages, new Comparator<PackageInfo>() {
@Override
public int compare(PackageInfo p1, PackageInfo p2) {
return Long.toString(p2.lastUpdateTime).compareTo(Long.toString(p1.lastUpdateTime));
}
});
break;
}
// Installed & System Apps
for (PackageInfo packageInfo : packages) {
if (!(packageManager.getApplicationLabel(packageInfo.applicationInfo).equals("") || packageInfo.packageName.equals(""))) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
try {
// Non System Apps
AppInfo tempApp = new AppInfo(packageManager.getApplicationLabel(packageInfo.applicationInfo).toString(), packageInfo.packageName, packageInfo.versionName, packageInfo.applicationInfo.sourceDir, packageInfo.applicationInfo.dataDir, packageManager.getApplicationIcon(packageInfo.applicationInfo), false);
appList.add(tempApp);
} catch (OutOfMemoryError e) {
//TODO Workaround to avoid FC on some devices (OutOfMemoryError). Drawable should be cached before.
AppInfo tempApp = new AppInfo(packageManager.getApplicationLabel(packageInfo.applicationInfo).toString(), packageInfo.packageName, packageInfo.versionName, packageInfo.applicationInfo.sourceDir, packageInfo.applicationInfo.dataDir, getResources().getDrawable(R.drawable.ic_android), false);
appList.add(tempApp);
} catch (Exception e) {
e.printStackTrace();
}
} else {
try {
// System Apps
AppInfo tempApp = new AppInfo(packageManager.getApplicationLabel(packageInfo.applicationInfo).toString(), packageInfo.packageName, packageInfo.versionName, packageInfo.applicationInfo.sourceDir, packageInfo.applicationInfo.dataDir, packageManager.getApplicationIcon(packageInfo.applicationInfo), true);
appSystemList.add(tempApp);
} catch (OutOfMemoryError e) {
//TODO Workaround to avoid FC on some devices (OutOfMemoryError). Drawable should be cached before.
AppInfo tempApp = new AppInfo(packageManager.getApplicationLabel(packageInfo.applicationInfo).toString(), packageInfo.packageName, packageInfo.versionName, packageInfo.applicationInfo.sourceDir, packageInfo.applicationInfo.dataDir, getResources().getDrawable(R.drawable.ic_android), false);
appSystemList.add(tempApp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
actualApps++;
publishProgress(Double.toString((actualApps * 100) / totalApps));
}
// Hidden Apps
for (String app : hiddenApps) {
AppInfo tempApp = new AppInfo(app);
Drawable tempAppIcon = UtilsApp.getIconFromCache(context, tempApp);
tempApp.setIcon(tempAppIcon);
appHiddenList.add(tempApp);
actualApps++;
publishProgress(Double.toString((actualApps * 100) / totalApps));
}
return null;
}
@Override
protected void onProgressUpdate(String... progress) {
super.onProgressUpdate(progress);
progressWheel.setProgress(Float.parseFloat(progress[0]));
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
appAdapter = new AppAdapter(appList, context);
appSystemAdapter = new AppAdapter(appSystemList, context);
appFavoriteAdapter = new AppAdapter(getFavoriteList(appList, appSystemList), context);
appHiddenAdapter = new AppAdapter(appHiddenList, context);
fastScroller.setVisibility(View.VISIBLE);
recyclerView.setAdapter(appAdapter);
pullToRefreshView.setEnabled(true);
progressWheel.setVisibility(View.GONE);
searchItem.setVisible(true);
fastScroller.setRecyclerView(recyclerView);
recyclerView.setOnScrollListener(fastScroller.getOnScrollListener());
setPullToRefreshView(pullToRefreshView);
drawer.closeDrawer();
drawer = UtilsUI.setNavigationDrawer((Activity) context, context, toolbar, appAdapter, appSystemAdapter, appFavoriteAdapter, appHiddenAdapter, recyclerView);
}
}
获取那些信息
AppInfo.java获取系统apk信息:
- name:packageManager.getApplicationLabel(packageInfo.applicationInfo).toString() 应用程序的标签
- apk:packageInfo.packageName 此包的名称
- version:packageInfo.versionName 此包的版本名称
- source:packageInfo.applicationInfo.sourceDir 应用APK完整路径
- data:packageInfo.applicationInfo.dataDir apk数据目录的完整路径。
- icon:packageManager.getApplicationIcon(packageInfo.applicationInfo) 默认的应用程序图标
- system:(packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0 表示不是系统应用
AppInfo对象实现了Serializable接口。序列化就是将一个对象的状态(各个属性量)保存起来,然后在适当的时候再获得。至于从什么地方读出来和保存到哪里去都被隐藏在函数参数的背后了。这样子,任何类型只要实现了Serializable接口,就可以被保存到文件中,或者作为数据流通过网络发送到别的地方。也可以用管道来传输到系统的其他程序中。这样子极大的简化了类的设计。只要设计一个保存一个读取功能就能解决上面说得所有问题。
public class AppInfo implements Serializable {
private String name;
private String apk;
private String version;
private String source;
private String data;
private Drawable icon;
private Boolean system;
public AppInfo(String name, String apk, String version, String source, String data, Drawable icon, Boolean isSystem) {
this.name = name;
this.apk = apk;
this.version = version;
this.source = source;
this.data = data;
this.icon = icon;
this.system = isSystem;
}
public AppInfo(String string) {
String[] split = string.split("##");
if (split.length == 6) {
this.name = split[0];
this.apk = split[1];
this.version = split[2];
this.source = split[3];
this.data = split[4];
this.system = Boolean.getBoolean(split[5]);
}
}
public String getName() {
return name;
}
public String getAPK() {
return apk;
}
public String getVersion() {
return version;
}
public String getSource() {
return source;
}
public String getData() {
return data;
}
public Drawable getIcon() {
return icon;
}
public void setIcon(Drawable icon) {
this.icon = icon;
}
public Boolean isSystem() {
return system;
}
public String toString() {
return getName() + "##" + getAPK() + "##" + getVersion() + "##" + getSource() + "##" + getData() + "##" + isSystem();
}
}
遵循Material Design规范UI设计
Material Design,中文名:材料设计语言,是由Google推出的全新的设计语言,谷歌表示,这种设计语言旨在为手机、平板电脑、台式机和“其他平台”提供更一致、更广泛的“外观和感觉”。
MLManager使用的依赖库
compile 'com.github.navasmdc:MaterialDesign:1.5@aar'
compile('com.github.afollestad.material-dialogs:core:0.8.5.3@aar') { transitive = true; }
compile('com.github.afollestad.material-dialogs:commons:0.8.5.3@aar') { transitive = true; }
compile 'com.pnikosis:materialish-progress:1.7'
compile('com.mikepenz:materialdrawer:4.6.1@aar') { transitive = true; }
compile 'com.mikepenz:google-material-typeface:1.2.0.1@aar'
com.github.navasmdc:MaterialDesign:1.5@aar
com.github.afollestad.material-dialogs:core:0.8.5.3@aar
com.github.afollestad.material-dialogs:commons:0.8.5.3@aar
com.pnikosis:materialish-progress:1.7
com.mikepenz:materialdrawer:4.6.1@aar
com.mikepenz:google-material-typeface:1.2.0.1@aar
浮动菜单FloatingActionsMenu
compile 'com.getbase:floatingactionbutton:1.10.1'
MLManager项目AppActivity.java界面中
fab_multiple.xml
<?xml version="1.0" encoding="utf-8"?>
<com.getbase.floatingactionbutton.FloatingActionsMenu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="@dimen/fab_margin"
app:fab_labelStyle="@style/menu_labels_style"
app:fab_addButtonColorNormal="@color/primary"
app:fab_addButtonColorPressed="@color/primary_dark">
<com.getbase.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_buy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fab_icon="@drawable/ic_local_grocery_store_white"
app:fab_colorNormal="@color/fab"
app:fab_title="@string/action_buy" />
<com.getbase.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_b"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:fab_colorNormal="@color/fab"
app:fab_title="@string/action_hide" />
<com.getbase.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_a"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fab_icon="@drawable/ic_send_white"
app:fab_colorNormal="@color/fab"
app:fab_title="@string/action_share" />
</com.getbase.floatingactionbutton.FloatingActionsMenu>
activity_app.xml添加布局fab_multiple.xml
fab.isExpanded() 浮动菜单是否是展开
fab.collapse() 折叠浮动菜单
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/fab"
layout="@layout/fab_multiple" />
</FrameLayout>
左侧抽屉菜单
compile('com.mikepenz:materialdrawer:4.6.1@aar') { transitive = true; }
MLManager项目MainActivity.java界面中
drawer = UtilsUI.setNavigationDrawer((Activity) context, context, toolbar, appAdapter, appSystemAdapter, appFavoriteAdapter, appHiddenAdapter, recyclerView);
抽屉菜单的创建drawerBuilder.build()
public static Drawer setNavigationDrawer (Activity activity, final Context context, Toolbar toolbar, final AppAdapter appAdapter, final
AppAdapter appSystemAdapter, final AppAdapter appFavoriteAdapter, final AppAdapter appHiddenAdapter, final RecyclerView recyclerView) {
final String loadingLabel = "...";
int header;
AppPreferences appPreferences = MLManagerApplication.getAppPreferences();
String apps, systemApps, favoriteApps, hiddenApps;
if (getDayOrNight() == 1) {
header = R.drawable.header_day;
} else {
header = R.drawable.header_night;
}
if (appAdapter != null) {
apps = Integer.toString(appAdapter.getItemCount());
} else {
apps = loadingLabel;
}
if (appSystemAdapter != null) {
systemApps = Integer.toString(appSystemAdapter.getItemCount());
} else {
systemApps = loadingLabel;
}
if (appFavoriteAdapter != null) {
favoriteApps = Integer.toString(appFavoriteAdapter.getItemCount());
} else {
favoriteApps = loadingLabel;
}
if (appHiddenAdapter != null) {
hiddenApps = Integer.toString(appHiddenAdapter.getItemCount());
} else {
hiddenApps = loadingLabel;
}
AccountHeader headerResult = new AccountHeaderBuilder()
.withActivity(activity)
.withHeaderBackground(header)
.build();
Integer badgeColor = ContextCompat.getColor(context, R.color.divider);
BadgeStyle badgeStyle = new BadgeStyle(badgeColor, badgeColor).withTextColor(Color.GRAY);
DrawerBuilder drawerBuilder = new DrawerBuilder();
drawerBuilder.withActivity(activity);
drawerBuilder.withToolbar(toolbar);
drawerBuilder.withAccountHeader(headerResult);
drawerBuilder.withStatusBarColor(UtilsUI.darker(appPreferences.getPrimaryColorPref(), 0.8));
if (MLManagerApplication.isPro()) {
drawerBuilder.addDrawerItems(
new PrimaryDrawerItem().withName(context.getResources().getString(R.string.action_apps)).withIcon(GoogleMaterial.Icon.gmd_phone_android).withBadge(apps).withBadgeStyle(badgeStyle).withIdentifier(1),
new PrimaryDrawerItem().withName(context.getResources().getString(R.string.action_system_apps)).withIcon(GoogleMaterial.Icon.gmd_android).withBadge(systemApps).withBadgeStyle(badgeStyle).withIdentifier(2),
new DividerDrawerItem(),
new PrimaryDrawerItem().withName(context.getResources().getString(R.string.action_favorites)).withIcon(GoogleMaterial.Icon.gmd_star).withBadge(favoriteApps).withBadgeStyle(badgeStyle).withIdentifier(3),
new DividerDrawerItem(),
new PrimaryDrawerItem().withName(context.getResources().getString(R.string.action_hidden_apps)).withIcon(GoogleMaterial.Icon.gmd_visibility_off).withBadge(hiddenApps).withBadgeStyle(badgeStyle).withIdentifier(4),
new DividerDrawerItem(),
new SecondaryDrawerItem().withName(context.getResources().getString(R.string.action_settings)).withIcon(GoogleMaterial.Icon.gmd_settings).withSelectable(false).withIdentifier(6),
new SecondaryDrawerItem().withName(context.getResources().getString(R.string.action_about)).withIcon(GoogleMaterial.Icon.gmd_info).withSelectable(false).withIdentifier(7));
} else {
drawerBuilder.addDrawerItems(
new PrimaryDrawerItem().withName(context.getResources().getString(R.string.action_apps)).withIcon(GoogleMaterial.Icon.gmd_phone_android).withBadge(apps).withBadgeStyle(badgeStyle).withIdentifier(1),
new PrimaryDrawerItem().withName(context.getResources().getString(R.string.action_system_apps)).withIcon(GoogleMaterial.Icon.gmd_android).withBadge(systemApps).withBadgeStyle(badgeStyle).withIdentifier(2),
new DividerDrawerItem(),
new PrimaryDrawerItem().withName(context.getResources().getString(R.string.action_favorites)).withIcon(GoogleMaterial.Icon.gmd_star).withBadge(favoriteApps).withBadgeStyle(badgeStyle).withIdentifier(3),
new DividerDrawerItem(),
new SecondaryDrawerItem().withName(context.getResources().getString(R.string.action_buy)).withIcon(GoogleMaterial.Icon.gmd_shop).withBadge(context.getResources().getString(R.string.action_buy_description)).withSelectable(false).withIdentifier(5),
new SecondaryDrawerItem().withName(context.getResources().getString(R.string.action_settings)).withIcon(GoogleMaterial.Icon.gmd_settings).withSelectable(false).withIdentifier(6),
new SecondaryDrawerItem().withName(context.getResources().getString(R.string.action_about)).withIcon(GoogleMaterial.Icon.gmd_info).withSelectable(false).withIdentifier(7));
}
drawerBuilder.withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
@Override
public boolean onItemClick(View view, int position, IDrawerItem iDrawerItem) {
switch (iDrawerItem.getIdentifier()) {
case 1:
recyclerView.setAdapter(appAdapter);
break;
case 2:
recyclerView.setAdapter(appSystemAdapter);
break;
case 3:
recyclerView.setAdapter(appFavoriteAdapter);
break;
case 4:
recyclerView.setAdapter(appHiddenAdapter);
break;
case 5:
UtilsDialog.showProFeatures(context);
break;
case 6:
context.startActivity(new Intent(context, SettingsActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
break;
case 7:
context.startActivity(new Intent(context, AboutActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
break;
default:
break;
}
return false;
}
});
return drawerBuilder.build();
}