Widget开发中遇到的坑
1.在Manifest文件中聲明
<receiver android:name=".receiver.GoldWidgetProvider"><intent-filter><action android:name="android.appwidget.action.APPWIDGET_UPDATE" /><action android:name="com.fuqi.gold.action_updatewidget" /><action android:name="com.fuqi.gold.action_click_updatewidget" /><action android:name="com.fuqi.gold.action_to_buygold" /></intent-filter><meta-dataandroid:name="android.appwidget.provider"android:resource="@xml/goldwidget_provider_info" /> </receiver>這個(gè)就相當(dāng)于一個(gè)廣播接收者,然后android:name屬性指定在第四步的時(shí)候創(chuàng)建的文件名
android:resource="@xml/example_appwidget_info"/>是widget的配置文件
2.添加Widget配置信息
在項(xiàng)目的 res/xml/ 目錄下。如果沒有xml目錄,需要新建一個(gè)
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"android:minWidth="40dp"android:minHeight="40dp"android:updatePeriodMillis="86400000"android:previewImage="@drawable/preview"android:initialLayout="@layout/example_appwidget"android:resizeMode="horizontal|vertical"android:widgetCategory="home_screen"> </appwidget-provider>initialLayout是widget的布局文件
previewImage就是widget的預(yù)覽效果
3.新建一個(gè)appwidget_layout文件
<FrameLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:padding="@dimen/widget_margin"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"android:background="@drawable/my_widget_background">…</LinearLayout></FrameLayout>4.新建一個(gè)AppWidgetProvider類
這個(gè)類其實(shí)是繼承至廣播接收者的
public class AppWidgetProvider extends BroadcastReceiver {然后呢,我們一般只需要用到onUpdate()方法,這個(gè)方法的更新時(shí)間,是你在example_appwidget_info配置文件中設(shè)置的android:updatePeriodMillis屬性決定的,這個(gè)地方有個(gè)坑,稍候再說
public class GoldWidgetProvider extends AppWidgetProvider {public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {final int N = appWidgetIds.length;for (int i=0; i<N; i++) {int appWidgetId = appWidgetIds[i];Intent intent = new Intent(context, ExampleActivity.class);PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);views.setOnClickPendingIntent(R.id.button, pendingIntent);widgetappWidgetManager.updateAppWidget(appWidgetId, views);}} }5.開發(fā)中的一些坑
1. updateMillies更新時(shí)間低于30分鐘,系統(tǒng)默認(rèn)為30分鐘。如果想要自己更新widget,將這個(gè)值設(shè)置為0,然后自己開timer或者通過廣播去更新。我是通過廣播去更新的
// 重寫OnReceiver方法@Overridepublic void onReceive(Context context, Intent intent) {super.onReceive(context, intent);String action = intent.getAction();// 需要在Manifest中注冊這個(gè)Actionif (ACTION_UPDATE_WIDGET.equals(action)) { // update widgetRemoteViews views = getRemoteViews(context, null);ComponentName name = new ComponentName(context, GoldWidgetProvider.class);AppWidgetManager.getInstance(context).updateAppWidget(name, views);}else if (ACTION_CLICK_UPDATE_WIDGET.equals(action)){RemoteViews remoteViews = getRemoteViews(context, "正在刷新...");ComponentName name = new ComponentName(context, GoldWidgetProvider.class);AppWidgetManager.getInstance(context).updateAppWidget(name, remoteViews);Intent goldPrice = new Intent(context, GoldPriceService.class);context.startService(goldPrice);} }public static RemoteViews getRemoteViews(Context context, String updating) {RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.goldwidget);//1,設(shè)置金價(jià)if (TextUtils.isEmpty(updating)) {String buyGoldPrice = ShaPreUtils.getBuyGoldPrice(context);views.setTextViewText(R.id.widget_tv_goldprice, buyGoldPrice);} else {views.setTextViewText(R.id.widget_tv_goldprice, updating);}//2,設(shè)置持有金if (GoldApplication.getInstance().isLogined()) {String total = GoldApplication.getInstance().getUserLoginInfo().getAccountInfo().getTotal();ShaPreUtils.putTotalGold(context,total);views.setTextViewText(R.id.widget_tv_total, total);views.setViewVisibility(R.id.widget_total_layout,View.VISIBLE);}else if (TextUtils.isEmpty(ShaPreUtils.getTotalGold(context))){views.setViewVisibility(R.id.widget_total_layout,View.GONE);}else{views.setViewVisibility(R.id.widget_total_layout,View.VISIBLE);views.setTextViewText(R.id.widget_tv_total,ShaPreUtils.getTotalGold(context));}//3,點(diǎn)擊事件Intent toStartActivity = new Intent(context, AppStart.class);views.setOnClickPendingIntent(R.id.widget_to_app, PendingIntent.getActivity(context, 0, toStartActivity, 0));// 買金的時(shí)候發(fā)送一個(gè)廣播,當(dāng)前類接收Intent to_buygold = new Intent(context, GoldWidgetProvider.class);to_buygold.setAction(ACTION_TO_BUYGOLD);views.setOnClickPendingIntent(R.id.widget_to_buygold, PendingIntent.getBroadcast(context, 0,to_buygold , 0));// 主動(dòng)刷新廣播Intent layout = new Intent(context, GoldWidgetProvider.class);layout.setAction(ACTION_CLICK_UPDATE_WIDGET);views.setOnClickPendingIntent(R.id.widget_layout, PendingIntent.getBroadcast(context, 0, layout, 0));return views;}2.appwidget_info里的android:configure屬性
一開始的時(shí)候照著官方文檔在appwidget_info xml文件里設(shè)置了這個(gè)屬性,在添加到桌面上的時(shí)候總是不成功,將這個(gè)屬性去掉就可以了,不知道這個(gè)屬性具體怎么用,有知道的麻煩告訴我一聲,感激不盡...
查看官方文檔法相這個(gè)屬性是給widget設(shè)置一個(gè)config,具體怎么使用可以查看官方文檔
3.appWidgetManager更新的兩個(gè)方法
updateAppWidget(int[] appWidgetIds, RemoteViews views)
updateAppWidget(ComponentName provider, RemoteViews views) {
updateAppWidget(int[] appWidgetIds, RemoteViews views)代碼如下:
// 更新 widget 的廣播對應(yīng)的actionprivate final String ACTION_UPDATE_ALL = "com.skywang.widget.UPDATE_ALL";// 保存 widget 的id的HashSet,每新建一個(gè) widget 都會(huì)為該 widget 分配一個(gè) id。private static Set idsSet = new HashSet();@Overridepublic void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {Log.d(TAG, "onUpdate(): appWidgetIds.length="+appWidgetIds.length);// 每次 widget 被創(chuàng)建時(shí),對應(yīng)的將widget的id添加到set中for (int appWidgetId : appWidgetIds) {idsSet.add(Integer.valueOf(appWidgetId));} } @Override public void onDeleted(Context context, int[] appWidgetIds) { Log.d(TAG, "onDeleted(): appWidgetIds.length="+appWidgetIds.length);// 當(dāng) widget 被刪除時(shí),對應(yīng)的刪除set中保存的widget的idfor (int appWidgetId : appWidgetIds) {idsSet.remove(Integer.valueOf(appWidgetId));} super.onDeleted(context, appWidgetIds); }//接收廣播的回調(diào)函數(shù)@Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (ACTION_UPDATE_ALL.equals(action)) {// “更新”廣播updateAllAppWidgets(context, AppWidgetManager.getInstance(context), idsSet);} } // 更新所有的 widget private void updateAllAppWidgets(Context context, AppWidgetManager appWidgetManager, Set set) {Log.d(TAG, "updateAllAppWidgets(): size="+set.size());// widget 的idint appID;// 迭代器,用于遍歷所有保存的widget的idIterator it = set.iterator();while (it.hasNext()) {appID = ((Integer)it.next()).intValue(); if (DEBUG) Log.d(TAG, "onUpdate(): index="+index); // 獲取 example_appwidget.xml 對應(yīng)的RemoteViews RemoteViews remoteView = getRemoteViews(context,"");// 更新 widgetappWidgetManager.updateAppWidget(appID, remoteView); } }上面這些代碼有個(gè)隱患,在應(yīng)用退出后,或是被第三方軟件殺死,點(diǎn)擊桌面widget就不會(huì)更新了。原因是updateid我是用static的set集合保存的,應(yīng)用退出后,這個(gè)set集合就被清空了,后面又換成了updateAppWidget(ComponentName)方法后就好了。
RemoteViews views = getRemoteViews(context, null); ComponentName name = new ComponentName(context, GoldWidgetProvider.class); AppWidgetManager.getInstance(context).updateAppWidget(name, views);4.在用setOnClickPendingIntent()方法設(shè)置點(diǎn)擊事件發(fā)送Broadcast時(shí),不能直接new Intent(acton)
Intent intent = new Intent(ACTION_CLICK_UPDATE_WIDGET); views.setOnClickPendingIntent(R.id.widget_layout, PendingIntent.getBroadcast(context, 0, intent, 0));上面這種寫法在應(yīng)用退出后在有些手機(jī)上收不到廣播,然后換成下面這種寫法
Intent layout = new Intent(context, GoldWidgetProvider.class); layout.setAction(ACTION_CLICK_UPDATE_WIDGET); views.setOnClickPendingIntent(R.id.widget_layout, PendingIntent.getBroadcast(context, 0, layout, 0));總結(jié)
以上是生活随笔為你收集整理的Widget开发中遇到的坑的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 柯里化的前生今世(四):编译器与解释器
- 下一篇: css样式表中的样式覆盖顺序(转)