這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)AppWidget如何在Android開(kāi)發(fā)中使用,文章內(nèi)容豐富且以專(zhuān)業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
站在用戶(hù)的角度思考問(wèn)題,與客戶(hù)深入溝通,找到陽(yáng)江網(wǎng)站設(shè)計(jì)與陽(yáng)江網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶(hù)體驗(yàn)好的作品,建站類(lèi)型包括:成都網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名與空間、網(wǎng)頁(yè)空間、企業(yè)郵箱。業(yè)務(wù)覆蓋陽(yáng)江地區(qū)。
什么是AppWidget
AppWidget 即桌面小部件,也叫桌面控件,就是能直接顯示在Android系統(tǒng)桌面上的小程序,先看圖:
圖中我用黃色箭頭指示的即為AppWidget,一些用戶(hù)使用比較頻繁的程序,可以做成AppWidget,這樣能方便地使用。典型的程序有時(shí)鐘、天氣、音樂(lè)播放器等。AppWidget 是Android 系統(tǒng)應(yīng)用開(kāi)發(fā)層面的一部分,有著特殊用途,使用得當(dāng)?shù)幕?,的確會(huì)為app 增色不少,它的工作原理是把一個(gè)進(jìn)程的控件嵌入到別外一個(gè)進(jìn)程的窗口里的一種方法。長(zhǎng)按桌面空白處,會(huì)出現(xiàn)一個(gè) AppWidget 的文件夾,在里面找到相應(yīng)的 AppWidget ,長(zhǎng)按拖出,即可將 AppWidget 添加到桌面,
如何開(kāi)發(fā)AppWidget
AppWidget 是通過(guò) BroadCastReceiver 的形式進(jìn)行控制的,開(kāi)發(fā) AppWidget 的主要類(lèi)為 AppWidgetProvider, 該類(lèi)繼承自 BroadCastReceiver。為了實(shí)現(xiàn)桌面小部件,開(kāi)發(fā)者只要開(kāi)發(fā)一個(gè)繼承自 AppWidgetProvider 的子類(lèi),并重寫(xiě)它的 onUpdate() 方法即可。重寫(xiě)該方法,一般來(lái)說(shuō)可按如下幾個(gè)步驟進(jìn)行:
1、創(chuàng)建一個(gè) RemoteViews 對(duì)象,這個(gè)對(duì)象加載時(shí)指定了桌面小部件的界面布局文件。
2、設(shè)置 RemoteViews 創(chuàng)建時(shí)加載的布局文件中各個(gè)元素的屬性。
3、創(chuàng)建一個(gè) ComponentName 對(duì)象
4、調(diào)用 AppWidgetManager 更新桌面小部件。
下面來(lái)看一個(gè)實(shí)際的例子,用 Android Studio 自動(dòng)生成的例子來(lái)說(shuō)。(注:我用的是最新版的 AS 2.2.3,下面簡(jiǎn)稱(chēng) AS。)
新建了一個(gè) HelloWorld 項(xiàng)目,然后新建一個(gè) AppWidget ,命名為 MyAppWidgetProvider,按默認(rèn)下一步,就完成了一個(gè)最簡(jiǎn)單的AppWidget的開(kāi)發(fā)。運(yùn)行程序之后,將小部件添加到桌面。操作步驟和默認(rèn)效果如下:
我們看看 AS 為我們自動(dòng)生成了哪些代碼呢?對(duì)照著上面說(shuō)的的步驟我們來(lái)看看。
首先,有一個(gè) MyAppWidgetProvider 的類(lèi)。
package com.example.joy.remoteviewstest; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.Context; import android.widget.RemoteViews; /** * Implementation of App Widget functionality. */ public class MyAppWidgetProvider extends AppWidgetProvider { static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { CharSequence widgetText = context.getString(R.string.appwidget_text); // Construct the RemoteViews object RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.my_app_widget_provider); views.setTextViewText(R.id.appwidget_text, widgetText); // Instruct the widget manager to update the widget appWidgetManager.updateAppWidget(appWidgetId, views); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // There may be multiple widgets active, so update all of them for (int appWidgetId : appWidgetIds) { updateAppWidget(context, appWidgetManager, appWidgetId); } } @Override public void onEnabled(Context context) { // Enter relevant functionality for when the first widget is created } @Override public void onDisabled(Context context) { // Enter relevant functionality for when the last widget is disabled } }
該類(lèi)繼承自 AppWidgetProvider ,AS默認(rèn)幫我們重寫(xiě) onUpdate() 方法,遍歷 appWidgetIds, 調(diào)用了 updateAppWidget() 方法。再看 updateAppWidget() 方法,很簡(jiǎn)單,只有四行:
第一行,CharSequence widgetText = context.getString(R.string.appwidget_text);聲明了一個(gè)字符串;
第二行,RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.my_app_widget_provider);
創(chuàng)建了一個(gè) RemoteViews 對(duì)象,第一個(gè)參數(shù)傳應(yīng)用程序包名,第二個(gè)參數(shù)指定了,RemoteViews 加載的布局文件。這一行對(duì)應(yīng)上面步驟中說(shuō)的第一點(diǎn)。可以看到在 res/layout/ 目錄下面 AS 自動(dòng)生成了一個(gè) my_app_widget_provider.xml 文件,內(nèi)容如下:
這個(gè)文件就是我們最后看到的桌面小部件的樣子,布局文件中只有一個(gè)TextView。這是你可能會(huì)問(wèn),想要加圖片可以嗎?可以,就像正常的Activity布局一樣添加 ImageView 就行了,聰明的你可能開(kāi)始想自定義小部件的樣式了,添加功能強(qiáng)大外觀漂亮逼格高的自定義控件了,很遺憾,不可以。小部件布局文件可以添加的組件是有限制的,詳細(xì)內(nèi)容在下文介紹RemoteViews 時(shí)再說(shuō)。
第三行,views.setTextViewText(R.id.appwidget_text, widgetText);
將第一行聲明的字符串賦值給上面布局文件中的 TextView,注意這里賦值時(shí),指定TextView的 id,要對(duì)應(yīng)起來(lái)。這一行對(duì)于了上面步驟中的第二點(diǎn)。
第四行,appWidgetManager.updateAppWidget(appWidgetId, views);
這里調(diào)用了 appWidgetManager.updateAppWidget() 方法,更新小部件。這一行對(duì)應(yīng)了上面步驟中的第四點(diǎn)。
這時(shí),你可能有疑問(wèn)了,上面明明說(shuō)了四個(gè)步驟,其中第三步,創(chuàng)建一個(gè) ComponentName 對(duì)象,明明就不需要。的確,這個(gè)例子中也沒(méi)有用到。如果我們手敲第四步代碼,AS的智能提示會(huì)告訴你,appWidgetManager.updateAppWidget() 有三個(gè)重載的方法。源碼中三個(gè)方法沒(méi)有寫(xiě)在一起,為了方便,這里我復(fù)制貼出官方 API 中的介紹
void | updateAppWidget(ComponentName provider, RemoteViews views) Set the RemoteViews to use for all AppWidget instances for the supplied AppWidget provider. | |||||||||||||
void | updateAppWidget(int[] appWidgetIds, RemoteViews views) Set the RemoteViews to use for the specified appWidgetIds. | |||||||||||||
void | updateAppWidget(int appWidgetId, RemoteViews views) Set the RemoteViews to use for the specified appWidgetId. |
這個(gè)三個(gè)方法都接收兩個(gè)參數(shù),第二個(gè)參數(shù)都是 RemoteViews 對(duì)象。其中第一個(gè)方法的第一個(gè)參數(shù)就是 ComponentName 對(duì)象,更新所有的 AppWidgetProvider 提供的所有的 AppWidget 實(shí)例,第二個(gè)方法時(shí)更新明確指定 Id 的 AppWidget 的對(duì)象集,第三個(gè)方法,更新明確指定 Id 的某個(gè) AppWidget 對(duì)象。所以一般我們使用第一個(gè)方法,針對(duì)所有的 AppWidget 對(duì)象,我們也可以根據(jù)需要選擇性地去更新。
到這里,所有步驟都結(jié)束了,就完了?還沒(méi)。前面說(shuō)了,自定義的 MyAppWidgetProvider 繼承自 AppWidgetProvider,而 AppWidgetProvider 又是繼承自 BroadCastReceiver,
所以說(shuō) MyAppWidgetProvider 本質(zhì)上是一個(gè)廣播接受者,屬于四大組件之一,需要我們的清單文件中注冊(cè)。打開(kāi)AndroidManifest.xml文件可以看到,的確是注冊(cè)了小部件的,內(nèi)容如下:
上面代碼中有一個(gè) Action,這個(gè) Action 必須要加,且不能更改,屬于系統(tǒng)規(guī)范,是作為小部件的標(biāo)識(shí)而存在的。如果不加,這個(gè) Receiver 就不會(huì)出現(xiàn)在小部件列表里面。然后看到小部件指定了 @xml/my_app_widget_provider_info 作為meta-data,細(xì)心的你發(fā)現(xiàn)了,在 res/ 目錄下面建立了一個(gè) xml 文件夾,下面新建了一個(gè) my_app_widget_provider_info.xml 文件,內(nèi)容如下:
<?xml version="1.0" encoding="utf-8"?>
這里配置了一些小部件的基本信息,常用的屬性有 initialLayout 就是小部件的初始化布局, minHeight 定義了小部件的最小高度,previewImage 指定了小部件在小部件列表里的預(yù)覽圖,updatePeriodMillis 指定了小部件更新周期,單位為毫秒。更多屬性,可以查看API文檔。
到這里,上面這個(gè)極簡(jiǎn)單的小部件開(kāi)發(fā)過(guò)程就真的結(jié)束了。為了開(kāi)發(fā)出更強(qiáng)大一點(diǎn)小部件,我們還需要進(jìn)一步了解 RemoteViews 和 AppWidgetProvider。
AppWidget的妝容——RemoteViews
下面簡(jiǎn)單說(shuō)說(shuō) RemoteViews 相關(guān)的幾個(gè)類(lèi)。
1.1 RemoteViews
RemoteViews,從字面意思理解為它是一個(gè)遠(yuǎn)程視圖。是一種遠(yuǎn)程的 View,它在其它進(jìn)程中顯示,卻可以在另一個(gè)進(jìn)程中更新。RemoteViews 在Android中的使用場(chǎng)景主要有:自定義通知欄和桌面小部件。
在RemoteViews 的構(gòu)造函數(shù)中,第二個(gè)參數(shù)接收一個(gè) layout 文件來(lái)確定 RemoteViews 的視圖;然后,我們調(diào)用RemoteViews 中的 set 方法對(duì) layout 中的各個(gè)組件進(jìn)行設(shè)置,例如,可以調(diào)用 setTextViewText() 來(lái)設(shè)置 TextView 組件的文本。
前面提到,小部件布局文件可以添加的組件是有限制的,它可以支持的 View 類(lèi)型包括四種布局:FrameLayout、LinearLayout、RelativeLayout、GridLayout 和 13 種View: AnalogClock、Button、Chronometer、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView、AdapterViewFlipper、ViewSub。注意:RemoteViews 也并不支持上述 View 的子類(lèi)。
RemoteViews 提供了一系列 setXXX() 方法來(lái)為小部件的子視圖設(shè)置屬性。具體可以參考 API 文檔。
1.2 RemoteViewsService
RemoteViewsService,是管理RemoteViews的服務(wù)。一般,當(dāng)AppWidget 中包含 GridView、ListView、StackView 等集合視圖時(shí),才需要使用RemoteViewsService來(lái)進(jìn)行更新、管理。RemoteViewsService 更新集合視圖的一般步驟是:
(01) 通過(guò) setRemoteAdapter() 方法來(lái)設(shè)置 RemoteViews 對(duì)應(yīng) RemoteViewsService 。
(02) 之后在 RemoteViewsService 中,實(shí)現(xiàn) RemoteViewsFactory 接口。然后,在 RemoteViewsFactory 接口中對(duì)集合視圖的各個(gè)子項(xiàng)進(jìn)行設(shè)置,例如 ListView 中的每一Item。
1.3 RemoteViewsFactory
通過(guò)RemoteViewsService中的介紹,我們知道RemoteViewsService是通過(guò) RemoteViewsFactory來(lái)具體管理layout中集合視圖的,RemoteViewsFactory是RemoteViewsService中的一個(gè)內(nèi)部接口。RemoteViewsFactory提供了一系列的方法管理集合視圖中的每一項(xiàng)。例如:
RemoteViews getViewAt(int position)
通過(guò)getViewAt()來(lái)獲取“集合視圖”中的第position項(xiàng)的視圖,視圖是以RemoteViews的對(duì)象返回的。
int getCount()
通過(guò)getCount()來(lái)獲取“集合視圖”中所有子項(xiàng)的總數(shù)。
AppWidget的美貌——AppWidgetProvider
我們說(shuō)一位女同事漂亮,除了因?yàn)樗┑囊路⒒膴y漂亮以外,我想最主要的原因還是她本人長(zhǎng)的漂亮吧。同樣,小部件之所以有附著在桌面,跨進(jìn)程更新 View 的能力,主要是因?yàn)锳ppWidgetProvider 是一個(gè)廣播接收者。
我們發(fā)現(xiàn),上面的例子中,AS 幫我們自動(dòng)生成的代碼中,除了 onUpdate() 方法被我們重寫(xiě)了,還有重寫(xiě) onEnable() 和 onDisable() 兩個(gè)方法,但都是空實(shí)現(xiàn),這兩個(gè)方法什么時(shí)候會(huì)被調(diào)用?還有,我們說(shuō)自定義的 MyAppWidgetProvider,繼承自 AppWidgetProvider,而 MyAppWidgetProvider 又是BroadCastReceiver 的子類(lèi),而我們卻沒(méi)有向?qū)懗R?guī)廣播接收者一樣重寫(xiě) onReceiver() 方法?下面跟進(jìn)去 AppWidgetProvider 源碼,一探究竟。
這個(gè)類(lèi)代碼并不多,其實(shí),AppWidgetProvider 出去構(gòu)造方法外,總共只有下面這些方法:
onEnable() :當(dāng)小部件第一次被添加到桌面時(shí)回調(diào)該方法,可添加多次,但只在第一次調(diào)用。對(duì)用廣播的 Action 為 ACTION_APPWIDGET_ENABLE。
onUpdate(): 當(dāng)小部件被添加時(shí)或者每次小部件更新時(shí)都會(huì)調(diào)用一次該方法,配置文件中配置小部件的更新周期 updatePeriodMillis,每次更新都會(huì)調(diào)用。對(duì)應(yīng)廣播 Action 為:ACTION_APPWIDGET_UPDATE 和 ACTION_APPWIDGET_RESTORED 。
onDisabled(): 當(dāng)最后一個(gè)該類(lèi)型的小部件從桌面移除時(shí)調(diào)用,對(duì)應(yīng)的廣播的 Action 為 ACTION_APPWIDGET_DISABLED。
onDeleted(): 每刪除一個(gè)小部件就調(diào)用一次。對(duì)應(yīng)的廣播的 Action 為: ACTION_APPWIDGET_DELETED 。
onRestored(): 當(dāng)小部件從備份中還原,或者恢復(fù)設(shè)置的時(shí)候,會(huì)調(diào)用,實(shí)際用的比較少。對(duì)應(yīng)廣播的 Action 為 ACTION_APPWIDGET_RESTORED。
onAppWidgetOptionsChanged(): 當(dāng)小部件布局發(fā)生更改的時(shí)候調(diào)用。對(duì)應(yīng)廣播的 Action 為 ACTION_APPWIDGET_OPTIONS_CHANGED。
最后就是 onReceive() 方法了,AppWidgetProvider 重寫(xiě)了該方法,用于分發(fā)具體的時(shí)間給上述的方法。看看源碼:
public void onReceive(Context context, Intent intent) { // Protect against rogue update broadcasts (not really a security issue, // just filter bad broacasts out so subclasses are less likely to crash). String action = intent.getAction(); if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) { Bundle extras = intent.getExtras(); if (extras != null) { int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS); if (appWidgetIds != null && appWidgetIds.length > 0) { this.onUpdate(context, AppWidgetManager.getInstance(context), appWidgetIds); } } } else if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) { Bundle extras = intent.getExtras(); if (extras != null && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID)) { final int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID); this.onDeleted(context, new int[] { appWidgetId }); } } else if (AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED.equals(action)) { Bundle extras = intent.getExtras(); if (extras != null && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID) && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS)) { int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID); Bundle widgetExtras = extras.getBundle(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS); this.onAppWidgetOptionsChanged(context, AppWidgetManager.getInstance(context), appWidgetId, widgetExtras); } } else if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) { this.onEnabled(context); } else if (AppWidgetManager.ACTION_APPWIDGET_DISABLED.equals(action)) { this.onDisabled(context); } else if (AppWidgetManager.ACTION_APPWIDGET_RESTORED.equals(action)) { Bundle extras = intent.getExtras(); if (extras != null) { int[] oldIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS); int[] newIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS); if (oldIds != null && oldIds.length > 0) { this.onRestored(context, oldIds, newIds); this.onUpdate(context, AppWidgetManager.getInstance(context), newIds); } } } }
AppWidget 練習(xí)
下面再自己寫(xiě)個(gè)例子,學(xué)習(xí) RemoteViews 中的其它知識(shí)點(diǎn),這個(gè)例子中小部件布局中用到 button 和 listview。上代碼:
小部件的布局文件 mul_app_widget_provider.xml 如下:
<?xml version="1.0" encoding="utf-8"?>
小部件的配置信息 mul_app_widget_provider_info.xml 如下:
<?xml version="1.0" encoding="utf-8"?>
MulAppWidgetProvider.java:
package com.example.joy.remoteviewstest; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.text.TextUtils; import android.widget.RemoteViews; import android.widget.Toast; public class MulAppWidgetProvider extends AppWidgetProvider { public static final String CHANGE_IMAGE = "com.example.joy.action.CHANGE_IMAGE"; private RemoteViews mRemoteViews; private ComponentName mComponentName; private int[] imgs = new int[]{ R.mipmap.a1, R.mipmap.b2, R.mipmap.c3, R.mipmap.d4, R.mipmap.e5, R.mipmap.f6 }; @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { mRemoteViews = new RemoteViews(context.getPackageName(), R.layout.mul_app_widget_provider); mRemoteViews.setImageViewResource(R.id.iv_test, R.mipmap.ic_launcher); mRemoteViews.setTextViewText(R.id.btn_test, "點(diǎn)擊跳轉(zhuǎn)到Activity"); Intent skipIntent = new Intent(context, MainActivity.class); PendingIntent pi = PendingIntent.getActivity(context, 200, skipIntent, PendingIntent.FLAG_CANCEL_CURRENT); mRemoteViews.setOnClickPendingIntent(R.id.btn_test, pi); // 設(shè)置 ListView 的adapter。 // (01) intent: 對(duì)應(yīng)啟動(dòng) ListViewService(RemoteViewsService) 的intent // (02) setRemoteAdapter: 設(shè)置 ListView 的適配器 // 通過(guò)setRemoteAdapter將 ListView 和ListViewService關(guān)聯(lián)起來(lái), // 以達(dá)到通過(guò) GridWidgetService 更新 gridview 的目的 Intent lvIntent = new Intent(context, ListViewService.class); mRemoteViews.setRemoteAdapter(R.id.lv_test, lvIntent); mRemoteViews.setEmptyView(R.id.lv_test,android.R.id.empty); // 設(shè)置響應(yīng) ListView 的intent模板 // 說(shuō)明:“集合控件(如GridView、ListView、StackView等)”中包含很多子元素,如GridView包含很多格子。 // 它們不能像普通的按鈕一樣通過(guò) setOnClickPendingIntent 設(shè)置點(diǎn)擊事件,必須先通過(guò)兩步。 // (01) 通過(guò) setPendingIntentTemplate 設(shè)置 “intent模板”,這是比不可少的! // (02) 然后在處理該“集合控件”的RemoteViewsFactory類(lèi)的getViewAt()接口中 通過(guò) setOnClickFillInIntent 設(shè)置“集合控件的某一項(xiàng)的數(shù)據(jù)” /* * setPendingIntentTemplate 設(shè)置pendingIntent 模板 * setOnClickFillInIntent 可以將fillInIntent 添加到pendingIntent中 */ Intent toIntent = new Intent(CHANGE_IMAGE); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 200, toIntent, PendingIntent.FLAG_UPDATE_CURRENT); mRemoteViews.setPendingIntentTemplate(R.id.lv_test, pendingIntent); mComponentName = new ComponentName(context, MulAppWidgetProvider.class); appWidgetManager.updateAppWidget(mComponentName, mRemoteViews); } @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); if(TextUtils.equals(CHANGE_IMAGE,intent.getAction())){ Bundle extras = intent.getExtras(); int position = extras.getInt(ListViewService.INITENT_DATA); mRemoteViews = new RemoteViews(context.getPackageName(), R.layout.mul_app_widget_provider); mRemoteViews.setImageViewResource(R.id.iv_test, imgs[position]); mComponentName = new ComponentName(context, MulAppWidgetProvider.class); AppWidgetManager.getInstance(context).updateAppWidget(mComponentName, mRemoteViews); } } }
MainActivity.java:
package com.example.joy.remoteviewstest; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
下面重點(diǎn)是 ListView 在小部件中的用法:
package com.example.joy.remoteviewstest; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.widget.RemoteViews; import android.widget.RemoteViewsService; import java.util.ArrayList; import java.util.List; public class ListViewService extends RemoteViewsService { public static final String INITENT_DATA = "extra_data"; @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { return new ListRemoteViewsFactory(this.getApplicationContext(), intent); } private class ListRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { private Context mContext; private ListmList = new ArrayList<>(); public ListRemoteViewsFactory(Context context, Intent intent) { mContext = context; } @Override public void onCreate() { mList.add("一"); mList.add("二"); mList.add("三"); mList.add("四"); mList.add("五"); mList.add("六"); } @Override public void onDataSetChanged() { } @Override public void onDestroy() { mList.clear(); } @Override public int getCount() { return mList.size(); } @Override public RemoteViews getViewAt(int position) { RemoteViews views = new RemoteViews(mContext.getPackageName(), android.R.layout.simple_list_item_1); views.setTextViewText(android.R.id.text1, "item:" + mList.get(position)); Bundle extras = new Bundle(); extras.putInt(ListViewService.INITENT_DATA, position); Intent changeIntent = new Intent(); changeIntent.setAction(MulAppWidgetProvider.CHANGE_IMAGE); changeIntent.putExtras(extras); /* android.R.layout.simple_list_item_1 --- id --- text1 * listview的item click:將 changeIntent 發(fā)送, * changeIntent 它默認(rèn)的就有action 是provider中使用 setPendingIntentTemplate 設(shè)置的action*/ views.setOnClickFillInIntent(android.R.id.text1, changeIntent); return views; } /* 在更新界面的時(shí)候如果耗時(shí)就會(huì)顯示 正在加載... 的默認(rèn)字樣,但是你可以更改這個(gè)界面 * 如果返回null 顯示默認(rèn)界面 * 否則 加載自定義的,返回RemoteViews */ @Override public RemoteViews getLoadingView() { return null; } @Override public int getViewTypeCount() { return 1; } @Override public long getItemId(int position) { return position; } @Override public boolean hasStableIds() { return false; } } }
最后看看清單文件:
<?xml version="1.0" encoding="utf-8"?>
這個(gè)小部件添加到桌面后有一個(gè) ImageView 顯示小機(jī)器人,下面有一個(gè) Button ,右邊有一個(gè)ListView。
這里主要看看,Button 和 ListView 在 RemoteViews中如何使用。、
Button 設(shè)置 Text 和 TextView 一樣,因?yàn)?Button 本身繼承自 TextView,Button 設(shè)置點(diǎn)擊事件如下:
Intent skipIntent = new Intent(context, MainActivity.class); PendingIntent pi = PendingIntent.getActivity(context, 200, skipIntent, PendingIntent.FLAG_CANCEL_CURRENT); mRemoteViews.setOnClickPendingIntent(R.id.btn_test, pi);
用到方法 setOnClickPendingIntent,PendingIntent 表示延遲的 Intent , 與通知中的用法一樣。這里點(diǎn)擊之后跳轉(zhuǎn)到了 MainActivity。
關(guān)于 ListView 的用法就復(fù)雜一些了。首先需要自定義一個(gè)類(lèi)繼承自 RemoteViewsServices ,并重寫(xiě) onGetViewFactory 方法,返回 RemoteViewsService.RemoteViewsFactory 接口的對(duì)象。這里定義了一個(gè)內(nèi)部類(lèi)實(shí)現(xiàn)該接口,需要重寫(xiě)多個(gè)方法,與 ListView 的多布局適配很類(lèi)似。重點(diǎn)方法是
public RemoteViews getViewAt(int position){}
這個(gè)方法中指定了 ListView 的每一個(gè) item 的布局以及內(nèi)容,同時(shí)通過(guò) setOnClickFillInIntent() 或者 setOnClickPendingIntent() 給 item 設(shè)置點(diǎn)擊事件。這里我實(shí)現(xiàn)的點(diǎn)擊 item,替換左邊的 ImageView 的圖片。重寫(xiě)了 MulAppWidgetProvider 類(lèi)的 onReceiver 方法,處理替換圖片的邏輯。
程序運(yùn)行效果如下圖:
上述就是小編為大家分享的AppWidget如何在Android開(kāi)發(fā)中使用了,如果剛好有類(lèi)似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。