Widget~~1--主类
在Android 2.2 SDK中我们可能首次启动模拟器可以看到和以前不一样的是多出了一个绿色的小机器人提示信息,Google给我们了演示了Android中如何通过 RemoteView和简单的图片轮换方式实现动画效果在桌面小工具中,appWidget的基类时AppWidgetProvider类,不过 Widget本身的生命周期管理并非Activity,相对于的而是BroadcastReceiver广播方式处理的,Android 2.2新增的Widget的实现大家可以从中学习到很多有用的知识。
OK废话少说就一个ProtipWidget.java类继承于AppWidgetProvider
1 publicclass ProtipWidget extends AppWidgetProvider {
2 publicstaticfinal String ACTION_NEXT_TIP ="com.android.misterwidget.NEXT_TIP"; //定义action切换到下一条提示
3 publicstaticfinal String ACTION_POKE ="com.android.misterwidget.HEE_HEE"; //唤醒小机器人
4
5 publicstaticfinal String EXTRA_TIMES ="times";
6
7 publicstaticfinal String PREFS_NAME ="Protips";
8 publicstaticfinal String PREFS_TIP_NUMBER ="widget_tip";
9
10 privatestatic Random sRNG =new Random(); //轮换图片用到的,生成一个静态的随机数生成器
11
12 privatestaticfinal Pattern sNewlineRegex = Pattern.compile(" *\\n *");
13 privatestaticfinal Pattern sDrawableRegex = Pattern.compile(" *@(drawable/[a-z0-9_]+) *");
14
15 // 初始化时Droid是眼睛没有睁开,同时没有信息提示
16 privateint mIconRes = R.drawable.droidman_open;
17 privateint mMessage =0;
18
19 private AppWidgetManager mWidgetManager =null;
20 privateint[] mWidgetIds;
21 private Context mContext;
22
23 private CharSequence[] mTips;
24
25 privatevoid setup(Context context) {
26 mContext = context;
27 mWidgetManager = AppWidgetManager.getInstance(context);
28 mWidgetIds = mWidgetManager.getAppWidgetIds(new ComponentName(context, ProtipWidget.class));
29
30 SharedPreferences pref = context.getSharedPreferences(PREFS_NAME, 0);
31 mMessage = pref.getInt(PREFS_TIP_NUMBER, 0);
32
33 mTips = context.getResources().getTextArray(R.array.tips);
34
35 if (mTips !=null) {
36 if (mMessage >= mTips.length) mMessage =0;
37 } else {
38 mMessage =-1;
39 }
40
41 }
42
43 publicvoid goodmorning() { //Android开发网提示线程中轮换图片,使用了500,200,100等这样的0.5秒休眠,0.2秒休眠实现了动画的间隔效果
44 mMessage =-1;
45 try {
46 setIcon(R.drawable.droidman_down_closed);
47 Thread.sleep(500);
48 setIcon(R.drawable.droidman_down_open);
49 Thread.sleep(200);
50 setIcon(R.drawable.droidman_down_closed);
51 Thread.sleep(100);
52 setIcon(R.drawable.droidman_down_open);
53 Thread.sleep(600);
54 } catch (InterruptedException ex) {
55 }
56 mMessage =0;
57 mIconRes = R.drawable.droidman_open;
58 refresh();
59 }
60
61 @Override
62 publicvoid onReceive(Context context, Intent intent) { //上面已经讲到了,appWidget是基于broadcastreceiver类的,所以说需要响应onReceive通过 action来驱动事件。
63 setup(context);
64
65 if (intent.getAction().equals(ACTION_NEXT_TIP)) {
66 mMessage = getNextMessageIndex();
67 SharedPreferences.Editor pref = context.getSharedPreferences(PREFS_NAME, 0).edit();
68 pref.putInt(PREFS_TIP_NUMBER, mMessage);
69 pref.commit();
70 refresh();
71 } elseif (intent.getAction().equals(ACTION_POKE)) {
72 blink(intent.getIntExtra(EXTRA_TIMES, 1));
73 } elseif (intent.getAction().equals(AppWidgetManager.ACTION_APPWIDGET_ENABLED)) {
74 goodmorning();
75 } else {
76 mIconRes = R.drawable.droidman_open;
77 refresh();
78 }
79 }
80
81 privatevoid refresh() { //管理如果有多个本widget执行需要逐个更新
82 RemoteViews rv = buildUpdate(mContext);
83 for (int i : mWidgetIds) {
84 mWidgetManager.updateAppWidget(i, rv);
85 }
86 }
87
88 privatevoid setIcon(int resId) {
89 mIconRes = resId;
90 refresh();
91 }
92
93 privateint getNextMessageIndex() {
94 return (mMessage +1) % mTips.length;
95 }
96
97 privatevoid blink(int blinks) {
98 if (mMessage <0) return;
99
100 //比较有意思的就是小绿人眼睛的一开一闭,这里使用的是图片轮换方式来实现动画效果,在appWidget中我们可以用的控件十分少
101
102 setIcon(R.drawable.droidman_closed);
103 try {
104 Thread.sleep(100);
105 while (0<--blinks) {
106 setIcon(R.drawable.droidman_open);
107 Thread.sleep(200);
108 setIcon(R.drawable.droidman_closed);
109 Thread.sleep(100);
110 }
111 } catch (InterruptedException ex) { }
112 setIcon(R.drawable.droidman_open);
113 }
114
115 public RemoteViews buildUpdate(Context context) {
116 RemoteViews updateViews =new RemoteViews(
117 context.getPackageName(), R.layout.widget); //映射布局,widget.xml文件的源码在下面可以找到
118
119 // 按下bubble的事件,对应action_next_tip动作
120 Intent bcast =new Intent(context, ProtipWidget.class);
121 bcast.setAction(ACTION_NEXT_TIP);
122 PendingIntent pending = PendingIntent.getBroadcast(
123 context, 0, bcast, PendingIntent.FLAG_UPDATE_CURRENT);
124 updateViews.setOnClickPendingIntent(R.id.tip_bubble, pending);
125
126 //这里为action_poke
127 bcast =new Intent(context, ProtipWidget.class);
128 bcast.setAction(ACTION_POKE);
129 bcast.putExtra(EXTRA_TIMES, 1);
130 pending = PendingIntent.getBroadcast(
131 context, 0, bcast, PendingIntent.FLAG_UPDATE_CURRENT);
132 updateViews.setOnClickPendingIntent(R.id.bugdroid, pending);
133
134 // Tip bubble text
135 if (mMessage >=0) {
136 String[] parts = sNewlineRegex.split(mTips[mMessage], 2);
137 String title = parts[0];
138 String text = parts.length >1? parts[1] : "";
139
140 // Look for a callout graphic referenced in the text
141 Matcher m = sDrawableRegex.matcher(text);
142 if (m.find()) {
143 String imageName = m.group(1);
144 int resId = context.getResources().getIdentifier(
145
146 imageName, null, context.getPackageName());
147 updateViews.setImageViewResource(R.id.tip_callout, resId);
148 updateViews.setViewVisibility(R.id.tip_callout, View.VISIBLE);
149 text = m.replaceFirst("");
150 } else {
151 updateViews.setImageViewResource(R.id.tip_callout, 0);
152 updateViews.setViewVisibility(R.id.tip_callout, View.GONE);
153 }
154
155 updateViews.setTextViewText(R.id.tip_message,
156 text);
157 updateViews.setTextViewText(R.id.tip_header,
158 title);
159 updateViews.setTextViewText(R.id.tip_footer,
160 context.getResources().getString(
161 R.string.pager_footer,
162 (1+mMessage), mTips.length));
163 updateViews.setViewVisibility(R.id.tip_bubble, View.VISIBLE);
164 } else {
165 updateViews.setViewVisibility(R.id.tip_bubble, View.INVISIBLE);
166 }
167
168 updateViews.setImageViewResource(R.id.bugdroid, mIconRes);
169
170 return updateViews;
171 }
172 }
173
2 publicstaticfinal String ACTION_NEXT_TIP ="com.android.misterwidget.NEXT_TIP"; //定义action切换到下一条提示
3 publicstaticfinal String ACTION_POKE ="com.android.misterwidget.HEE_HEE"; //唤醒小机器人
4
5 publicstaticfinal String EXTRA_TIMES ="times";
6
7 publicstaticfinal String PREFS_NAME ="Protips";
8 publicstaticfinal String PREFS_TIP_NUMBER ="widget_tip";
9
10 privatestatic Random sRNG =new Random(); //轮换图片用到的,生成一个静态的随机数生成器
11
12 privatestaticfinal Pattern sNewlineRegex = Pattern.compile(" *\\n *");
13 privatestaticfinal Pattern sDrawableRegex = Pattern.compile(" *@(drawable/[a-z0-9_]+) *");
14
15 // 初始化时Droid是眼睛没有睁开,同时没有信息提示
16 privateint mIconRes = R.drawable.droidman_open;
17 privateint mMessage =0;
18
19 private AppWidgetManager mWidgetManager =null;
20 privateint[] mWidgetIds;
21 private Context mContext;
22
23 private CharSequence[] mTips;
24
25 privatevoid setup(Context context) {
26 mContext = context;
27 mWidgetManager = AppWidgetManager.getInstance(context);
28 mWidgetIds = mWidgetManager.getAppWidgetIds(new ComponentName(context, ProtipWidget.class));
29
30 SharedPreferences pref = context.getSharedPreferences(PREFS_NAME, 0);
31 mMessage = pref.getInt(PREFS_TIP_NUMBER, 0);
32
33 mTips = context.getResources().getTextArray(R.array.tips);
34
35 if (mTips !=null) {
36 if (mMessage >= mTips.length) mMessage =0;
37 } else {
38 mMessage =-1;
39 }
40
41 }
42
43 publicvoid goodmorning() { //Android开发网提示线程中轮换图片,使用了500,200,100等这样的0.5秒休眠,0.2秒休眠实现了动画的间隔效果
44 mMessage =-1;
45 try {
46 setIcon(R.drawable.droidman_down_closed);
47 Thread.sleep(500);
48 setIcon(R.drawable.droidman_down_open);
49 Thread.sleep(200);
50 setIcon(R.drawable.droidman_down_closed);
51 Thread.sleep(100);
52 setIcon(R.drawable.droidman_down_open);
53 Thread.sleep(600);
54 } catch (InterruptedException ex) {
55 }
56 mMessage =0;
57 mIconRes = R.drawable.droidman_open;
58 refresh();
59 }
60
61 @Override
62 publicvoid onReceive(Context context, Intent intent) { //上面已经讲到了,appWidget是基于broadcastreceiver类的,所以说需要响应onReceive通过 action来驱动事件。
63 setup(context);
64
65 if (intent.getAction().equals(ACTION_NEXT_TIP)) {
66 mMessage = getNextMessageIndex();
67 SharedPreferences.Editor pref = context.getSharedPreferences(PREFS_NAME, 0).edit();
68 pref.putInt(PREFS_TIP_NUMBER, mMessage);
69 pref.commit();
70 refresh();
71 } elseif (intent.getAction().equals(ACTION_POKE)) {
72 blink(intent.getIntExtra(EXTRA_TIMES, 1));
73 } elseif (intent.getAction().equals(AppWidgetManager.ACTION_APPWIDGET_ENABLED)) {
74 goodmorning();
75 } else {
76 mIconRes = R.drawable.droidman_open;
77 refresh();
78 }
79 }
80
81 privatevoid refresh() { //管理如果有多个本widget执行需要逐个更新
82 RemoteViews rv = buildUpdate(mContext);
83 for (int i : mWidgetIds) {
84 mWidgetManager.updateAppWidget(i, rv);
85 }
86 }
87
88 privatevoid setIcon(int resId) {
89 mIconRes = resId;
90 refresh();
91 }
92
93 privateint getNextMessageIndex() {
94 return (mMessage +1) % mTips.length;
95 }
96
97 privatevoid blink(int blinks) {
98 if (mMessage <0) return;
99
100 //比较有意思的就是小绿人眼睛的一开一闭,这里使用的是图片轮换方式来实现动画效果,在appWidget中我们可以用的控件十分少
101
102 setIcon(R.drawable.droidman_closed);
103 try {
104 Thread.sleep(100);
105 while (0<--blinks) {
106 setIcon(R.drawable.droidman_open);
107 Thread.sleep(200);
108 setIcon(R.drawable.droidman_closed);
109 Thread.sleep(100);
110 }
111 } catch (InterruptedException ex) { }
112 setIcon(R.drawable.droidman_open);
113 }
114
115 public RemoteViews buildUpdate(Context context) {
116 RemoteViews updateViews =new RemoteViews(
117 context.getPackageName(), R.layout.widget); //映射布局,widget.xml文件的源码在下面可以找到
118
119 // 按下bubble的事件,对应action_next_tip动作
120 Intent bcast =new Intent(context, ProtipWidget.class);
121 bcast.setAction(ACTION_NEXT_TIP);
122 PendingIntent pending = PendingIntent.getBroadcast(
123 context, 0, bcast, PendingIntent.FLAG_UPDATE_CURRENT);
124 updateViews.setOnClickPendingIntent(R.id.tip_bubble, pending);
125
126 //这里为action_poke
127 bcast =new Intent(context, ProtipWidget.class);
128 bcast.setAction(ACTION_POKE);
129 bcast.putExtra(EXTRA_TIMES, 1);
130 pending = PendingIntent.getBroadcast(
131 context, 0, bcast, PendingIntent.FLAG_UPDATE_CURRENT);
132 updateViews.setOnClickPendingIntent(R.id.bugdroid, pending);
133
134 // Tip bubble text
135 if (mMessage >=0) {
136 String[] parts = sNewlineRegex.split(mTips[mMessage], 2);
137 String title = parts[0];
138 String text = parts.length >1? parts[1] : "";
139
140 // Look for a callout graphic referenced in the text
141 Matcher m = sDrawableRegex.matcher(text);
142 if (m.find()) {
143 String imageName = m.group(1);
144 int resId = context.getResources().getIdentifier(
145
146 imageName, null, context.getPackageName());
147 updateViews.setImageViewResource(R.id.tip_callout, resId);
148 updateViews.setViewVisibility(R.id.tip_callout, View.VISIBLE);
149 text = m.replaceFirst("");
150 } else {
151 updateViews.setImageViewResource(R.id.tip_callout, 0);
152 updateViews.setViewVisibility(R.id.tip_callout, View.GONE);
153 }
154
155 updateViews.setTextViewText(R.id.tip_message,
156 text);
157 updateViews.setTextViewText(R.id.tip_header,
158 title);
159 updateViews.setTextViewText(R.id.tip_footer,
160 context.getResources().getString(
161 R.string.pager_footer,
162 (1+mMessage), mTips.length));
163 updateViews.setViewVisibility(R.id.tip_bubble, View.VISIBLE);
164 } else {
165 updateViews.setViewVisibility(R.id.tip_bubble, View.INVISIBLE);
166 }
167
168 updateViews.setImageViewResource(R.id.bugdroid, mIconRes);
169
170 return updateViews;
171 }
172 }
173