Android widget使用心得

因?yàn)楣卷?xiàng)目需求猩系,需要實(shí)現(xiàn)widget 來刷新數(shù)據(jù)拒名,稀里糊涂的做,然后踩了很多坑顾彰,寫個文章來總結(jié)下widget一些實(shí)際上遇到的坑极阅。

官方API地址:官方api(中文,最美語言)

(方便查看涨享,中文的筋搏,比較詳細(xì))

如果widget簡單實(shí)用就參考下面文章:基本使用?這篇文章更多幫你理理一些思路,或者理清楚一下

1.Widget(小組件)具體是啥

你的Widget(小組件)都需要繼承AppWidgetProvider 灰伟,然后這個呢拆又,是繼承BroadcastReceiver,所以呢栏账,也不用我多說帖族,Widget(小組件)就是一個廣播,廣播呢挡爵,就會有我開發(fā)過程中的第一個坑

Widget(小組件)說沒就沒竖般,數(shù)據(jù)說不刷新就不刷新,雖然系統(tǒng)給了個固定刷新機(jī)制茶鹃,但是實(shí)際測試中涣雕,會根據(jù)你當(dāng)前測試機(jī)的型號不同艰亮,得到的效果也各不相同(不得不吐槽某充電xx分鐘,通話xx小時的某國產(chǎn)手機(jī))挣郭。具體原因可以看下Widget無響應(yīng)迄埃。個人也是直接抄答案沒有細(xì)想,最后稍微帶著經(jīng)驗(yàn)猜測如下:

Widget(小組件)說白了就是個廣播兑障,廣播一般都是發(fā)完就不會管后續(xù)的呢侄非,所以如果你想一個廣播一直前臺更新數(shù)據(jù)挺有局限的呢,所以我開發(fā)過程中會碰到Widget(小組件)說沒就沒現(xiàn)象特別多流译,并且你壓根找不到原因是啥逞怨。所以Widget(小組件)真就一個廣播,廣播备T瑁活(小弟不才叠赦,學(xué)藝不精不會),所以在onReceive 持久化數(shù)據(jù)不得行革砸。

@Override

public void onReceive(final Context context, Intent intent) {

敲黑板了除秀,這里處理數(shù)據(jù)很大概率會碰到無響應(yīng),或者接收不到廣播

super.onReceive(context, intent);

}

解決辦法:在你的自身的Provider 也就是你按照xxWidgetProvider extend AppWidgetProvider的不要做數(shù)據(jù)處理业岁,開啟個服務(wù) 按照我如下操作就行?

package com.haixue.highendclass.widget;

import android.appwidget.AppWidgetManager;

import android.appwidget.AppWidgetProvider;

import android.content.Context;

import android.content.Intent;

import android.os.Build;

import android.os.Bundle;

import com.haixue.highendclass.common.Constants;

import com.haixue.highendclass.utils.Ln;

import com.haixue.yijian.BuildConfig;

public class HxWidgetProvider extends AppWidgetProvider {

// 更新 widget 的廣播對應(yīng)的action 這個其實(shí)是刷新所有頁面的

? ? public static final StringTAG="zzzz";

? ? /**

* 接收窗口小部件點(diǎn)擊時發(fā)送的廣播

*/

? ? @Override

? ? public void onReceive(final Context context, Intent intent) {

super.onReceive(context, intent);

? ? }

// 當(dāng) widget 被初次添加 或者 當(dāng) widget 的大小被改變時鳞仙,被調(diào)用

? ? @Override

? ? public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle

newOptions) {

super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);

? ? }

/**

* 當(dāng)小部件從備份恢復(fù)時調(diào)用該方法

*/

? ? @Override

? ? public void onRestored(Context context, int[] oldWidgetIds, int[] newWidgetIds) {

super.onRestored(context, oldWidgetIds, newWidgetIds);

? ? }

/**

* 每次窗口小部件被點(diǎn)擊更新都調(diào)用一次該方法

*/

? ? @Override

? ? public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {

// 每次 widget 被創(chuàng)建時,開啟服務(wù)笔时,后續(xù)服務(wù)處理業(yè)務(wù)邏輯

? ? ? ? Intent intent=new Intent(context,WidgetService.class);

? ? ? ? intent.setAction(Constants.ACTION_WIDGET_REFRESH_DATA);

? ? ? ? intent.putExtra(Constants.TAG_WIDGET_UPDATE_DATA,appWidgetIds);

? ? ? ? if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

context.startForegroundService(intent);

? ? ? ? }else {

context.startService(intent);

? ? ? ? }

super.onUpdate(context, appWidgetManager, appWidgetIds);

? ? }

/**

* 當(dāng)最后一個該窗口小部件刪除時調(diào)用該方法棍好,注意是最后一個

*/

? ? @Override

? ? public void onDisabled(Context context) {

// 在最后一個 widget 被刪除時,終止服務(wù)

? ? ? ? Intent intent =new Intent(context, WidgetService.class);

? ? ? ? context.stopService(intent);

? ? ? ? super.onDisabled(context);

? ? }

}

也就是基本上的生命周期只是做個擺設(shè)允耿,你直接去Service處理邏輯就行借笙,只能說這里有點(diǎn)不負(fù)責(zé)任,沒有給代碼较锡,這里注意下?

context.startForegroundService(intent);和context.startService(intent);區(qū)別业稼,startForegroundService導(dǎo)致部分機(jī)型有widget更新消息一直在消息欄,這里算是沒有解決的坑蚂蕴,所以Widget(小組件)低散,其實(shí)也就開了個Service ,剩下都在Service中處理?

