# widget #java
- 长按桌面, 或者在全部应用列表里向右滑动, 能够添加窗口小部件.
- 写一个类, 继承 AppWidgetProvider, 而后在清单文件里配置, 按照文档来就好了.
主要是 meta-data 标签里配置的 xml:android
<!-- <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="40dp" 最小宽高
android:minHeight="40dp"
android:updatePeriodMillis="1800000" 多久更新一下Widget, 单位是毫秒, 最短是半个小时 1800000
android:previewImage="@drawable/preview" 预览图片
android:initialLayout="@layout/example_appwidget" 布局文件
android:configure="com.example.android.ExampleAppWidgetConfigure" 配置页面
android:resizeMode="horizontal|vertical" 缩放模式
android:widgetCategory="home_screen"> 类型, 显示在桌面上, 仍是显示在锁屏界面上, API 17
</appwidget-provider> -->app
- 修改布局, 反编译金山的apk, 反编译以后再清单文件里搜索, 把须要的文件所有拷贝过来
该拷的拷, 该删的删, 该改的改. 改完了别忘了修改清单文件
- Widget的生命周期ide
public class WidgetReceiver extends AppWidgetProvider{
/**
* 接收到事件
*/
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
System.out.println("onReceive");
}
/**
* 第一次添加
*/
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
System.out.println("onEnabled");
}
/**
* 被添加(第一次, 或者再次添加)/更新
*/
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
/**
* 被删除
*/
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
}
/**
* 最后一个被删除
*/
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
}
}布局
- 定时更新Widget
看一下日志, 发现金山每隔一会就更新一下Widget, 它在配置文件里配的 android:updatePeriodMillis="0",
不依赖系统的更新, 它实际上是启动了一个服务, 在服务里作定时操做.
咱们也写一个服务, 定时更新Widget, 在 onEnabled 方法里启动, 在 onDisable 方法里中止
另外在 onUpdate 方法里也要起一下服务, 确保服务正在运行. 这是为了不桌面上已经有Widget,
而后直接在项目上右键 run as 不走 onEnabled 方法.
/**
* 被添加(第一次, 或者再次添加)/更新
*/
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
// onUpdate 方法里也要起一下服务, 确保服务正在运行. 避免桌面上已经有Widget,
// 而后直接在项目上右键 run as 不走 onEnabled 方法.
if (!ServiceStateUtil.isServiceRunning(context, UpdateWidgetService.class)) {
context.startService(new Intent(context, UpdateWidgetService.class));
}
}
## 定时器 ##this
java提供的Timer类
private void timer1() {
Timer timer = new Timer();
参1 定时任务 参2 第一次执行的延时时间 参3 间隔
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("定时器: Timer");
}
}, 0, 3000);
// 中止
// timer.cancel();
}日志
- 在相应的服务里: 在oncreate方法中 开启定时器
component
// 闹钟管理器 能够执行定时任务 而且应用退出也起做用 可是timer就不行
am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent();
intent.setAction("com.itheima.mobilesafe.action.upwidget");
// PendingIntent 延时的intent 对应的动做不会当即执行 须要有一个触发的事件
// 这里是用定时器来触发发送一个广播
operation = PendingIntent.getBroadcast(getApplicationContext(), 100, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// 参1 计时方式,参2 第一次执行的延时时间,参3执行间隔 参4 延时的intent
am.setRepeating(AlarmManager.RTC, 2000, 5000, operation);orm
//注册接受更新的广播
IntentFilter filter = new IntentFilter();
filter.addAction("com.itheima.mobilesafe.action.upwidget");
registerReceiver(receiver, filter);xml
- 关于setRepeating的参数1计时方式 了解一下
public static final int ELAPSED_REALTIME
// 当系统进入睡眠状态时,这种类型的闹铃不会唤醒系统。直到系统下次被唤醒才传递它,该闹铃所用的时间是相对时间,是从系统启动后开始计时的,包括睡眠时 间,能够经过调用SystemClock.elapsedRealtime()得到。系统值是3 (0x00000003)。
public static final int ELAPSED_REALTIME_WAKEUP
//能唤醒系统,用法同ELAPSED_REALTIME,系统值是2 (0x00000002) 。
public static final int RTC
//当系统进入睡眠状态时,这种类型的闹铃不会唤醒系统。直到系统下次被唤醒才传递它,该闹铃所用的时间是绝对时间,所用时间是UTC时间,能够经过调用 System.currentTimeMillis()得到。系统值是1 (0x00000001) 。
public static final int RTC_WAKEUP
//能唤醒系统,用法同RTC类型,系统值为 0 (0x00000000) 。
Public static final int POWER_OFF_WAKEUP
//能唤醒系统,它是一种关机闹铃,就是说设备在关机状态下也能够唤醒系统,因此咱们把它称之为关机闹铃。受SDK版本影响,某些版本并不支持,使用方法同RTC类型,系统值为4(0x00000004)。
- 在注册的receiver里
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (TextUtils.equals(action, "com.itheima.mobilesafe.action.upwidget")) {
updateWidget();
}
}
};
//更新Widget内容, 要使用 AppWidgetManager 这个类
private void updateWidget() {
// 获取 AppWidgetManager
mWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
// 初始化widget组件
ComponentName provider = new ComponentName(this, WidgetReceiver.class);
// 初始化远程view对象, 这个View不在咱们的应用进程里
RemoteViews remoteView = new RemoteViews(getPackageName(), R.layout.process_widget);
remoteView.setTextViewText(R.id.tv_running_num,
"正在运行的软件:" + ProcessInfoProvider.getRunningProcessCount(this));
remoteView.setTextViewText(R.id.tv_avail_mem,
"可用内存:" + Formatter.formatFileSize(this, ProcessInfoProvider.getAvailMemory(this)));
// 更新远程view
mWidgetManager.updateAppWidget(provider, remoteView);
}
- AppWidgetManager 和 ComponentName 初始化能够放在 onCreate 方法里.
- 在ondestroy里
@Override
public void onDestroy() {
super.onDestroy();
//服务结束取消定时器 和取消注册
am.cancel(operation);
unregisterReceiver(receiver);
}
- 设置Widget的点击事件 仍是以前的 RemoteViews那里 增长点击事件就好
Intent intent = new Intent();
intent.setAction("com.itheima.mobilesafe.action.widgetclean");
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 101,intent, PendingIntent.FLAG_UPDATE_CURRENT);
//点击发送一个广播 去杀死进程
views.setOnClickPendingIntent(R.id.btn_clear, pendingIntent);
widgetManager.updateAppWidget(component, views);
> 以前 注册的广播增长一个action
IntentFilter filter = new IntentFilter();
filter.addAction("com.itheima.mobilesafe.action.upwidget");
filter.addAction("com.itheima.mobilesafe.action.widgetclean");
registerReceiver(receiver, filter);
> 广播接收者里也增长判断
private BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (TextUtils.equals(action, "com.itheima.mobilesafe.action.upwidget")) { updateWidget(); } else if (TextUtils.equals(action, "com.itheima.mobilesafe.action.widgetclean")) { ProcessInfoProvider.killAllPro(getApplicationContext()); } } };