三:软件管理
1.程序管理器:
将程序分为系统程序和应用程序来区分,通过点击可以卸载程序,启动程序,查看程序的详细信息
其实就是获取手机上的所以应用程序的信息,然后以listview的方式展示到界面上去,主要是通过packagermanager对象来获取信息
2.反编译:
通过apktool.bat工具来反编译.apk文件,命令:apktool d .apk,反编译出来一个文件夹,可以看到程序的资源内容,反编译会把id前的+给漏掉
3.listview的优化:
其实是利用了getview方法里的contentview这个参数,使用的时候先检查这个历史的
Contentview是否存在,如果存在则复用,如果不存在在根据布局文件进行创建,就是将
Item的布局文件通过inflater填充成一个view对象
还有一点涉及到优化:
// convertView 历史的缓存的view对象
public View getView(int position, View convertView, ViewGroup parent) {
View view;
ViewHolder holder = null;
if (convertView == null) {// 如果没有历史缓存的view对象 就利用布局文件生成一个view对象
view = View.inflate(getApplicationContext(),
R.layout.applationinstall_item, null);
holder = new ViewHolder();
Logger.i(TAG, "GETvIEW----" + position + "创建新的view对象");
holder.tv_name = (TextView) view.findViewById(R.id.tv_appname);
holder.tv_version = (TextView) view
.findViewById(R.id.tv_appversion);
holder.iv_icon = (ImageView) view.findViewById(R.id.iv_appicon);
view.setTag(holder);
} else {
view = convertView;
holder = (ViewHolder) view.getTag();
Logger.i(TAG, "GETvIEW----" + position + "使用历史的view对象");
}
AppInfo appinfo = adapterappinfos.get(position);
holder.tv_name.setText(appinfo.getAppname());
holder.tv_version.setText(appinfo.getVersion());
holder.iv_icon.setImageDrawable(appinfo.getAppicon());
return view;
}
}
static class ViewHolder {
TextView tv_name;
TextView tv_version;
ImageView iv_icon;
}
如果Listview要显示的图片很大,数据很大,可以通过分页显示,异步加载的方式来进行
4.区分系统程序和用户程序
可以参考setting的源代码
/**
*
* @param info ApplicationInfo
* @return 当前应用程序是否是用户的应用
*/
public boolean filterApp(ApplicationInfo info) {
if ((info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
return true; //代表的是一个系统的应用但是被用户升级了.(用户应用).
} else if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
return true;
}
return false;
}
1. 如果正在加载数据不能够进行界面的切换,这是一个隐含的bug
if (loading)// 如果正在加载数据 不能进行界面的切换
return;
6.程序管理器的分享和启动
7.反编译源代码:
通过dex2jar.bat来反编译classes.dex,反编译出来的jar文件通过jd-gui.exe来查看源代码
8.listview上的点击事件的处理
lv_appmanger.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
dismissPopwindow();
9.popupWindow
popupWindow = new PopupWindow(popupview, getWindowManager()
.getDefaultDisplay().getWidth() - DensityUtil.dip2px(getApplicationContext(), 80), bottom - top + DensityUtil.dip2px(getApplicationContext(), 20));
Popupwindow可以看成是一个轻量级的activity,popupwindow一定要设置一个背景图片
否则可能会出现问题
11.popupwindow上的卸载,运行,分享
case R.id.ll_app_share:
Logger.i(TAG, "分享" + packname);
Intent shareintent = new Intent("android.intent.action.SEND");
shareintent.setType("text/plain");
shareintent.putExtra("android.intent.extra.SUBJECT", "f分享");
StringBuilder localStringBuilder = new StringBuilder("Hi!推荐您使用软件:");
localStringBuilder.append("程序叫 "+packname);
shareintent.putExtra("android.intent.extra.TEXT", localStringBuilder.toString());
startActivity(shareintent);
dismissPopwindow();
break;
case R.id.ll_app_start:
Logger.i(TAG, "开启" + packname);
try {
PackageInfo packinfo = packageManager.getPackageInfo(packname,
PackageManager.GET_ACTIVITIES);
ActivityInfo[] activityinfos = packinfo.activities;
if (activityinfos != null && activityinfos.length > 0) {
ActivityInfo activityinfo = packinfo.activities[0];
String activityname = activityinfo.name;
Intent intent = new Intent();
intent.setClassName(packname, activityname);
startActivity(intent);
}else {
Toast.makeText(this, "无法启动改应用", 0).show();
}
} catch (NameNotFoundException e) {
e.printStackTrace();
Toast.makeText(this, "无法启动改应用", 0).show();
}
dismissPopwindow();
break;
case R.id.ll_app_uninstall:
Logger.i(TAG, "卸载" + packname);
//判断当前程序是否是系统的apk
AppInfo appinfo = (AppInfo) v.getTag();
if(appinfo.isUserapp()){
//激活系统的组件进行卸载应用的操作
Intent intent = new Intent();
intent.setAction(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:"+packname));
//startActivity(intent);
startActivityForResult(intent, 0);
}else{//系统应用
//TODO:弹出土司,提示用户系统应用不能被卸载
Toast.makeText(getApplicationContext(), "系统应用不能被卸载", 0).show();
}
dismissPopwindow();
break;
}
分享功能在模拟器和真机上是不一样的,在真机上可以选择通过哪个程序进行分享,会有一个弹出列表
12.程序锁
实现原理是采用了后台的一个服务,程序锁其实就是一个看门狗,它不停的监视手机里的进程的运行状态,如果它发现要启动的进程是要锁定的进程,则弹出来一个界面,让用户去输入密码,获取当前应用程序的状态需要通过activitymanager来实现,他是一个系统服务,通过getsystemservice(ACTIVITY_SERVICE)来获取
PackageManager pm;// 包管理服务 程序管理器
private ActivityManager am; // 活动的管理服务 任务管理器
监视任务栈,获取栈顶的activity,然后得到程序的包名
点击Listview条目后将程序的包名持久化到数据库中
13.服务的两种开启方式:
/**
* start开启一个后台运行的服务,
* 服务跟调用者没有任何的关系.
* 一旦服务开启就会长期的在后台运行,
* 直到显示的调用stopService的时候 服务才会停止
* @param view
*/
/**
* bind绑定开启一个服务,
* 服务的生命周期跟调用者进行了关联
* 一旦调用者ondestroy的方法,
* 绑定的服务也会停止运行
*
* 可以利用ServiceConntion的实例,去调用服务里面的方法
* @param view
*/
*注意:
*1... start方式开启服务- bind的方式绑定服务- 接触绑定服务(服务不会被停止掉)- stopservice
*
*2... start方式开启服务--bind的方式绑定服务- stopservice停止服务(服务是停不掉的)-unbindservice接触绑定服务(服务会被直接停止掉)
*
14.绑定服务,调用服务里面的方法
通过serviceconntion的实例去调用服务里面的方法
15. lv_applock.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
AdapterView<?> parent:代表当前的listview
View view:代表每一个被点击的条目
16.getview的优化:
查询数据库的操作:
/*
* if (dao.find(info.getPackname())) {
* holder.iv_lock.setImageResource(R.drawable.lock); } else {
* holder.iv_lock.setImageResource(R.drawable.unlock); }
*/
查询内存的操作:(效率高)
if (lockpacknames.contains(info.getPackname())) {
holder.iv_lock.setImageResource(R.drawable.lock);
} else {
holder.iv_lock.setImageResource(R.drawable.unlock);
}
17.service ,broadcastreceiver里没有任务栈,开启activity需要增加
entryPwdIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK );//在没有任务栈的组件里面激活activity 一定要指定FLAG_ACTIVITY_NEW_TASK 参数