功能 |
思路 |
软件管理 对已安装的apk的管理 data/app system/app apk->>功能清单
|
1.获取apk信息的集合 2.PackageManager包管理者 查询与删除 3.PackageInfo 一个功能清单的解析内容的javaBean 4.ApplicationInfo 一个appliation标签 的解析信息 图标 应用名 路径. 5.flags变量 二进制 |分配 & 包含 6.复杂列表显示 ListView+BaseAdapter 7.两个方法getViewTypeCount视图种类 8.getItemViewType指定下标的类型-->getView 9.优化: 普通 列表 的n倍 10.Eviroment环境变量 11.PopupWindow 弹出视图 指定坐标显示 12.ScaleAnimation 缩放 AnimationSet动画集合 13.隐式意图:使用请求参数action动作category类型 data数据 14.adb命令+RootUtils.jar命令开发包 |
进程管理 对正在运行的程序的管理,查看 终止 相当于window任务管理器 |
1.进程 程序 线程 2.ActivityManager进程管理者 系统级的服务 3.获取正在运行的进程信息集合 uid pid porcessName 4.给PackageManager来获取图标应用名 5.配置进程名 6.使用flags分类 7.使用复杂ListView getViewTypeCount种类 8.getItemViewType 显示指定下标的视图 9.进程个数据 用户+系统 10.总内存:兼容 /proc/meminfo 读取第一行 11.killBackGorundProcess +权限 12.守护服务 13.服务级别 startForeGround 14.定时清理 Timer 1 2 3 4 CountDownTiemr倒计时 15.锁屏清理 接收SCREEN_OFF+清理所有进程 注意:代码注册广播 16.BaseAdapter的getCount 决定行数 |
AppWidget 显示在桌面的小程序 |
当用Activity来开发 |
参考文档完成 |
1.继承 AppWidgetProvider BoradcastReceiver的子类 2.布局 3.配置 4.xml描述 5.用户从widgets页面拖到桌面 6.刷新 Timer+Service 7.RemoteViews 对视图的操作的工具 a.初始化 b.写事件 8.BroadcastReceiver 来响应点击 |
用户应用程序的卸载:调用系统应用卸载界面.刷新
系统应用程序的卸载:以root账号登录 删除system/app/...apk
C:\Users\itheima>adb root 登录
adbd is already running as root
C:\Users\itheima>adb remount system/app 授权
remount succeeded
C:\Users\itheima>adb shell shell命令
root@vbox86p:/ # rm -r system/app/Calculator.apk 强制删除
rm -r system/app/Calculator.apk
root@vbox86p:/ #
RootTools.jar |
将命令发送给手机的一个开发库 |
|
|
mount -o remount , rw system/app
rm -r system/app/Calculator.apk
try {
if (!RootTools.isRootAvailable()) {
Toast.makeText(getBaseContext(), "请root手机", 0).show();
return;
}
if (!RootTools.isAccessGiven()) {
Toast.makeText(getBaseContext(), "授权后可卸载系统应用程序", 0).show();
return;
}
// 系统
// mount -o remount , rw system/app
RootTools.sendShell("mount -o remount , rw system/app", 2000);
// rm -r system/app/Calculator.apk
RootTools.sendShell("rm -r "+apkInfo.path, 2000);
Log.i("wzx", apkInfo.path+"");
} catch (Exception e) {
e.printStackTrace();
}
动画 Animation
|--TranslateAnimation
|--RoateAnimation
|--ScaleAnimation
|--AlphaAnimation
// ScaleAnimation:缩放动画
// AlphaAnimation:透明度
// AnimationSet:动画集合
ScaleAnimation anim = new ScaleAnimation//
(0.5f, 1.0f, 0.5f, 1.0f, //
ScaleAnimation.RELATIVE_TO_SELF, 0.0f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(500);
// 1.宽高 0.5,0.5 -->1.0 1.0
// 2.动画 时长 500
// 3.点是 定点
AlphaAnimation anim2 = new AlphaAnimation(0.5f, 1.0f);
anim2.setDuration(500);
AnimationSet animset = new AnimationSet(false);
animset.addAnimation(anim);
animset.addAnimation(anim2);
viewPop.startAnimation(animset);
需求:帮助用户 管理进程(查看 释放内存),类似 window任务管理器
进程 |
程序(apk) |
线程 |
程序被打开,系统分配cpu与内存(资源) |
安装在手机上 成为一个程序 |
java 处理耗时代码 线程 Thread 编程 |
程序---》运行--》进程
进程--》终止-->程序
知识要点:
① 创建 Activity a.继承 b.重写 c.配置 d.启动 布局
② 获取进程数(正在运行的程序个数)
ActivityManager |
activity运行中 进程管理者 1.系统服务getSystemService 2.获取 个数 3.获取进程信息的集合 4.杀死后台进程 |
android 底层linux |
linux proc目录 存放 的系统的信息。 1.cpu 2.men 3.流量 |
/**
* 获取系统中的进程个数
* @param context
* @return
*/
public static int getProcessCount(Context context)
{
//获取进程管理者
ActivityManager am=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
//获取个数process=RunningApp
List
return list.size();
}
③ 内存信息
/**
* 获取可用内存
*
* @param context
* @return
*/
public static long getFreeMem(Context context) {
// 获取进程管理者
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
// 获取进程信息
am.getMemoryInfo(mi);
return mi.availMem;
}
/**
* 获取总内存
*
* @param context
* @return
*/
@SuppressLint("NewApi")
public static long getTotalMem(Context context) {
// 获取进程管理者
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
// 获取进程信息
am.getMemoryInfo(mi);
return mi.totalMem;// api 级别为16才有 sdk
}
public static long getTotalMem(Context context) {
long total = 0;
try {
// 创建 文件流
// 读取第一行
// 解析出数量
// 返回*1024
File file = new File("proc/meminfo");
// BufferedReader字符读取器
BufferedReader reader = new BufferedReader(new FileReader(file));
String firstLine = reader.readLine();
// root@vbox86p:/proc # cat meminfo
char[] chars = firstLine.toCharArray();
StringBuffer sb = new StringBuffer();
for (char c : chars) {
if (c >= '0' && c <= '9') {
sb.append(c);
}
}
// cat meminfo
// MemTotal: 511128 kB
// 511128 kb
total = Long.parseLong(sb.toString()) * 1024;// -->byte
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
return total;
}
④ 获取进程信息的集合
/**
* 获取进程信息
* @param context
* @return
*/
public static List findAll(Context context) {
// 创建集合
List list = new ArrayList();
// 获取进程管理者
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
// apk 功能清单的application
PackageManager pm = context.getPackageManager();
// 获取进程列表
List processList = am.getRunningAppProcesses();
for (RunningAppProcessInfo item : processList) {
try {
ProcessInfo bean = new ProcessInfo();
bean.uid = item.uid;
bean.pid = item.pid;
// 【默认情况】 进程名 会等于 包名
bean.packagename = item.processName;
//
⑤ 分类
⑥ 使用复杂ListView
listview.setOnItemClickListener(new ListView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
ProcessInfo info = (ProcessInfo) adapter.getItem(position);
if (info != null) {
info.isCheck = !info.isCheck;
}
// adapter =new ProcessAdapter();
// listview.setAdapter(adapter);
// // 比较
// if (adapter != null) {
// adapter.notifyDataSetChanged();//重新可见的所有行刷新
// }
ProcessViewHolder holder = (ProcessViewHolder) view.getTag();
holder.check.setChecked(info.isCheck);
}
});
⑦ 提供批量操作(项目十分流行)
@OnClick(R.id.select_all)
public void select_all(View view)
{
//用户
for(ProcessInfo bean:userProcess)
{
bean.isCheck=true;
}
//系统
for(ProcessInfo bean:systemPorcess)
{
bean.isCheck=true;
}
//界面刷新
if(adapter!=null)
{
adapter.notifyDataSetChanged();
}
}
@OnClick(R.id.select_reverse)
public void select_reverse(View view)
{
//用户
for(ProcessInfo bean:userProcess)
{
bean.isCheck=!bean.isCheck;
}
//系统
for(ProcessInfo bean:systemPorcess)
{
bean.isCheck=!bean.isCheck;
}
//界面刷新
if(adapter!=null)
{
adapter.notifyDataSetChanged();
}
}
⑧ 清理
// 获取进程管理者
ActivityManager tm = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
// tm.killBackgroundProcesses(包名);
tm.killBackgroundProcesses("com.itheima.mobilesafe");
@OnClick(R.id.clean)
public void clean(View view)
{
List selected=new ArrayList();
//只针对选中
//用户
for(ProcessInfo bean:userProcess) //不可以 不能在加强for删除集合元素
{
if(bean.isCheck)
{
selected.add(bean);
}
}
//系统
for(ProcessInfo bean:systemPorcess)
{
if(bean.isCheck)
{
selected.add(bean);
}
}
if(selected.size()<1)
{
Toast.makeText(getBaseContext(), "未选中进程", 0).show();
return ;
}
//
int freeCount=0;
long freeMemKill=0;
//kill
for(ProcessInfo bean:selected)
{
ProcessUtils.killBackGroundProcess(this, bean.packagename);
if(bean.isSystem)
{
systemPorcess.remove(bean);
}else
{
userProcess.remove(bean);
}
freeMemKill+=bean.memorySize;
++freeCount;
}
if(adapter!=null)
{
adapter.notifyDataSetChanged();//同步刷新列表
}
//从集合中删除 列表同步
//统计 释放 进程 内存 同步界面
Toast.makeText(this, "杀死"+freeCount+"个进程,释放了"+formate(freeMemKill)+"内存", 0).show();
//同步界面
process_count.setText("进程:" + (userProcess.size() + systemPorcess.size()) + "个");
//剩余内存
freemem+=freeMemKill;
String result = "剩余/总内存:" + formate(freemem) + "/" + formate(totalmem);
memory.setText(result);
}
⑨ 进程管理的设置
l 创建Activity 布局
l 事件 使用sp保存boolean
l 回到进程页面使用boolean
set_show_system_process.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// 创建Activity 布局
// 事件 使用sp保存boolean
SharedPreferencesUtils.saveBoolean(getBaseContext(), "set_show_system_process", isChecked);
// 回到进程页面使用boolean
}
});
}
@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
boolean set_show_system_processValue=SharedPreferencesUtils.getBoolean(getBaseContext(), "set_show_system_process", false);
set_show_system_process.setChecked(set_show_system_processValue);
}
显示时列表的行数
@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
if (adapter != null) {
adapter.notifyDataSetChanged();
}
showProcessCount();
}
private class ProcessAdapter extends BaseAdapter {
// 返回行数
@Override
public int getCount() {
boolean set_show_system_processValue = SharedPreferencesUtils.getBoolean(getBaseContext(), "set_show_system_process", false);
if (set_show_system_processValue) {
return 2 + userProcess.size() + systemPorcess.size();
} else {
return 1 + userProcess.size();
}
}
⑩ 防止被清理
方式一 创建守护服务 防止被人kill
a. 创建一个服务 MoSecurityService 1.继承 2.重写 3.配置 4.启动
b. onDestory 被别人kill并不会调用onDestory
public class MoSecurityService extends Service {
@Override
public void onCreate() {
super.onCreate();
Log.i("wzx", "创建复活服务...");
startService(new Intent(this,AddressShowService.class));
startService(new Intent(this,CallSmsService.class));
}
// 服务 被强行关闭 隔5秒打开自已
@Override
public void onDestroy() {
super.onDestroy();
Log.i("wzx", "销毁复活服务...onDestroy");
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
方式二:
服务也存在优先级的问题
系统>前台>后台>空
startForgound
// 提成前台
// Notification:显示状态通知里的对象
// 状态栏隐藏 小图标
// 显示:大图标 标题 描述 运行时间
// 通常绑定一个意图
// PenddingIntent:对象 Intent包装 只有点击时才打开 Pendding将来
// startForeground(编号 , 状态栏通知);
// Notification notification=new Notification(大图标, 小字, 时间);
Notification notification = new Notification(R.drawable.shenmabg, "黑马73 15K", System.currentTimeMillis());
// notification.setLatestEventInfo(上下文, 标题, 描述, 通常绑定一个意图 );
Intent intent = new Intent();
//
//
//
//
intent.setAction("itheima.intent.action.HOME");
intent.addCategory("android.intent.category.DEFAULT");
PendingIntent pendingIntent = PendingIntent.getActivity(getBaseContext(), 0, intent, 0);
notification.setLatestEventInfo(getBaseContext(), "金山手机卫士正在运行", "范德萨放松", pendingIntent);
startForeground(1, notification);
11 定时清理
Thread+while |
|
Timer |
j2se提供的定时器 ,设定时间 与时间间隔 执行一段代码 TimerTask 1 2 3 4 5 ... |
CountDownTimer |
是一个倒计时定时器 30 29 28 27 |
方法一:
// 创建定时器
timer = new Timer();
// schedule :计划 plan
// timer.schedule(task, 延时时间, 时间间隔);
timer.schedule(task, 0, 10000);//2个小时 60*2*60*1000
}
private TimerTask task = new TimerTask() {
@Override
public void run() {
Log.i("wzx", "当前是定时清理...");
// kill
List list = ProcessUtils.findAll(getBaseContext());
for (ProcessInfo item : list) {
ProcessUtils.killBackGroundProcess(getBaseContext(), item.packagename);
}
}
};
private Timer timer;
// 服务 被强行关闭 隔5秒打开自已
@Override
public void onDestroy() {
super.onDestroy();
if (task != null) {
task.cancel();
task = null;
}
Log.i("wzx", "销毁复活服务...onDestroy");
}
方法二
// timer=new CountDownTimer(任务长度,时间间隔) { 30000 1000 30 29.。
timer=new CountDownTimer(30000,1000) {
//tick 滴答
int count=30;
//读秒
@Override
public void onTick(long millisUntilFinished) {
count--;
Log.i("wzx", count+" count");
ProcessUtils.killAll(getBaseContext());
}
//最后一次
@Override
public void onFinish() {
count--;
ProcessUtils.killAll(getBaseContext());
Log.i("wzx", count+" count");
}
};
timer.start();
}
private CountDownTimer timer;
// 服务 被强行关闭 隔5秒打开自已
@Override
public void onDestroy() {
super.onDestroy();
if(timer!=null)
{
timer.cancel();
timer=null;
}
Log.i("wzx", "销毁复活服务...onDestroy");
}
12 判断服务是否在运行
/**
* 判断 服务是否在运行
* @param context
* @param serviceName
* @return
*/
public static boolean isSerivceRunning(Context context, String serviceName) {
// 获取进程管理者
ActivityManager tm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List infos = tm.getRunningServices(100);
boolean isRunning = false;
for (RunningServiceInfo item : infos) {
if (serviceName.equals(item.service.getClassName())) {
isRunning = true;
break;
}
}
return isRunning;
}
13 锁屏清理:锁屏广播接收
1.继承 2.重写 3.配置
该广播必须使用 代码注册才能生效
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);// 锁屏
filter.addAction(Intent.ACTION_SCREEN_ON);// 解锁屏
registerReceiver(receiver, filter);
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
public void onReceive(android.content.Context context, Intent intent) {
Log.i("wzx", "onReceive接收到广播" + intent.getAction());
if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())||
Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
//清理
}
};
};
// 服务 被强行关闭 隔5秒打开自已
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
Log.i("wzx", "销毁复活服务...onDestroy");
}
14 桌面小控件AppWidget (只要求 开发者能够按照文档照抄)
AppWidget:微型小程序(“一个小Activity”)
1.只显示桌面
2.如果一个程序有appWidget 用户可从”小部件” 创建
3.包含视图
4.支持事件
5.自动更新
Activity |
AppWidget |
继承activity |
继承 |--BroadcastReicever |--AppWidgetProvider |
布局view |
布局view |
配置 |
配置 |
启动 |
安装 以后由用户拖动桌面 |
刷新 Thread+handler |
通过Service+Timer |
findViewById setOnClickListner |
通过RemoteViews+BoradCastReceiver |
http://www.apiminer.org/doc/guide/topics/appwidgets/index.html
//BroadcastReceiver
//|--AppWidgetProvider
public class MyWidgetProvider extends AppWidgetProvider {
}
<receiver android:name="com.itheima.widget.receiver.MyWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/my_widget_provider" />
receiver>
描述文件
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/my_widget_layout"
android:minHeight="100dp"
android:minWidth="200dp"
android:previewImage="@drawable/pre"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="86400000" >
appwidget-provider>
public class WidgetUpdateService extends Service {
private Timer timer = null;
private TimerTask task = new TimerTask() {
@Override
public void run() {
// 9:58:32
SimpleDateFormat foramte = new SimpleDateFormat("HH:mm:ss");
Date date = new Date();
String time = foramte.format(date);
// Actvitiy findViewById set..
// 初始控件
// RemoteViews: 只是一个操作控件的工具:findViewById setText setOnClickListern
// 设置值
RemoteViews remoteviews = new RemoteViews(getPackageName(), R.layout.my_widget_layout);
remoteviews.setTextViewText(R.id.time_btn, time);// findViewById
// setText
// 更新到桌
// AppWidgetManager 桌面小程序的管理 更新widget视图
AppWidgetManager am = AppWidgetManager.getInstance(getBaseContext());
// am.updateAppWidget(provider, views);//提交到桌面进行更新
// ComponentName:组件name
ComponentName name = new ComponentName(getBaseContext(), MyWidgetProvider.class);
am.updateAppWidget(name, remoteviews);// 提交到桌面进行更新
}
};
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
timer = new Timer();
timer.schedule(task, 0, 1000);
Log.i("wzx", "widget更新服务 ....");
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if (timer != null) {
timer.cancel();
timer = null;
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
//PendingIntent点击响应的Intent
Intent intent=new Intent();
intent.setAction("itheima.appwidget.action.ON_CLICK");
PendingIntent pI=PendingIntent.getBroadcast(getBaseContext(), 0, intent, 0);
remoteviews.setOnClickPendingIntent(R.id.time_btn, pI);
public class OnClickReciever extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Toast.makeText(context, "清理进程", 0).show();
}
}
1. 桌面小程序
用户如果不看widget 暂停服务 stopService
用户看 启动 startService
appwidget生命周期
生命周期:一堆有序方法的集合,有开始 有销毁 x1 中间有可能多次
回调函数:(CallBack)都以on开头 由开发者实现(重写) 由系统调用。
Service: startService onCreate-->onStartCommand --->running -->onDestory
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onResume() {
super.onResume();
}@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onStop() {
super.onStop();
}
添加
09-21 01:08:27.840: I/wzx(2442): --onEnabled--- 第一个实例创建 Service+timer更新
09-21 01:08:27.840: I/wzx(2442): --onUpdate--- 更新桌面
09-21 01:09:08.320: I/wzx(2442): --onUpdate---第N个实例创建
删除
09-21 01:09:50.168: I/wzx(2442): --onDeleted--删除第N个实例创建
09-21 01:10:12.044: I/wzx(2442): --onDeleted---
09-21 01:10:12.044: I/wzx(2442): --onDisabled---最后一个widget实例从桌面删除 Service+Timer更新
1.1. Appwidget的尺寸问题
1.2. 山寨其它应用appwidget
a. 布局
b. 创建AppWidgetProider
c. 配置
d. 描述 创建xml
e. 更新 Service+Timer+Remoteviews+优化onEnable
f. 写事件 RemoteViews+BroadcastReceiver