In the Android 2.2 SDK, we can start the emulator the first time, you can see not the same is more of a small green robot tips, Google Android demonstrated to us how the picture through the RemoteView and simple way of rotation achieve animation effects on the desktop gadget, appWidget AppWidgetProvider class base class, but the Widget itself is not life-cycle management Activity, relative to the treatment but BroadcastReceiver broadcast, Android 2.2 Implementation of the new Widget that we can learn from a lot of useful knowledge.
public class ProtipWidget extends AppWidgetProvider {
public static final String ACTION_NEXT_TIP = "com.android.misterwidget.NEXT_TIP"; / / definition of a prompt action to switch to the next
public static final String ACTION_POKE = "com.android.misterwidget.HEE_HEE"; / / wake up little robot
public static final String EXTRA_TIMES = "times";
public static final String PREFS_NAME = "Protips";
public static final String PREFS_TIP_NUMBER = "widget_tip";
private static Random sRNG = new Random (); / / rotate images used to generate a static random number generator
private static final Pattern sNewlineRegex = Pattern.compile ("* \ \ n *");
Private static Final Pattern sDrawableRegex = Pattern.compile (" * @ (Drawable / [a-Z0-9 _] +) * ");
/ / Initialization Droid is the eyes do not open, and there is no message alert
private int mIconRes = R.drawable.droidman_open;
private int mMessage = 0;
private AppWidgetManager mWidgetManager = null;
private int [] mWidgetIds;
private Context mContext;
private CharSequence [] mTips;
private void setup (Context context) {
mContext = context;
mWidgetManager = AppWidgetManager.getInstance (context);
mWidgetIds = mWidgetManager.getAppWidgetIds (new ComponentName (context, ProtipWidget.class));
SharedPreferences pref = context.getSharedPreferences (PREFS_NAME, 0);
mMessage = pref.getInt (PREFS_TIP_NUMBER, 0);
mTips = context.getResources (). getTextArray (R.array.tips);
if (mTips! = null) {
if (mMessage> = mTips.length) mMessage = 0;
} Else {
mMessage = -1;
}
}
public void goodmorning () {/ / Android Developer Network tips thread rotate pictures, use the 500,200,100 0.5 seconds so that sleep, sleep 0.2 seconds interval to achieve the animation effect
mMessage = -1;
try {
setIcon (R.drawable.droidman_down_closed);
Thread.sleep (500);
setIcon (R.drawable.droidman_down_open);
Thread.sleep (200);
setIcon (R.drawable.droidman_down_closed);
Thread.sleep (100);
setIcon (R.drawable.droidman_down_open);
Thread.sleep (600);
} Catch (InterruptedException ex) {
}
mMessage = 0;
mIconRes = R.drawable.droidman_open;
refresh ();
}
@ Override
public void onReceive (Context context, Intent intent) {/ / The above android123 has been talked about, appWidget is based on the broadcastreceiver class, so that the necessary action to respond to onReceive driven by events.
setup (context);
if (intent.getAction (). equals (ACTION_NEXT_TIP)) {
mMessage = getNextMessageIndex ();
SharedPreferences.Editor pref = context.getSharedPreferences (PREFS_NAME, 0). Edit ();
pref.putInt (PREFS_TIP_NUMBER, mMessage);
pref.commit ();
refresh ();
} Else if (intent.getAction (). Equals (ACTION_POKE)) {
blink (intent.getIntExtra (EXTRA_TIMES, 1));
} Else if (intent.getAction (). Equals (AppWidgetManager.ACTION_APPWIDGET_ENABLED)) {
goodmorning ();
} Else {
mIconRes = R.drawable.droidman_open;
refresh ();
}
}
private void refresh () {/ / If there are multiple management need to individually update the implementation of the widget
RemoteViews rv = buildUpdate (mContext);
for (int i: mWidgetIds) {
mWidgetManager.updateAppWidget (i, rv);
}
}
private void setIcon (int resId) {
mIconRes = resId;
refresh ();
}
private int getNextMessageIndex () {
return (mMessage + 1)% mTips.length;
}
private void blink (int blinks) {
if (mMessage <0) return;
/ / Android123 prompted more interesting is that all little green men eyes opening and closing, here is an image rotation method used to achieve animation effects, we can use in appWidget very little control
setIcon (R.drawable.droidman_closed);
try {
Thread.sleep (100);
while (0 <- blinks) {
setIcon (R.drawable.droidman_open);
Thread.sleep (200);
setIcon (R.drawable.droidman_closed);
Thread.sleep (100);
}
} Catch (InterruptedException ex) {}
setIcon (R.drawable.droidman_open);
}
public RemoteViews buildUpdate (Context context) {
RemoteViews updateViews = new RemoteViews (
context.getPackageName (), R.layout.widget); / / map layout, widget.xml source file can be found in the following
/ / Click events bubble, corresponding to action_next_tip action
Intent bcast = new Intent (context, ProtipWidget.class);
bcast.setAction (ACTION_NEXT_TIP);
PendingIntent pending = PendingIntent.getBroadcast (
context, 0, bcast, PendingIntent.FLAG_UPDATE_CURRENT);
updateViews.setOnClickPendingIntent (R.id.tip_bubble, pending);
/ / Here for action_poke
bcast = new Intent (context, ProtipWidget.class);
bcast.setAction (ACTION_POKE);
bcast.putExtra (EXTRA_TIMES, 1);
pending = PendingIntent.getBroadcast (
context, 0, bcast, PendingIntent.FLAG_UPDATE_CURRENT);
updateViews.setOnClickPendingIntent (R.id.bugdroid, pending);
/ / Tip bubble text
if (mMessage> = 0) {
String [] parts = sNewlineRegex.split (mTips [mMessage], 2);
String title = parts [0];
String text = parts.length> 1? Parts [1]: "";
/ / Look for a callout graphic referenced in the text
Matcher m = sDrawableRegex.matcher (text);
if (m.find ()) {
String imageName = m.group (1);
int resId = context.getResources (). getIdentifier (
imageName, null, context.getPackageName ());
updateViews.setImageViewResource (R.id.tip_callout, resId);
updateViews.setViewVisibility (R.id.tip_callout, View.VISIBLE);
text = m.replaceFirst ("");
} Else {
updateViews.setImageViewResource (R.id.tip_callout, 0);
updateViews.setViewVisibility (R.id.tip_callout, View.GONE);
}
updateViews.setTextViewText (R.id.tip_message,
text);
updateViews.setTextViewText (R.id.tip_header,
title);
updateViews.setTextViewText (R.id.tip_footer,
context.getResources (). getString (
R.string.pager_footer,
(1 + mMessage), mTips.length));
updateViews.setViewVisibility (R.id.tip_bubble, View.VISIBLE);
} Else {
updateViews.setViewVisibility (R.id.tip_bubble, View.INVISIBLE);
}
updateViews.setImageViewResource (R.id.bugdroid, mIconRes);
return updateViews;
}
}
For the detailed recevier AndroidManifest.xml code below
<receiver android:name=".ProtipWidget" android:label="@string/widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.android.protips.NEXT_TIP" />
<action android:name="com.android.protips.HEE_HEE" />
</ Intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_build" />
</ Receiver>
For res / xml / widget_build.xml the code below
<Appwidget-Provider xmlns: Android = " http://schemas.android.com/apk/res/android "
android: minWidth = "294dip"
android: minHeight = "72dip"
android: updatePeriodMillis = "0"
android: initialLayout = "@ layout / widget" />
For res / layout / widget.xml the code below, note the following layout file using the include way nested
<RelativeLayout xmlns: Android = " http://schemas.android.com/apk/res/android "
android: id = "@ + id / widget"
android: layout_width = "fill_parent"
android: layout_height = "wrap_content"
android: orientation = "vertical"
android: padding = "5dip"
>
<include layout="@layout/droid" />
<include layout="@layout/bubble" />
</ RelativeLayout>
For res / layout / droid.xml the code below
<ImageView xmlns: Android = " http://schemas.android.com/apk/res/android "
android: id = "@ + id / bugdroid"
android: src = "@ drawable / droidman_down_closed"
android: scaleType = "center"
android: layout_width = "wrap_content"
android: layout_height = "wrap_content"
android: layout_alignParentRight = "true"
android: layout_centerVertical = "true"
/>
For res / layout / bubble.xml the code below
<RelativeLayout xmlns: Android = " http://schemas.android.com/apk/res/android "
android: id = "@ + id / tip_bubble"
android: layout_width = "fill_parent"
android: layout_height = "wrap_content"
android: layout_toLeftOf = "@ + id / bugdroid"
android: layout_centerVertical = "true"
android: gravity = "center_vertical | left"
android: layout_marginRight = "2dip"
android: visibility = "invisible"
android: background = "@ drawable / droid_widget"
android: focusable = "true"
>
<TextView
android: layout_width = "0dip"
android: layout_height = "0dip"
android: layout_alignParentTop = "true"
android: layout_marginTop = "-100dip"
android: text = "@ string / widget_name"
/>
<TextView
android: layout_width = "0dip"
android: layout_height = "0dip"
android: layout_alignParentTop = "true"
android: layout_marginTop = "-90dip"
android: text = "@ string / tts_pause"
/>
<TextView
android: id = "@ + id / tip_footer"
style = "@ style / TipText.Footer"
android: layout_width = "wrap_content"
android: layout_height = "wrap_content"
android: layout_alignParentBottom = "true"
android: layout_alignParentRight = "true"
android: layout_marginRight = "1dip"
/>
<ImageView
android: id = "@ + id / tip_callout"
android: layout_width = "wrap_content"
android: layout_height = "fill_parent"
android: gravity = "center"
android: layout_alignParentTop = "true"
android: layout_alignParentRight = "true"
android: layout_above = "@ id / tip_footer"
android: visibility = "gone"
android: padding = "4dip"
/>
<TextView
android: id = "@ + id / tip_header"
style = "@ style / TipText.Header"
android: layout_width = "fill_parent"
android: layout_height = "wrap_content"
android: layout_alignParentTop = "true"
android: layout_toLeftOf = "@ id / tip_callout"
android: layout_alignWithParentIfMissing = "true"
android: layout_marginTop = "0dip"
android: layout_marginLeft = "3dip"
/>
<TextView
android: id = "@ + id / tip_message"
style = "@ style / TipText.Message"
android: layout_width = "fill_parent"
android: layout_height = "wrap_content"
android: layout_below = "@ id / tip_header"
android: layout_alignLeft = "@ id / tip_header"
android: layout_alignRight = "@ id / tip_header"
android: layout_marginTop = "1dip"
/>
</ RelativeLayout>
For the above bubble.xml drawable object in the code is as follows droid_widget
<Selector xmlns: Android = " http://schemas.android.com/apk/res/android ">
<item android:state_pressed="true" android:drawable="@drawable/droid_widget_pressed" />
<item android:state_focused="true" android:state_window_focused="true" android:drawable="@drawable/droid_widget_focused" />
<item android:state_focused="true" android:state_window_focused="false" android:drawable="@drawable/droid_widget_normal" />
<item android:drawable="@drawable/droid_widget_normal" />
</ Selector>
public class ProtipWidget extends AppWidgetProvider {
public static final String ACTION_NEXT_TIP = "com.android.misterwidget.NEXT_TIP"; / / definition of a prompt action to switch to the next
public static final String ACTION_POKE = "com.android.misterwidget.HEE_HEE"; / / wake up little robot
public static final String EXTRA_TIMES = "times";
public static final String PREFS_NAME = "Protips";
public static final String PREFS_TIP_NUMBER = "widget_tip";
private static Random sRNG = new Random (); / / rotate images used to generate a static random number generator
private static final Pattern sNewlineRegex = Pattern.compile ("* \ \ n *");
Private static Final Pattern sDrawableRegex = Pattern.compile (" * @ (Drawable / [a-Z0-9 _] +) * ");
/ / Initialization Droid is the eyes do not open, and there is no message alert
private int mIconRes = R.drawable.droidman_open;
private int mMessage = 0;
private AppWidgetManager mWidgetManager = null;
private int [] mWidgetIds;
private Context mContext;
private CharSequence [] mTips;
private void setup (Context context) {
mContext = context;
mWidgetManager = AppWidgetManager.getInstance (context);
mWidgetIds = mWidgetManager.getAppWidgetIds (new ComponentName (context, ProtipWidget.class));
SharedPreferences pref = context.getSharedPreferences (PREFS_NAME, 0);
mMessage = pref.getInt (PREFS_TIP_NUMBER, 0);
mTips = context.getResources (). getTextArray (R.array.tips);
if (mTips! = null) {
if (mMessage> = mTips.length) mMessage = 0;
} Else {
mMessage = -1;
}
}
public void goodmorning () {/ / Android Developer Network tips thread rotate pictures, use the 500,200,100 0.5 seconds so that sleep, sleep 0.2 seconds interval to achieve the animation effect
mMessage = -1;
try {
setIcon (R.drawable.droidman_down_closed);
Thread.sleep (500);
setIcon (R.drawable.droidman_down_open);
Thread.sleep (200);
setIcon (R.drawable.droidman_down_closed);
Thread.sleep (100);
setIcon (R.drawable.droidman_down_open);
Thread.sleep (600);
} Catch (InterruptedException ex) {
}
mMessage = 0;
mIconRes = R.drawable.droidman_open;
refresh ();
}
@ Override
public void onReceive (Context context, Intent intent) {/ / The above android123 has been talked about, appWidget is based on the broadcastreceiver class, so that the necessary action to respond to onReceive driven by events.
setup (context);
if (intent.getAction (). equals (ACTION_NEXT_TIP)) {
mMessage = getNextMessageIndex ();
SharedPreferences.Editor pref = context.getSharedPreferences (PREFS_NAME, 0). Edit ();
pref.putInt (PREFS_TIP_NUMBER, mMessage);
pref.commit ();
refresh ();
} Else if (intent.getAction (). Equals (ACTION_POKE)) {
blink (intent.getIntExtra (EXTRA_TIMES, 1));
} Else if (intent.getAction (). Equals (AppWidgetManager.ACTION_APPWIDGET_ENABLED)) {
goodmorning ();
} Else {
mIconRes = R.drawable.droidman_open;
refresh ();
}
}
private void refresh () {/ / If there are multiple management need to individually update the implementation of the widget
RemoteViews rv = buildUpdate (mContext);
for (int i: mWidgetIds) {
mWidgetManager.updateAppWidget (i, rv);
}
}
private void setIcon (int resId) {
mIconRes = resId;
refresh ();
}
private int getNextMessageIndex () {
return (mMessage + 1)% mTips.length;
}
private void blink (int blinks) {
if (mMessage <0) return;
/ / Android123 prompted more interesting is that all little green men eyes opening and closing, here is an image rotation method used to achieve animation effects, we can use in appWidget very little control
setIcon (R.drawable.droidman_closed);
try {
Thread.sleep (100);
while (0 <- blinks) {
setIcon (R.drawable.droidman_open);
Thread.sleep (200);
setIcon (R.drawable.droidman_closed);
Thread.sleep (100);
}
} Catch (InterruptedException ex) {}
setIcon (R.drawable.droidman_open);
}
public RemoteViews buildUpdate (Context context) {
RemoteViews updateViews = new RemoteViews (
context.getPackageName (), R.layout.widget); / / map layout, widget.xml source file can be found in the following
/ / Click events bubble, corresponding to action_next_tip action
Intent bcast = new Intent (context, ProtipWidget.class);
bcast.setAction (ACTION_NEXT_TIP);
PendingIntent pending = PendingIntent.getBroadcast (
context, 0, bcast, PendingIntent.FLAG_UPDATE_CURRENT);
updateViews.setOnClickPendingIntent (R.id.tip_bubble, pending);
/ / Here for action_poke
bcast = new Intent (context, ProtipWidget.class);
bcast.setAction (ACTION_POKE);
bcast.putExtra (EXTRA_TIMES, 1);
pending = PendingIntent.getBroadcast (
context, 0, bcast, PendingIntent.FLAG_UPDATE_CURRENT);
updateViews.setOnClickPendingIntent (R.id.bugdroid, pending);
/ / Tip bubble text
if (mMessage> = 0) {
String [] parts = sNewlineRegex.split (mTips [mMessage], 2);
String title = parts [0];
String text = parts.length> 1? Parts [1]: "";
/ / Look for a callout graphic referenced in the text
Matcher m = sDrawableRegex.matcher (text);
if (m.find ()) {
String imageName = m.group (1);
int resId = context.getResources (). getIdentifier (
imageName, null, context.getPackageName ());
updateViews.setImageViewResource (R.id.tip_callout, resId);
updateViews.setViewVisibility (R.id.tip_callout, View.VISIBLE);
text = m.replaceFirst ("");
} Else {
updateViews.setImageViewResource (R.id.tip_callout, 0);
updateViews.setViewVisibility (R.id.tip_callout, View.GONE);
}
updateViews.setTextViewText (R.id.tip_message,
text);
updateViews.setTextViewText (R.id.tip_header,
title);
updateViews.setTextViewText (R.id.tip_footer,
context.getResources (). getString (
R.string.pager_footer,
(1 + mMessage), mTips.length));
updateViews.setViewVisibility (R.id.tip_bubble, View.VISIBLE);
} Else {
updateViews.setViewVisibility (R.id.tip_bubble, View.INVISIBLE);
}
updateViews.setImageViewResource (R.id.bugdroid, mIconRes);
return updateViews;
}
}
For the detailed recevier AndroidManifest.xml code below
<receiver android:name=".ProtipWidget" android:label="@string/widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.android.protips.NEXT_TIP" />
<action android:name="com.android.protips.HEE_HEE" />
</ Intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_build" />
</ Receiver>
For res / xml / widget_build.xml the code below
<Appwidget-Provider xmlns: Android = " http://schemas.android.com/apk/res/android "
android: minWidth = "294dip"
android: minHeight = "72dip"
android: updatePeriodMillis = "0"
android: initialLayout = "@ layout / widget" />
For res / layout / widget.xml the code below, note the following layout file using the include way nested
<RelativeLayout xmlns: Android = " http://schemas.android.com/apk/res/android "
android: id = "@ + id / widget"
android: layout_width = "fill_parent"
android: layout_height = "wrap_content"
android: orientation = "vertical"
android: padding = "5dip"
>
<include layout="@layout/droid" />
<include layout="@layout/bubble" />
</ RelativeLayout>
For res / layout / droid.xml the code below
<ImageView xmlns: Android = " http://schemas.android.com/apk/res/android "
android: id = "@ + id / bugdroid"
android: src = "@ drawable / droidman_down_closed"
android: scaleType = "center"
android: layout_width = "wrap_content"
android: layout_height = "wrap_content"
android: layout_alignParentRight = "true"
android: layout_centerVertical = "true"
/>
For res / layout / bubble.xml the code below
<RelativeLayout xmlns: Android = " http://schemas.android.com/apk/res/android "
android: id = "@ + id / tip_bubble"
android: layout_width = "fill_parent"
android: layout_height = "wrap_content"
android: layout_toLeftOf = "@ + id / bugdroid"
android: layout_centerVertical = "true"
android: gravity = "center_vertical | left"
android: layout_marginRight = "2dip"
android: visibility = "invisible"
android: background = "@ drawable / droid_widget"
android: focusable = "true"
>
<TextView
android: layout_width = "0dip"
android: layout_height = "0dip"
android: layout_alignParentTop = "true"
android: layout_marginTop = "-100dip"
android: text = "@ string / widget_name"
/>
<TextView
android: layout_width = "0dip"
android: layout_height = "0dip"
android: layout_alignParentTop = "true"
android: layout_marginTop = "-90dip"
android: text = "@ string / tts_pause"
/>
<TextView
android: id = "@ + id / tip_footer"
style = "@ style / TipText.Footer"
android: layout_width = "wrap_content"
android: layout_height = "wrap_content"
android: layout_alignParentBottom = "true"
android: layout_alignParentRight = "true"
android: layout_marginRight = "1dip"
/>
<ImageView
android: id = "@ + id / tip_callout"
android: layout_width = "wrap_content"
android: layout_height = "fill_parent"
android: gravity = "center"
android: layout_alignParentTop = "true"
android: layout_alignParentRight = "true"
android: layout_above = "@ id / tip_footer"
android: visibility = "gone"
android: padding = "4dip"
/>
<TextView
android: id = "@ + id / tip_header"
style = "@ style / TipText.Header"
android: layout_width = "fill_parent"
android: layout_height = "wrap_content"
android: layout_alignParentTop = "true"
android: layout_toLeftOf = "@ id / tip_callout"
android: layout_alignWithParentIfMissing = "true"
android: layout_marginTop = "0dip"
android: layout_marginLeft = "3dip"
/>
<TextView
android: id = "@ + id / tip_message"
style = "@ style / TipText.Message"
android: layout_width = "fill_parent"
android: layout_height = "wrap_content"
android: layout_below = "@ id / tip_header"
android: layout_alignLeft = "@ id / tip_header"
android: layout_alignRight = "@ id / tip_header"
android: layout_marginTop = "1dip"
/>
</ RelativeLayout>
For the above bubble.xml drawable object in the code is as follows droid_widget
<Selector xmlns: Android = " http://schemas.android.com/apk/res/android ">
<item android:state_pressed="true" android:drawable="@drawable/droid_widget_pressed" />
<item android:state_focused="true" android:state_window_focused="true" android:drawable="@drawable/droid_widget_focused" />
<item android:state_focused="true" android:state_window_focused="false" android:drawable="@drawable/droid_widget_normal" />
<item android:drawable="@drawable/droid_widget_normal" />
</ Selector>