# 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()); } } };