作者:徐建祥(netpirate@gmail.com)
时间: 2010/12/15
来自: http://www.anymobile.org
Widget杂谈:最早Widget是指在PC的桌面上的小窗口程序;Web上的先行者似乎是Yahoo!;当然,OPhone也搞了一套Widget,HTML+CSS的东东。
我们这里谈的所谓Widget,就是窗口小部件,Android SDK从1.5版本开始支持AppWidget framework,返个框架允许开发者开发Widgets,这些Widgets可以被用户通过长按桌面进行添加,与应用程序进行数据交互。
需求:
在桌面上开发一个Widget,可以实时显示IM软件的状态更新变化;可以通过左右按钮,查看上次或下调更新内容。
(参考效果图)
设计思路:
(参考设计序列图)
代码:
Java:
/src/org.anymobile.demo.Globals \\Intent.action 声明
/src/org.anymobile.demo.service.UpdateService extends Service \\同步、更新Widget布局数据的Service
/src/org.anymobile.demo.widget.UpdateAppWidgetProvider extends AppWidgetProvider \\Widget,接收器
XML:
/res/layout/update_appwidget.xml \\布局设计
/res/values/strings.xml \\常量声明
/res/xml/update_appwidget_info.xml \\app widget定义
AndroidManifest.xml
#AndroidManifest.xml
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.anymobile.demo"
- android:versionCode="1"
- android:versionName="1.0">
- <application android:icon="@drawable/icon" android:label="@string/app_name">
-
- <receiver android:name=".widget.UpdateAppWidgetProvider"
- android:label="@string/app_widget_label" >
- <intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
- </intent-filter>
- <meta-data android:name="android.appwidget.provider"
- android:resource="@xml/update_appwidget_info" />
- </receiver>
-
- <service android:name=".service.UpdateService" android:label="@string/app_name">
- <intent-filter>
- <action android:name="org.anymobile.demo.service.IMM_UPDATE_SERVICE" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </service>
- </application>
- </manifest>
#strings.xml
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <string name="app_name">AnymobileDemo</string>
-
- <string name="app_widget_label">AnymobileDemo Widget</string>
- <string name="app_widget_title">Updates</string>
- <string name="app_widget_error_message">No messages, please check to login.</string>
-
- </resources>
#update_appwidget_info.xml
- <?xml version="1.0" encoding="utf-8"?>
- <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
- android:minWidth="294dip"
- android:minHeight="120dip"
- android:updatePeriodMillis="0"
- android:initialLayout="@layout/update_appwidget">
- </appwidget-provider>
#update_appwidget.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <LinearLayout
- android:id="@+id/app_widget_top"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- android:background="@drawable/widget_titlebar"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/app_widget_body"
- android:orientation="horizontal"
- android:background="@drawable/widget_body"
- android:layout_width="fill_parent"
- android:layout_height="100dip">
- <LinearLayout
- android:id="@+id/app_widget_message"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <TextView
- android:id="@+id/widget_message"
- android:text="@string/app_widget_error_message"
- android:paddingRight="5dip"
- android:paddingLeft="5dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- </TextView>
- </LinearLayout>
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/app_widget_bottom"
- android:gravity="right"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- </LinearLayout>
- </LinearLayout>
#Globals.java
- package org.anymobile.demo;
- public final class Globals
- {
- public static final String ACTION_APP_WIDGET_SERVICE= "org.anymobile.demo.service.IMM_UPDATE_SERVICE";
-
- public static final String ACTION_APP_WIDGET_PREV = "org.anymobile.demo.intent.action.APP_WIDGET_PREV";
- public static final String ACTION_APP_WIDGET_NEXT = "org.anymobile.demo.intent.action.APP_WIDGET_NEXT";
-
- public static final String ACTION_APP_WIDGET_RELOAD = "org.anymobile.demo.intent.action.APP_WIDGET_RELOAD";
-
- }
#UpdateService.java
- package org.anymobile.demo.service;
-
- import java.util.ArrayList;
- import android.app.Service;
- import android.appwidget.AppWidgetManager;
- import android.content.BroadcastReceiver;
- import android.content.ComponentName;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- import android.os.IBinder;
- import android.util.Log;
- import android.view.View;
- import android.widget.RemoteViews;
- import org.anymobile.demo.Globals;
- import org.anymobile.demo.R;
- import org.anymobile.demo.widget.UpdateAppWidgetProvider;
-
- public class UpdateService extends Service
- {
- public static final String TAG = "ANYMOBILE-DEMO--UpdateService";
-
- private ArrayList<String> mList;
- private int mCount;
- private int mId;
-
- private BroadcastReceiver mIntentReceiver = new BroadcastReceiver()
- {
- @Override
- public void onReceive(Context context, Intent intent)
- {
- String action = intent.getAction();
- Log.d(TAG, "onReceive() " + action);
-
- if (action.equals(Globals.ACTION_APP_WIDGET_RELOAD))
- {
- doReload();
- }
- }
- };
- @Override
- public void onCreate()
- {
- Log.d(TAG, "onCreate()");
- super.onCreate();
-
- reloadQueue();
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(Globals.ACTION_APP_WIDGET_RELOAD);
- registerReceiver(mIntentReceiver, filter);
- }
-
- @Override
- public void onStart(Intent intent, int startId)
- {
- super.onStart(intent, startId);
- String action = intent.getAction();
- Log.d(TAG, "onStart() " + action);
- if (action.equals(Globals.ACTION_APP_WIDGET_PREV))
- {
- doPrev();
- }
- else if (action.equals(Globals.ACTION_APP_WIDGET_NEXT))
- {
- doNext();
- }
- else
- {
- notifyWidget();
- }
- }
-
- private void notifyWidget()
- {
- Log.d(TAG, "notifyWidget()");
-
- ComponentName widget = new ComponentName(this, UpdateAppWidgetProvider.class);
- RemoteViews updateViews = buildUpdate(this);
-
- AppWidgetManager manager = AppWidgetManager.getInstance(this);
- manager.updateAppWidget(widget, updateViews);
- }
- @Override
- public void onDestroy()
- {
- Log.d(TAG, "onDestroy()");
-
- unregisterReceiver(mIntentReceiver);
-
- super.onDestroy();
- }
- @Override
- public IBinder onBind(Intent intent)
- {
- Log.d(TAG, "onBind()");
- return null;
- }
-
- private RemoteViews buildUpdate(Context context)
- {
- RemoteViews updateViews =
- new RemoteViews(context.getPackageName(), R.layout.update_appwidget);
- String item = null;
-
- if (mCount > 0)
- {
- item = mList.get(mId);
- if (item != null)
- {
- updateViews.setViewVisibility(R.id.app_widget_content, View.GONE);
- updateViews.setViewVisibility(R.id.app_widget_message, View.VISIBLE);
-
-
-
-
-
-
-
-
-
- updateViews.setTextViewText(R.id.widget_message, item);
- }
- }
- if (item == null)
- {
- updateViews.setViewVisibility(R.id.app_widget_content, View.GONE);
- updateViews.setViewVisibility(R.id.app_widget_message, View.VISIBLE);
-
- updateViews.setTextViewText(R.id.widget_message,
- context.getText(R.string.app_widget_error_message));
- }
- Log.d(TAG, "buildUpdate: layoutId = " + updateViews.getLayoutId() +
- "; count = " + mCount + "; id = " + mId);
-
- return updateViews;
- }
-
- private void doReload()
- {
- Log.d(TAG, "doReload()");
- reloadQueue();
-
- notifyWidget();
- }
-
- private void reloadQueue()
- {
- mList = new ArrayList<String>();
- String[] arr = {"aa", "bb", "cc", "dd"};
- for (int i = 0; i < arr.length; i++)
- {
- mList.add(arr[i]);
- }
-
- if (mList != null)
- {
- mCount = mList.size();
- }
- else
- {
- mCount = 0;
- }
- mId = 0;
-
-
- }
-
- private void doPrev()
- {
- Log.d(TAG, "doPrev()");
- mId -= 1;
- if (mId < 0)
- {
- mId = mCount - 1;
- }
- notifyWidget();
- }
-
- private void doNext()
- {
- Log.d(TAG, "doNext()");
- mId += 1;
- if (mId > mCount - 1)
- {
- mId = 0;
- }
- notifyWidget();
- }
- }
#UpdateAppWidgetProvider.java
- package org.anymobile.demo.widget;
-
- 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.util.Log;
- import android.view.View;
- import android.widget.RemoteViews;
- import org.anymobile.demo.Globals;
- import org.anymobile.demo.R;
- import org.anymobile.demo.service.UpdateService;
- public class UpdateAppWidgetProvider extends AppWidgetProvider
- {
- public static final String TAG = "ANYMOBILE-DEMO-UpdateAppWidgetProvider";
-
- public static final String APP_WIDGET_UPDATE = "appwidgetupdate";
- public static final ComponentName APPWIDGET_COMPONENT_NAME =
- new ComponentName("org.anymobile.demo",
- "org.anymobile.demo.widget.UpdateAppWidgetProvider");
- @Override
- public void onReceive(Context context, Intent intent)
- {
- Log.d(TAG, "onReceive() " + intent.getAction());
- super.onReceive(context, intent);
- }
- @Override
- public void onEnabled(Context context)
- {
- Log.d(TAG, "onEnabled()");
- super.onEnabled(context);
- }
- @Override
- public void onDisabled(Context context)
- {
- Log.d(TAG, "onDisabled()");
- super.onDisabled(context);
- }
- @Override
- public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
- {
- Log.d(TAG, "onUpdate()");
-
- defaultAppWidget(context, appWidgetIds);
-
- context.startService(new Intent(Globals.ACTION_APP_WIDGET_SERVICE));
- }
-
- private void defaultAppWidget(Context context, int[] appWidgetIds)
- {
- final RemoteViews views =
- new RemoteViews(context.getPackageName(), R.layout.update_appwidget);
-
- views.setViewVisibility(R.id.app_widget_content, View.GONE);
- views.setViewVisibility(R.id.app_widget_message, View.VISIBLE);
-
-
- linkButtons(context, views);
-
- pushUpdate(context, appWidgetIds, views);
- }
-
- private void linkButtons(Context context, RemoteViews views)
- {
- Intent intent;
- PendingIntent pendingIntent;
- final ComponentName serviceName = new ComponentName(context, UpdateService.class);
-
- intent = new Intent(Globals.ACTION_APP_WIDGET_PREV);
- intent.setComponent(serviceName);
- pendingIntent = PendingIntent.getService(context,
- 0 , intent, 0 );
- views.setOnClickPendingIntent(R.id.widget_btn_prev_page, pendingIntent);
- intent = new Intent(Globals.ACTION_APP_WIDGET_NEXT);
- intent.setComponent(serviceName);
- pendingIntent = PendingIntent.getService(context,
- 0 , intent, 0 );
- views.setOnClickPendingIntent(R.id.widget_btn_next_page, pendingIntent);
- }
-
- private void pushUpdate(Context context, int[] appWidgetIds, RemoteViews views)
- {
- final AppWidgetManager gm = AppWidgetManager.getInstance(context);
- if (appWidgetIds != null)
- {
- gm.updateAppWidget(appWidgetIds, views);
- }
- else
- {
- gm.updateAppWidget(APPWIDGET_COMPONENT_NAME, views);
- }
- }
-
- void notifyChange(UpdateService service, String what)
- {
-
- }
- }
日志:
#init
12-15 19:23:09.479 D/ANYMOBILE-DEMO--UpdateAppWidgetProvider( 585): onReceive() android.appwidget.action.APPWIDGET_UPDATE
12-15 19:23:09.509 D/ANYMOBILE-DEMO--UpdateAppWidgetProvider( 585): onUpdate()
12-15 19:23:09.549 D/ANYMOBILE-DEMO--UpdateService( 585): onCreate()
12-15 19:23:09.579 D/ANYMOBILE-DEMO--UpdateService( 585): onStart()
#add widget
12-15 19:24:23.780 D/ANYMOBILE-DEMO--UpdateAppWidgetProvider( 585): onReceive() android.appwidget.action.APPWIDGET_UPDATE
12-15 19:24:23.780 D/ANYMOBILE-DEMO--UpdateAppWidgetProvider( 585): onUpdate()
12-15 19:24:23.850 D/ANYMOBILE-DEMO--UpdateService( 585): onStart()
#receive software event, reload and update widget
12-15 19:24:58.150 D/ANYMOBILE-DEMO--UpdateService( 585): onReceive() Activation
12-15 19:24:58.150 D/ANYMOBILE-DEMO--UpdateService( 585): doReload()
12-15 19:24:58.150 D/ANYMOBILE-DEMO--UpdateService( 585): notifyWidget()
12-15 19:24:58.200 D/ANYMOBILE-DEMO--UpdateService( 585): buildUpdate: layoutId = 2130903068; count = 11; id = 0
#click widget button, new start the bind service
12-15 19:25:49.260 D/ANYMOBILE-DEMO--UpdateService( 585): onStart()
12-15 19:24:58.150 D/ANYMOBILE-DEMO--UpdateService( 585): notifyWidget()
12-15 19:24:58.200 D/ANYMOBILE-DEMO--UpdateService( 585): buildUpdate: layoutId = 2130903068; count = 11; id = 0
OVER!
参考:
com.android.music/.MediaAppWidgetProvider
com.android.music/.MediaPlaybackService
posted on 2010-12-15 21:44
Xu Jianxiang 阅读(891)
评论(0) 编辑 收藏 所属分类:
Android