您好,登錄后才能下訂單哦!
這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)AppWidget如何在Android開發(fā)中使用,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
什么是AppWidget
AppWidget 即桌面小部件,也叫桌面控件,就是能直接顯示在Android系統(tǒng)桌面上的小程序,先看圖:
圖中我用黃色箭頭指示的即為AppWidget,一些用戶使用比較頻繁的程序,可以做成AppWidget,這樣能方便地使用。典型的程序有時鐘、天氣、音樂播放器等。AppWidget 是Android 系統(tǒng)應(yīng)用開發(fā)層面的一部分,有著特殊用途,使用得當(dāng)?shù)幕?,的確會為app 增色不少,它的工作原理是把一個進(jìn)程的控件嵌入到別外一個進(jìn)程的窗口里的一種方法。長按桌面空白處,會出現(xiàn)一個 AppWidget 的文件夾,在里面找到相應(yīng)的 AppWidget ,長按拖出,即可將 AppWidget 添加到桌面,
如何開發(fā)AppWidget
AppWidget 是通過 BroadCastReceiver 的形式進(jìn)行控制的,開發(fā) AppWidget 的主要類為 AppWidgetProvider, 該類繼承自 BroadCastReceiver。為了實現(xiàn)桌面小部件,開發(fā)者只要開發(fā)一個繼承自 AppWidgetProvider 的子類,并重寫它的 onUpdate() 方法即可。重寫該方法,一般來說可按如下幾個步驟進(jìn)行:
1、創(chuàng)建一個 RemoteViews 對象,這個對象加載時指定了桌面小部件的界面布局文件。
2、設(shè)置 RemoteViews 創(chuàng)建時加載的布局文件中各個元素的屬性。
3、創(chuàng)建一個 ComponentName 對象
4、調(diào)用 AppWidgetManager 更新桌面小部件。
下面來看一個實際的例子,用 Android Studio 自動生成的例子來說。(注:我用的是最新版的 AS 2.2.3,下面簡稱 AS。)
新建了一個 HelloWorld 項目,然后新建一個 AppWidget ,命名為 MyAppWidgetProvider,按默認(rèn)下一步,就完成了一個最簡單的AppWidget的開發(fā)。運行程序之后,將小部件添加到桌面。操作步驟和默認(rèn)效果如下:
我們看看 AS 為我們自動生成了哪些代碼呢?對照著上面說的的步驟我們來看看。
首先,有一個 MyAppWidgetProvider 的類。
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 } }
該類繼承自 AppWidgetProvider ,AS默認(rèn)幫我們重寫 onUpdate() 方法,遍歷 appWidgetIds, 調(diào)用了 updateAppWidget() 方法。再看 updateAppWidget() 方法,很簡單,只有四行:
第一行,CharSequence widgetText = context.getString(R.string.appwidget_text);聲明了一個字符串;
第二行,RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.my_app_widget_provider);
創(chuàng)建了一個 RemoteViews 對象,第一個參數(shù)傳應(yīng)用程序包名,第二個參數(shù)指定了,RemoteViews 加載的布局文件。這一行對應(yīng)上面步驟中說的第一點??梢钥吹皆?res/layout/ 目錄下面 AS 自動生成了一個 my_app_widget_provider.xml 文件,內(nèi)容如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#09C" android:padding="@dimen/widget_margin"> <TextView android:id="@+id/appwidget_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:layout_margin="8dp" android:background="#09C" android:contentDescription="@string/appwidget_text" android:text="@string/appwidget_text" android:textColor="#ffffff" android:textStyle="bold|italic" /> </RelativeLayout>
這個文件就是我們最后看到的桌面小部件的樣子,布局文件中只有一個TextView。這是你可能會問,想要加圖片可以嗎?可以,就像正常的Activity布局一樣添加 ImageView 就行了,聰明的你可能開始想自定義小部件的樣式了,添加功能強(qiáng)大外觀漂亮逼格高的自定義控件了,很遺憾,不可以。小部件布局文件可以添加的組件是有限制的,詳細(xì)內(nèi)容在下文介紹RemoteViews 時再說。
第三行,views.setTextViewText(R.id.appwidget_text, widgetText);
將第一行聲明的字符串賦值給上面布局文件中的 TextView,注意這里賦值時,指定TextView的 id,要對應(yīng)起來。這一行對于了上面步驟中的第二點。
第四行,appWidgetManager.updateAppWidget(appWidgetId, views);
這里調(diào)用了 appWidgetManager.updateAppWidget() 方法,更新小部件。這一行對應(yīng)了上面步驟中的第四點。
這時,你可能有疑問了,上面明明說了四個步驟,其中第三步,創(chuàng)建一個 ComponentName 對象,明明就不需要。的確,這個例子中也沒有用到。如果我們手敲第四步代碼,AS的智能提示會告訴你,appWidgetManager.updateAppWidget() 有三個重載的方法。源碼中三個方法沒有寫在一起,為了方便,這里我復(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. |
這個三個方法都接收兩個參數(shù),第二個參數(shù)都是 RemoteViews 對象。其中第一個方法的第一個參數(shù)就是 ComponentName 對象,更新所有的 AppWidgetProvider 提供的所有的 AppWidget 實例,第二個方法時更新明確指定 Id 的 AppWidget 的對象集,第三個方法,更新明確指定 Id 的某個 AppWidget 對象。所以一般我們使用第一個方法,針對所有的 AppWidget 對象,我們也可以根據(jù)需要選擇性地去更新。
到這里,所有步驟都結(jié)束了,就完了?還沒。前面說了,自定義的 MyAppWidgetProvider 繼承自 AppWidgetProvider,而 AppWidgetProvider 又是繼承自 BroadCastReceiver,
所以說 MyAppWidgetProvider 本質(zhì)上是一個廣播接受者,屬于四大組件之一,需要我們的清單文件中注冊。打開AndroidManifest.xml文件可以看到,的確是注冊了小部件的,內(nèi)容如下:
<receiver android:name=".MyAppWidgetProvider"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/my_app_widget_provider_info" /> </receiver>
上面代碼中有一個 Action,這個 Action 必須要加,且不能更改,屬于系統(tǒng)規(guī)范,是作為小部件的標(biāo)識而存在的。如果不加,這個 Receiver 就不會出現(xiàn)在小部件列表里面。然后看到小部件指定了 @xml/my_app_widget_provider_info 作為meta-data,細(xì)心的你發(fā)現(xiàn)了,在 res/ 目錄下面建立了一個 xml 文件夾,下面新建了一個 my_app_widget_provider_info.xml 文件,內(nèi)容如下:
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialKeyguardLayout="@layout/my_app_widget_provider" android:initialLayout="@layout/my_app_widget_provider" android:minHeight="40dp" android:minWidth="40dp" android:previewImage="@drawable/example_appwidget_preview" android:resizeMode="horizontal|vertical" android:updatePeriodMillis="86400000" android:widgetCategory="home_screen"> </appwidget-provider>
這里配置了一些小部件的基本信息,常用的屬性有 initialLayout 就是小部件的初始化布局, minHeight 定義了小部件的最小高度,previewImage 指定了小部件在小部件列表里的預(yù)覽圖,updatePeriodMillis 指定了小部件更新周期,單位為毫秒。更多屬性,可以查看API文檔。
到這里,上面這個極簡單的小部件開發(fā)過程就真的結(jié)束了。為了開發(fā)出更強(qiáng)大一點小部件,我們還需要進(jìn)一步了解 RemoteViews 和 AppWidgetProvider。
AppWidget的妝容——RemoteViews
下面簡單說說 RemoteViews 相關(guān)的幾個類。
1.1 RemoteViews
RemoteViews,從字面意思理解為它是一個遠(yuǎn)程視圖。是一種遠(yuǎn)程的 View,它在其它進(jìn)程中顯示,卻可以在另一個進(jìn)程中更新。RemoteViews 在Android中的使用場景主要有:自定義通知欄和桌面小部件。
在RemoteViews 的構(gòu)造函數(shù)中,第二個參數(shù)接收一個 layout 文件來確定 RemoteViews 的視圖;然后,我們調(diào)用RemoteViews 中的 set 方法對 layout 中的各個組件進(jìn)行設(shè)置,例如,可以調(diào)用 setTextViewText() 來設(shè)置 TextView 組件的文本。
前面提到,小部件布局文件可以添加的組件是有限制的,它可以支持的 View 類型包括四種布局:FrameLayout、LinearLayout、RelativeLayout、GridLayout 和 13 種View: AnalogClock、Button、Chronometer、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView、AdapterViewFlipper、ViewSub。注意:RemoteViews 也并不支持上述 View 的子類。
RemoteViews 提供了一系列 setXXX() 方法來為小部件的子視圖設(shè)置屬性。具體可以參考 API 文檔。
1.2 RemoteViewsService
RemoteViewsService,是管理RemoteViews的服務(wù)。一般,當(dāng)AppWidget 中包含 GridView、ListView、StackView 等集合視圖時,才需要使用RemoteViewsService來進(jìn)行更新、管理。RemoteViewsService 更新集合視圖的一般步驟是:
(01) 通過 setRemoteAdapter() 方法來設(shè)置 RemoteViews 對應(yīng) RemoteViewsService 。
(02) 之后在 RemoteViewsService 中,實現(xiàn) RemoteViewsFactory 接口。然后,在 RemoteViewsFactory 接口中對集合視圖的各個子項進(jìn)行設(shè)置,例如 ListView 中的每一Item。
1.3 RemoteViewsFactory
通過RemoteViewsService中的介紹,我們知道RemoteViewsService是通過 RemoteViewsFactory來具體管理layout中集合視圖的,RemoteViewsFactory是RemoteViewsService中的一個內(nèi)部接口。RemoteViewsFactory提供了一系列的方法管理集合視圖中的每一項。例如:
RemoteViews getViewAt(int position)
通過getViewAt()來獲取“集合視圖”中的第position項的視圖,視圖是以RemoteViews的對象返回的。
int getCount()
通過getCount()來獲取“集合視圖”中所有子項的總數(shù)。
AppWidget的美貌——AppWidgetProvider
我們說一位女同事漂亮,除了因為她穿的衣服、化的妝漂亮以外,我想最主要的原因還是她本人長的漂亮吧。同樣,小部件之所以有附著在桌面,跨進(jìn)程更新 View 的能力,主要是因為AppWidgetProvider 是一個廣播接收者。
我們發(fā)現(xiàn),上面的例子中,AS 幫我們自動生成的代碼中,除了 onUpdate() 方法被我們重寫了,還有重寫 onEnable() 和 onDisable() 兩個方法,但都是空實現(xiàn),這兩個方法什么時候會被調(diào)用?還有,我們說自定義的 MyAppWidgetProvider,繼承自 AppWidgetProvider,而 MyAppWidgetProvider 又是BroadCastReceiver 的子類,而我們卻沒有向?qū)懗R?guī)廣播接收者一樣重寫 onReceiver() 方法?下面跟進(jìn)去 AppWidgetProvider 源碼,一探究竟。
這個類代碼并不多,其實,AppWidgetProvider 出去構(gòu)造方法外,總共只有下面這些方法:
onEnable() :當(dāng)小部件第一次被添加到桌面時回調(diào)該方法,可添加多次,但只在第一次調(diào)用。對用廣播的 Action 為 ACTION_APPWIDGET_ENABLE。
onUpdate(): 當(dāng)小部件被添加時或者每次小部件更新時都會調(diào)用一次該方法,配置文件中配置小部件的更新周期 updatePeriodMillis,每次更新都會調(diào)用。對應(yīng)廣播 Action 為:ACTION_APPWIDGET_UPDATE 和 ACTION_APPWIDGET_RESTORED 。
onDisabled(): 當(dāng)最后一個該類型的小部件從桌面移除時調(diào)用,對應(yīng)的廣播的 Action 為 ACTION_APPWIDGET_DISABLED。
onDeleted(): 每刪除一個小部件就調(diào)用一次。對應(yīng)的廣播的 Action 為: ACTION_APPWIDGET_DELETED 。
onRestored(): 當(dāng)小部件從備份中還原,或者恢復(fù)設(shè)置的時候,會調(diào)用,實際用的比較少。對應(yīng)廣播的 Action 為 ACTION_APPWIDGET_RESTORED。
onAppWidgetOptionsChanged(): 當(dāng)小部件布局發(fā)生更改的時候調(diào)用。對應(yīng)廣播的 Action 為 ACTION_APPWIDGET_OPTIONS_CHANGED。
最后就是 onReceive() 方法了,AppWidgetProvider 重寫了該方法,用于分發(fā)具體的時間給上述的方法??纯丛创a:
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í)
下面再自己寫個例子,學(xué)習(xí) RemoteViews 中的其它知識點,這個例子中小部件布局中用到 button 和 listview。上代碼:
小部件的布局文件 mul_app_widget_provider.xml 如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="100dp" android:layout_height="200dp" android:orientation="vertical"> <ImageView android:id="@+id/iv_test" android:layout_width="match_parent" android:layout_height="100dp" android:src="@mipmap/ic_launcher"/> <Button android:id="@+id/btn_test" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="點擊跳轉(zhuǎn)"/> </LinearLayout> <TextView android:layout_width="1dp" android:layout_height="200dp" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:background="#f00"/> <ListView android:id="@+id/lv_test" android:layout_width="100dp" android:layout_height="200dp"> </ListView> </LinearLayout>
小部件的配置信息 mul_app_widget_provider_info.xml 如下:
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialLayout="@layout/mul_app_widget_provider" android:minHeight="200dp" android:minWidth="200dp" android:previewImage="@mipmap/a1" android:updatePeriodMillis="86400000"> </appwidget-provider>
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, "點擊跳轉(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: 對應(yīng)啟動 ListViewService(RemoteViewsService) 的intent // (02) setRemoteAdapter: 設(shè)置 ListView 的適配器 // 通過setRemoteAdapter將 ListView 和ListViewService關(guān)聯(lián)起來, // 以達(dá)到通過 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模板 // 說明:“集合控件(如GridView、ListView、StackView等)”中包含很多子元素,如GridView包含很多格子。 // 它們不能像普通的按鈕一樣通過 setOnClickPendingIntent 設(shè)置點擊事件,必須先通過兩步。 // (01) 通過 setPendingIntentTemplate 設(shè)置 “intent模板”,這是比不可少的! // (02) 然后在處理該“集合控件”的RemoteViewsFactory類的getViewAt()接口中 通過 setOnClickFillInIntent 設(shè)置“集合控件的某一項的數(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); } }
下面重點是 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 List<String> mList = 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; } /* 在更新界面的時候如果耗時就會顯示 正在加載... 的默認(rèn)字樣,但是你可以更改這個界面 * 如果返回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"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.joy.remoteviewstest"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".MulAppWidgetProvider" android:label="@string/app_name"> <intent-filter> <action android:name="com.example.joy.action.CHANGE_IMAGE"/> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/mul_app_widget_provider_info"> </meta-data> </receiver> <service android:name=".ListViewService" android:permission="android.permission.BIND_REMOTEVIEWS" android:exported="false" android:enabled="true"/> </application> </manifest>
這個小部件添加到桌面后有一個 ImageView 顯示小機(jī)器人,下面有一個 Button ,右邊有一個ListView。
這里主要看看,Button 和 ListView 在 RemoteViews中如何使用。、
Button 設(shè)置 Text 和 TextView 一樣,因為 Button 本身繼承自 TextView,Button 設(shè)置點擊事件如下:
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 , 與通知中的用法一樣。這里點擊之后跳轉(zhuǎn)到了 MainActivity。
關(guān)于 ListView 的用法就復(fù)雜一些了。首先需要自定義一個類繼承自 RemoteViewsServices ,并重寫 onGetViewFactory 方法,返回 RemoteViewsService.RemoteViewsFactory 接口的對象。這里定義了一個內(nèi)部類實現(xiàn)該接口,需要重寫多個方法,與 ListView 的多布局適配很類似。重點方法是
public RemoteViews getViewAt(int position){}
這個方法中指定了 ListView 的每一個 item 的布局以及內(nèi)容,同時通過 setOnClickFillInIntent() 或者 setOnClickPendingIntent() 給 item 設(shè)置點擊事件。這里我實現(xiàn)的點擊 item,替換左邊的 ImageView 的圖片。重寫了 MulAppWidgetProvider 類的 onReceiver 方法,處理替換圖片的邏輯。
程序運行效果如下圖:
上述就是小編為大家分享的AppWidget如何在Android開發(fā)中使用了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。