日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Android时钟的widget

發(fā)布時(shí)間:2025/6/15 Android 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android时钟的widget 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前段時(shí)間解決一個(gè)widget的bug,具體分析是“appWidgetManager.updateAppWidget(THIS_APPWIDGET, views);”這個(gè)方法updateAppWidget()在恢復(fù)出廠設(shè)置后不更新了,我就查原因,結(jié)果通過(guò)log的驗(yàn)證發(fā)現(xiàn)時(shí)sdk的bug:

step 1:

[java]?view plaincopyprint?
  • <span?style="FONT-SIZE:?16px">public?void?updateAppWidget(int[]?appWidgetIds,?RemoteViews?views)?{??
  • ????????try?{??
  • ????????????sService.updateAppWidgetIds(appWidgetIds,?views);??
  • ????????}??
  • ????????catch?(RemoteException?e)?{??
  • ????????????throw?new?RuntimeException("system?server?dead?",?e);??
  • ????????}??
  • ????}</span>??
  • ?

    step 2:這個(gè)sService.updateAppWidgetIds(appWIdgetIds, views);sService是AppWidgetService的對(duì)象,在這個(gè)類(lèi)中:

    [java]?view plaincopyprint?
  • <span?style="FONT-SIZE:?16px">public?void?updateAppWidgetIds(int[]?appWidgetIds,?RemoteViews?views)?{??
  • ????????if?(appWidgetIds?==?null)?{??
  • ????????????return;??
  • ????????}??
  • ????????if?(appWidgetIds.length?==?0)?{??
  • ????????????return;??
  • ????????}??
  • ????????final?int?N?=?appWidgetIds.length;??
  • ??
  • ????????synchronized?(mAppWidgetIds)?{??
  • ????????????for?(int?i=0;?i<N;?i++)?{??
  • ????????????????AppWidgetId?id?=?lookupAppWidgetIdLocked(appWidgetIds[i]);??
  • ????????????????updateAppWidgetInstanceLocked(id,?views);??
  • ????????????}??
  • ????????}??
  • ????}</span>??
  • ?

    step 3:經(jīng)過(guò)分析代碼:updateAppWidgetInstanceLocked()這個(gè)方法出的問(wèn)題;看代碼:

    [java]?view plaincopyprint?
  • <span?style="FONT-SIZE:?16px">void?updateAppWidgetInstanceLocked(AppWidgetId?id,?RemoteViews?views)?{??
  • ????????//?allow?for?stale?appWidgetIds?and?other?badness??
  • ????????//?lookup?also?checks?that?the?calling?process?can?access?the?appWidgetId??
  • ????????//?drop?unbound?appWidgetIds?(shouldn't?be?possible?under?normal?circumstances)??
  • ????????if?(id?!=?null?&&?id.provider?!=?null?&&?!id.provider.zombie?&&?!id.host.zombie)?{??
  • ????????????id.views?=?views;??
  • ??
  • ????????????//?is?anyone?listening???
  • ????????????if?(id.host.callbacks?!=?null)?{??
  • ????????????????try?{??
  • ????????????????????//?the?lock?is?held,?but?this?is?a?oneway?call??
  • ????????????????????id.host.callbacks.updateAppWidget(id.appWidgetId,?views);??
  • ????????????????}?catch?(RemoteException?e)?{??
  • ????????????????????//?It?failed;?remove?the?callback.?No?need?to?prune?because??
  • ????????????????????//?we?know?that?this?host?is?still?referenced?by?this?instance.??
  • ????????????????????id.host.callbacks?=?null;??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????}??
  • </span>??

  • ?

    Step 4:經(jīng)過(guò)打log分析,原來(lái)這個(gè)值id.host.callbacks == null造成的沒(méi)有走到這個(gè)方法updateAppWidget(id.appWidgetId, views);這個(gè)callbacks是在這個(gè)類(lèi)的startListening的時(shí)候賦值的,下面看一下這個(gè)方法:

    [java]?view plaincopyprint?
  • ?<span?style="FONT-SIZE:?16px">public?int[]?startListening(IAppWidgetHost?callbacks,?String?packageName,?int?hostId,??
  • ????????????List<RemoteViews>?updatedViews)?{??
  • ????????int?callingUid?=?enforceCallingUid(packageName);??
  • ????????synchronized?(mAppWidgetIds)?{??
  • ????????????Host?host?=?lookupOrAddHostLocked(callingUid,?packageName,?hostId);??
  • ??????????<strong>??</strong><span?style="color:#990000;"><strong>host.callbacks?=?callbacks;</strong>??
  • ??
  • </span>????????????updatedViews.clear();??
  • ??
  • ????????????ArrayList<AppWidgetId>?instances?=?host.instances;??
  • ????????????int?N?=?instances.size();??
  • ????????????int[]?updatedIds?=?new?int[N];??
  • ????????????for?(int?i=0;?i<N;?i++)?{??
  • ????????????????AppWidgetId?id?=?instances.get(i);??
  • ????????????????updatedIds[i]?=?id.appWidgetId;??
  • ????????????????updatedViews.add(id.views);??
  • ????????????}??
  • ????????????return?updatedIds;??
  • ????????}??
  • ????}??
  • </span>??
  • 造成這個(gè)callbacks為空有兩種原因,一個(gè)是host.callbacks = callbacks;賦值后,這個(gè)host.callbacks被別的條件置為空,另一個(gè)原因是這個(gè)參數(shù)傳遞的時(shí)候callbacks就傳遞了空值。

    ?

    Step5:找到IAppWidgetHost callback賦值的地方。在AppWidgetHost中也有個(gè)startListenering方法()代碼如下:

    [java]?view plaincopyprint?
  • <span?style="FONT-SIZE:?16px">?/**?
  • ?????*?Start?receiving?onAppWidgetChanged?calls?for?your?AppWidgets.??Call?this?when?your?activity?
  • ?????*?becomes?visible,?i.e.?from?onStart()?in?your?Activity.?
  • ?????*/??
  • ????public?void?startListening()?{??
  • ????????int[]?updatedIds;??
  • ????????ArrayList<RemoteViews>?updatedViews?=?new?ArrayList<RemoteViews>();??
  • ??????????
  • ????????try?{??
  • ????????????if?(mPackageName?==?null)?{??
  • ????????????????mPackageName?=?mContext.getPackageName();??
  • ????????????}??
  • ????????????<span?style="color:#660000;"><strong>updatedIds?=?sService.startListening(mCallbacks,?mPackageName,?mHostId,?updatedViews);??
  • </strong></span>????????}??
  • ????????catch?(RemoteException?e)?{??
  • ????????????throw?new?RuntimeException("system?server?dead?",?e);??
  • ????????}??
  • ??
  • ????????final?int?N?=?updatedIds.length;??
  • ????????for?(int?i=0;?i<N;?i++)?{??
  • ????????????updateAppWidgetView(updatedIds[i],?updatedViews.get(i));??
  • ????????}??
  • ????}</span>??
  • 這個(gè)mCallbacks就是Step4中的callbacks傳遞過(guò)去的值,現(xiàn)在查找這個(gè)mCallbacks怎么賦值的??

    搜索發(fā)現(xiàn)Callbacks mCallbacks = new Callbacks();這個(gè)mCallbacks是new的。這下明了了吧,在

    sService.startListening(mCallbacks, mPackageName, mHostId, updatedViews);判斷一下,如果mCallbacks為空,再new一下。傳遞過(guò)去后,把這個(gè)callbacks的值賦給一個(gè)全局變量,在Step3的時(shí)候加一個(gè)判斷,為空的時(shí)候,賦值給id.host.callbacks。這樣就解決了為空的情況!真正的原因沒(méi)有查為什么為空?只是找到了解決方案!

    ?

    通過(guò)以上的查找,我對(duì)AppWidgetProvider有了一定的了解。借此基礎(chǔ)我寫(xiě)了一個(gè)時(shí)鐘的widget,和模擬時(shí)鐘的效果一樣的,點(diǎn)擊時(shí)鐘就能進(jìn)入到鬧鐘的界面:截圖如下:

    ????????????紅色部分是時(shí)鐘:?????????????????????????點(diǎn)擊桌面添加時(shí)鐘widget:?????點(diǎn)擊每一個(gè)進(jìn)入到鬧鐘界面:

    ??????????????????????????????????????

    ?

    ??? 因?yàn)锳ppWidgetProvider是繼承extends BroadcastReceiver, 為一個(gè)簡(jiǎn)便類(lèi)來(lái)處理App Widget廣播。AppWidgetProvider只接收和這個(gè)App Widget相關(guān)的事件廣播,比如這個(gè)App Widget被更新,刪除,啟用,以及禁用。當(dāng)這些廣播事件發(fā)生時(shí),AppWidgetProvider 將接收到下面的方法調(diào)用:


    ?? 一、onEnabled(Context ?context):

    ?????? ?當(dāng)?shù)谝淮螌?shí)例化一個(gè)appwidget的時(shí)候,接受action_appwidget_enabled廣播,重寫(xiě)此方法以實(shí)現(xiàn)自己的appwidget功能。

    ?

    ??二、onUpdate(Context context, ?AppWidgetManager appWidgetManager,? int[] appWidgetIds)

    ??????? 這個(gè)方法調(diào)用來(lái)間隔性的更新App Widget,間隔時(shí)間用AppWidgetProviderInfo 里的updatePeriodMillis屬性定義(參見(jiàn)添加AppWidgetProviderInfo元數(shù)據(jù))。這個(gè)方法也會(huì)在用戶(hù)添加App Widget時(shí)被調(diào)用,因此它應(yīng)該執(zhí)行基礎(chǔ)的設(shè)置,比如為視圖定義事件處理器并啟動(dòng)一個(gè)臨時(shí)的服務(wù)Service,如果需要的話(huà)。但是,如果你已經(jīng)聲明了一個(gè)配置活動(dòng),這個(gè)方法在用戶(hù)添加App Widget時(shí)將不會(huì)被調(diào)用,而只在后續(xù)更新時(shí)被調(diào)用。配置活動(dòng)應(yīng)該在配置完成時(shí)負(fù)責(zé)執(zhí)行第一次更新。

    ?

    三、onDisabled(Context)?
    ?????? 當(dāng)你的App Widget的最后一個(gè)實(shí)例被從宿主中刪除時(shí)被調(diào)用。你應(yīng)該在onEnabled(Context)中做一些清理工作,比如刪除一個(gè)shareparence或者是一個(gè)數(shù)據(jù)庫(kù)。

    ?

    四、onReceive(Context, Intent)?
    ????? 這個(gè)接收到每個(gè)廣播時(shí)都會(huì)被調(diào)用,而且在上面的回調(diào)函數(shù)之前。你通常不需要實(shí)現(xiàn)這個(gè)方法,因?yàn)槿笔〉腁ppWidgetProvider 實(shí)現(xiàn)過(guò)濾所有App Widget 廣播并恰當(dāng)?shù)恼{(diào)用上述方法。
    注意: 在Android?1.5中, 有一個(gè)已知問(wèn)題,onDeleted()方法在該調(diào)用時(shí)不被調(diào)用。為了規(guī)避這個(gè)問(wèn)題,你可以像

    ? Group post中描述的那樣實(shí)現(xiàn)onReceive() 來(lái)接收這個(gè)onDeleted()回調(diào)。

    ? 更多詳細(xì)知識(shí)請(qǐng)看sdk幫助文檔;

    ?

    下面把截圖的代碼簡(jiǎn)單梳理一下:

    一、在manifest中注冊(cè)receiver事件

    [html]?view plaincopyprint?
  • <span?style="FONT-SIZE:?16px"><receiver?android:name="com.cn.daming.provider.DMAlarmAppWidgetProvider"?android:label="@string/dmling_widget"??
  • ????????????android:icon="@drawable/ic_appwidget_clock148">??
  • ????????????<intent-filter>??
  • ????????????????<action?android:name="android.appwidget.action.APPWIDGET_UPDATE"?/>??
  • ????????????</intent-filter>??
  • ????????????<meta-data?android:name="android.appwidget.oldName"?android:value="com.cn.daming.provider.DMAlarmAppWidgetProvider"?/>??
  • ????????????<meta-data?android:name="android.appwidget.provider"?android:resource="@xml/dmling_appwidget"?/>??
  • ????????</receiver>??
  • ??????????
  • ??????????
  • ????????<receiver?android:name="com.cn.daming.provider.DMAlarmAppWidgetProvider2"?android:label="@string/dmling_widget2"??
  • ????????????android:icon="@drawable/ic_appwidget_clock248">??
  • ????????????<intent-filter>??
  • ????????????????<action?android:name="android.appwidget.action.APPWIDGET_UPDATE"?/>??
  • ????????????</intent-filter>??
  • ????????????<meta-data?android:name="android.appwidget.oldName2"?android:value="com.cn.daming.provider.DMAlarmAppWidgetProvider2"?/>??
  • ????????????<meta-data?android:name="android.appwidget.provider"?android:resource="@xml/dmling_appwidget2"?/>??
  • ????????</receiver>??
  • ??????????
  • ????????<receiver?android:name="com.cn.daming.provider.DMAlarmAppWidgetProvider3"?android:label="@string/dmling_widget3"??
  • ????????????android:icon="@drawable/ic_appwidget_clock348">??
  • ????????????<intent-filter>??
  • ????????????????<action?android:name="android.appwidget.action.APPWIDGET_UPDATE"?/>??
  • ????????????</intent-filter>??
  • ????????????<meta-data?android:name="android.appwidget.oldName3"?android:value="com.cn.daming.provider.DMAlarmAppWidgetProvider3"?/>??
  • ????????????<meta-data?android:name="android.appwidget.provider"?android:resource="@xml/dmling_appwidget3"?/>??
  • ????????</receiver>??
  • ????</application></span>??

  • 其中<meta-data android:name="android.appwidget.provider" android:resource="@xml/dmling_appwidget" />這個(gè)格式是固定不變的,給appwidget定義一個(gè)dmling_appwidget.xml的文件.

    ?

    二、在res目錄下建立xml文件夾,在xml文件夾中建立dmling_appwidget.xml文件

    [html]?view plaincopyprint?
  • <span?style="FONT-SIZE:?16px"><?xml?version="1.0"?encoding="utf-8"?>??
  • <appwidget-provider?xmlns:android="http://schemas.android.com/apk/res/android"??
  • ????android:minWidth="146dip"??
  • ????android:minHeight="146dip"??
  • ????android:updatePeriodMillis="0"??
  • ????android:initialLayout="@layout/damling_appwidget"??
  • ????>??
  • </appwidget-provider>??
  • ??
  • </span>??
  • 這個(gè)appwidget-provider格式是固定的。

    ?

    三、給“一”中的receiver建立一個(gè)接受類(lèi),正如“一”中的xml的語(yǔ)句中:

    ????? receiver android:name="com.cn.daming.provider.DMAlarmAppWidgetProvider"建立com.cn.daming.provider包,在

    com.cn.daming.provider包中建立DMAlarmAppWidgetProvider.java類(lèi),如下:

    [java]?view plaincopyprint?
  • <span?style="FONT-SIZE:?16px">package?com.cn.daming.provider;??
  • ??
  • import?android.app.PendingIntent;??
  • import?android.appwidget.AppWidgetManager;??
  • import?android.content.BroadcastReceiver;??
  • import?android.content.Context;??
  • import?android.content.Intent;??
  • import?android.util.Log;??
  • import?android.widget.RemoteViews;??
  • ??
  • import?com.cn.daming.deskclock.DeskClockMainActivity;??
  • import?com.cn.daming.deskclock.R;??
  • ??
  • public?class?DMAlarmAppWidgetProvider?extends?BroadcastReceiver?{??
  • ??
  • ????public?void?onReceive(Context?context,?Intent?intent)?{??
  • ????????String?action?=?intent.getAction();??
  • ??
  • ????????if?(AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action))?{??
  • ????????????RemoteViews?views?=?new?RemoteViews(context.getPackageName(),??
  • ????????????????????R.layout.damling_appwidget);??
  • ??
  • ????????????views.setOnClickPendingIntent(R.id.damling_appwidget,??
  • ????????????????????PendingIntent.getActivity(context,?0,??
  • ????????????????????????new?Intent(context,?DeskClockMainActivity.class),??
  • ????????????????????????PendingIntent.FLAG_UPDATE_CURRENT));//FLAG_NO_CREATE??
  • ??
  • ????????????int[]?appWidgetIds?=?intent.getIntArrayExtra(??
  • ????????????????????AppWidgetManager.EXTRA_APPWIDGET_IDS);??
  • ??
  • ????????????AppWidgetManager?gm?=?AppWidgetManager.getInstance(context);??
  • ????????????Log.v("wdaming",?"DMAlarmAppWidgetProvider?--->?appWidgetIds?==?"+appWidgetIds+"??gm?==?"+gm+??
  • ????????????????????"??views?==?"+views);??
  • ????????????gm.updateAppWidget(appWidgetIds,?views);??
  • ????????}??
  • ????}??
  • }??
  • </span>??

  • ?

    四、如“二”中的代碼建立layout文件damling_appwidget.xml:

    [html]?view plaincopyprint?
  • <span?style="FONT-SIZE:?16px"><?xml?version="1.0"?encoding="utf-8"?>??
  • <!--?模擬時(shí)鐘?-->??
  • <AnalogClock?xmlns:android="http://schemas.android.com/apk/res/android"??
  • ????android:id="@+id/damling_appwidget"??
  • ????android:dial="@drawable/ic_appwidget_clock1"??
  • ????android:hand_hour="@drawable/appwidget_clock_hour"??
  • ????android:hand_minute="@drawable/appwidget_clock_minute"??
  • ????android:layout_width="match_parent"??
  • ????android:layout_height="match_parent"?/>??
  • </span>??
  • ?

    這樣基本就把時(shí)鐘的widget建立好了!當(dāng)然這個(gè)沒(méi)有按照AppWidgetProvider來(lái)寫(xiě)。我參考的是鬧鐘的時(shí)鐘widget,我看這樣也挺簡(jiǎn)單的,extends BroadcastReceiver,在onReceiver中寫(xiě)一個(gè)監(jiān)聽(tīng)時(shí)鐘的點(diǎn)擊事件的方法,因?yàn)檫@個(gè)模擬時(shí)鐘是

    AnalogClock,在frameworks已經(jīng)對(duì)它做了處理,所以我們只需要給它dial【表盤(pán)】,hand_hour:【時(shí)針】,hand_minute:

    【分針】,就可以實(shí)現(xiàn)時(shí)鐘了!

    ????說(shuō)明:有問(wèn)題的,好意見(jiàn)的或者想要源碼的可以留言!歡迎各界人士拍磚!

    《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀

    總結(jié)

    以上是生活随笔為你收集整理的Android时钟的widget的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 韩国久久久久久 | 操女人视频网站 | 天天色天天插 | 免费观看黄色一级视频 | 国产精品1024 | 亚洲成人高清 | 日韩精品一区二区三区无码专区 | 老司机狠狠爱 | 挪威xxxx性hd极品 | 外国电影免费观看高清完整版 | 欧美日韩人妻精品一区二区三区 | 贵族女沦为官妓h呻吟 | 成年人免费看的视频 | 日韩欧美一区视频 | 色网站在线播放 | 男人深夜网站 | 日韩中文字幕一区二区三区四区 | 欧美午夜精品久久久久久蜜 | 欧美mv日韩mv国产网站 | 国内精品久久99人妻无码 | 屁屁影院一区二区三区 | 国产精品成人一区二区三区 | 日本欧美韩国国产精品 | 136fldh导航福利微拍 | 青青草91视频 | 日本在线播放一区 | 欧美三级视频 | 玖玖精品国产 | 亚洲视频在线网 | 国产一级视频在线观看 | 亚洲狠| 欧美综合在线视频 | 日韩精品久久一区二区 | 女女同性女同一区二区三区九色 | 精品一区二区精品 | 红桃视频网站 | 国产日韩欧美久久 | 热热色原网址 | 精品在线视频观看 | 天堂资源中文在线 | 向日葵视频在线播放 | 久久精品国产亚洲av麻豆图片 | 午夜看看 | 撸撸在线视频 | 午夜肉体高潮免费毛片 | 欧美日韩精品二区 | 国产第一福利影院 | 国模在线观看 | 在线视频第一页 | 国产精品伦一区 | 久久精品视频中文字幕 | 午夜精品极品粉嫩国产尤物 | 苍井空亚洲精品aa片在线播放 | 国产aⅴ一区二区三区 | 亚洲一区二区三 | 亚洲视频久久久 | 亚洲视频播放 | 丰满人妻一区二区 | 申鹤乳液狂飙 | 国产免费久久精品国产传媒 | 欧美久久一区二区三区 | www.亚色| 午夜影院啊啊啊 | 好吊在线视频 | 丰满岳乱妇一区二区 | 奇米影视四色7777 | 午夜在线视频免费观看 | 正在播放木下凛凛xv99 | 成人免费在线网站 | 黑人精品无码一区二区三区AV | 色婷婷成人网 | 免费a大片 | 国产不卡在线视频 | 91日本在线观看 | 美女网站一区 | 男女午夜激情视频 | 国产孕交 | 欧美图片一区 | 色四月 | 欧美日韩一区二区在线 | 超碰在 | 久草av在线播放 | 国内精品久久久久久 | 激情综合网站 | 毛片无遮挡高清免费观看 | 久久久久久久久97 | 精品国产www| 日韩成人自拍 | 精品一区二区三区成人免费视频 | 森泽佳奈av | 精品黑人一区二区三区国语馆 | 中文日韩在线观看 | 象人高潮调教丨vk | 亚洲影院在线观看 | 乱精品一区字幕二区 | 中国男人操女人 | 精品久久久久久久无码 | 不卡视频国产 | 日日夜夜一区二区 |