在Android 2.2 SDK中我们可能首次启动模拟器可以看到和以前不一样的是多出了一个绿色的小机器人提示信息,Google给我们了演示了Android中如何通过 RemoteView和简单的图片轮换方式实现动画效果在桌面小工具中,appWidget的基类时AppWidgetProvider类,不过 Widget本身的生命周期管理并非Activity,相对于的而是BroadcastReceiver广播方式处理的,Android 2.2新增的Widget的实现大家可以从中学习到很多有用的知识。
OK废话少说就一个ProtipWidget.java类继承于AppWidgetProvider
1
public
class
ProtipWidget
extends
AppWidgetProvider {
2
public
static
final
String ACTION_NEXT_TIP
=
"
com.android.misterwidget.NEXT_TIP
"
;
//
定义action切换到下一条提示
3
public
static
final
String ACTION_POKE
=
"
com.android.misterwidget.HEE_HEE
"
;
//
唤醒小机器人
4
5
public
static
final
String EXTRA_TIMES
=
"
times
"
;
6
7
public
static
final
String PREFS_NAME
=
"
Protips
"
;
8
public
static
final
String PREFS_TIP_NUMBER
=
"
widget_tip
"
;
9
10
private
static
Random sRNG
=
new
Random();
//
轮换图片用到的,生成一个静态的随机数生成器
11
12
private
static
final
Pattern sNewlineRegex
=
Pattern.compile(
"
*\\n *
"
);
13
private
static
final
Pattern sDrawableRegex
=
Pattern.compile(
"
*@(drawable/[a-z0-9_]+) *
"
);
14
15
//
初始化时Droid是眼睛没有睁开,同时没有信息提示
16
private
int
mIconRes
=
R.drawable.droidman_open;
17
private
int
mMessage
=
0
;
18
19
private
AppWidgetManager mWidgetManager
=
null
;
20
private
int
[] mWidgetIds;
21
private
Context mContext;
22
23
private
CharSequence[] mTips;
24
25
private
void
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
public
void
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
public
void
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
}
else
if
(intent.getAction().equals(ACTION_POKE)) {
72
blink(intent.getIntExtra(EXTRA_TIMES,
1
));
73
}
else
if
(intent.getAction().equals(AppWidgetManager.ACTION_APPWIDGET_ENABLED)) {
74
goodmorning();
75
}
else
{
76
mIconRes
=
R.drawable.droidman_open;
77
refresh();
78
}
79
}
80
81
private
void
refresh() {
//
管理如果有多个本widget执行需要逐个更新
82
RemoteViews rv
=
buildUpdate(mContext);
83
for
(
int
i : mWidgetIds) {
84
mWidgetManager.updateAppWidget(i, rv);
85
}
86
}
87
88
private
void
setIcon(
int
resId) {
89
mIconRes
=
resId;
90
refresh();
91
}
92
93
private
int
getNextMessageIndex() {
94
return
(mMessage
+
1
)
%
mTips.length;
95
}
96
97
private
void
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