我也是參考了這個時鐘例子(但是并不那么完美)

一般更新widget操作:

AppWidgetManager manager = AppWidgetManager.getInstance(context);

int[] idLs = manager.getAppWidgetIds(new ComponentName(context.getPackageName(), HxWidgetProvider.class.getName()));

//用于遍歷所有保存的widget的id

for (int i : idLs) {

int appID = i;

? ? // 獲取 layout_hx_widget.xml 對應(yīng)的RemoteViews 只顯示一條數(shù)據(jù)

? ? RemoteViews remoteView =new RemoteViews(context.getPackageName(), R.layout.layout_hx_widget);

? ? //widget點(diǎn)擊刷新按鈕骡楼,刷新數(shù)據(jù)

? ? remoteView.setOnClickPendingIntent(R.id.iv_course_refresh, getRefreshIntent(context));

? ? initViewByData(remoteView, context);

? ? // 更新 widget

? ? appWidgetManager.updateAppWidget(appID, remoteView);

}

踩的坑第二個:重點(diǎn)來了熔号,以下代碼其實(shí)在Activity和Service中也是可以執(zhí)行的,也就是widget更新并不局限你的xxWidgetProvider?extend?AppWidgetProvider 這個廣播類中鸟整,所以保持widget引镊,其實(shí)保持個Service也是可以做到實(shí)時更新數(shù)據(jù)的,所有就xxWidgetProvider 開啟個Service就能保活弟头,Service狈宰ィ活應(yīng)該比Broadcast簡單,官方建議也是如此

踩的坑第三個:widget點(diǎn)擊事件赴恨,上述基本使用文章已經(jīng)告知你疹娶,widget只支持基礎(chǔ)控件,并且你如果直接用個View伦连,也是會報(bào)錯的蚓胸。具體為啥呢?畢竟所有的類都是它的子類除师,它都能支持,就不存在不支持的View類扔枫。

一般點(diǎn)擊事件如下:

RemoteViews remoteView =new RemoteViews(context.getPackageName(), R.layout.layout_hx_widget);

//widget點(diǎn)擊刷新按鈕汛聚,刷新數(shù)據(jù)

remoteView.setOnClickPendingIntent(R.id.iv_course_refresh, getRefreshIntent(context));

initViewByData(remoteView, context);

//定義你的PendingIntent?

private PendingIntent getRefreshIntent(Context context) {

Intent intent =new Intent(context, WidgetService.class);

? ? intent.putExtra(Constants.TAG_WIDGET_UPDATE_DATA, mIds);

? ? intent.setAction(Constants.ACTION_WIDGET_REFRESH_DATA);

? ? PendingIntent pi;

? ? if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

pi = PendingIntent.getForegroundService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

? ? }else {

pi = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

? ? }

return pi;

}

重點(diǎn):PendingIntent.FLAG_UPDATE_CURRENT 這個參數(shù)很重要,決定了你的點(diǎn)擊事件是否是可以持續(xù)點(diǎn)擊??

重點(diǎn)小技巧短荐,點(diǎn)擊widget某個地方直接開啟App倚舀,或者指定App某個activity比較簡單,但是有個業(yè)務(wù)場景就是你app已經(jīng)開啟忍宋,你得跟launcher界面點(diǎn)擊app圖標(biāo)進(jìn)行一樣的操作的情況痕貌,你按照以下代碼設(shè)置

private PendingIntentgetAppIntent(Context context) {

Intent intent =new Intent(Intent.ACTION_MAIN);

? ? intent.addCategory(Intent.CATEGORY_LAUNCHER);

? ? intent.putExtra(Constants.TAG_WIDGET_OPEN_APP,TYPE_OPEN_OTHER);

? ? intent.setComponent(new ComponentName("你的包名", "你的啟動activity"));

? ? intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

? ? PendingIntent pi = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

? ? return pi;

}

以上就是widget一些體會吧,并沒有提供太多代碼糠排,有不正確的地方還希望校正

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末舵稠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子入宦,更是在濱河造成了極大的恐慌哺徊,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乾闰,死亡現(xiàn)場離奇詭異落追,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)涯肩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門轿钠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人病苗,你說我怎么就攤上這事疗垛。” “怎么了铅乡?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵继谚,是天一觀的道長。 經(jīng)常有香客問我,道長花履,這世上最難降的妖魔是什么芽世? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮诡壁,結(jié)果婚禮上济瓢,老公的妹妹穿的比我還像新娘。我一直安慰自己妹卿,他們只是感情好旺矾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著夺克,像睡著了一般箕宙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上铺纽,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天柬帕,我揣著相機(jī)與錄音,去河邊找鬼狡门。 笑死陷寝,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的其馏。 我是一名探鬼主播凤跑,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼叛复!你這毒婦竟也來了仔引?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤褐奥,失蹤者是張志新(化名)和其女友劉穎肤寝,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抖僵,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鲤看,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了耍群。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片义桂。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蹈垢,靈堂內(nèi)的尸體忽然破棺而出慷吊,到底是詐尸還是另有隱情,我是刑警寧澤曹抬,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布溉瓶,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏堰酿。R本人自食惡果不足惜疾宏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望触创。 院中可真熱鬧坎藐,春花似錦、人聲如沸哼绑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抖韩。三九已至蛀恩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間茂浮,已是汗流浹背赦肋。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留励稳,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓囱井,卻偏偏與公主長得像驹尼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子庞呕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354