一,项目初看
(事先要说明的一点就是,我使用的是android4.1的源代码哦,虚拟机也是Jelly Bean的哦。
(1)项目主要由com.android.deskclock及com.android.alarmclock组成。总共
26个源文件
其中最简单的一个要数Log.java类了,相信只要有基本的Java基础的人都能够看懂。 从AndroidManifest.xml文件中可以看出,应用的入口是DeskClock.java文件的DeskClock类.
二,进入应用,Jelly Bean的虚拟机的话,应用的主界面,就有一个时钟。
显然这个时钟是一个Widget。我们就先来看看这个吧。widget在清单文件中上的声明吧:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<
receiver
android:name
=
"com.android.alarmclock.AnalogAppWidgetProvider"
android:icon
=
"@mipmap/ic_widget_analog_clock"
android:label
=
"@string/analog_gadget"
>
<
intent-filter
>
<
action
android:name
=
"android.appwidget.action.APPWIDGET_UPDATE"
/>
</
intent-filter
>
<
meta-data
android:name
=
"android.appwidget.oldName"
android:value
=
"com.android.deskclock.AnalogAppWidgetProvider"
/>
<
meta-data
android:name
=
"android.appwidget.provider"
android:resource
=
"@xml/analog_appwidget"
/>
</
receiver
>
|
我们知道一个Widget是一个BroadcastReceiver的子类组件。
上面我们只关注它的intent-filter的action,这个声明,表明这个广播接收者只接收intent的action
值为"android.appwidget.action.APPWIDGET_UPDATE"的广播。
事实是Widget本身也对这个做了判断。
AnalogAppWidgetProvider类代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/**
* Simple widget to show analog clock.
*/
public
class
AnalogAppWidgetProvider
extends
BroadcastReceiver {
static
final
String TAG =
"AnalogAppWidgetProvider"
;
public
void
onReceive(Context context, Intent intent) {
String action = intent.getAction();
if
(AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
RemoteViews views =
new
RemoteViews(context.getPackageName(),
R.layout.analog_appwidget);
views.setOnClickPendingIntent(R.id.analog_appwidget,
PendingIntent.getActivity(context,
0
,
new
Intent(context, AlarmClock.
class
),
0
));
int
[] appWidgetIds = intent.getIntArrayExtra(
AppWidgetManager.EXTRA_APPWIDGET_IDS);
AppWidgetManager gm = AppWidgetManager.getInstance(context);
gm.updateAppWidget(appWidgetIds, views);
}
}
}
|
(1) RemoteViews
文档的解释是:RemoteViews是一个描述了可以在其它进程显示View层级的类。View层级通过一个布局资源文件构造得来,RemoteViews类同时提供了些基本的用于修改构造的布局层级的操作。
关于RemoteViews呢,我发现RemoteViews概述 这一篇博客讲得很不错,推荐去看。
(2)关于PendingIntent
为也好说明,将上面的其中的两行代码改写如下:
1
2
3
|
Intent intent =
new
Intent(cotext,AlarmClock.
class
);
PendingIntent pi = PendingIntent.getActivity(context,
0
,intent,
0
)
views.setOnClickPendingIntent(R.id.analog_appwidget,pi)
|
上面的三行代码,第一行自不必说了。
第二行呢,需要对PendingIntent有一些了解。
顾名思义,PendingIntent即一个捎带了Intent的类。
我们知道Intent用于启动某一个组件。所以PendingIntent的静态工厂方法getActivity()
即是返回一个用于启用Activity的Intent.
因此显然PendingIntent如你所想像中那样还有下面的这些方法:
1
2
3
4
|
public
static
PendingIntent getBroadcast(Context context,
int
requestCode,
Intent intent,
int
flags)
public
static
PendingIntent getService(Context context,
int
requestCode,
Intent intent,
int
flags)
|
第三行,views.setOnClickPendingIntent(R.id.analog_appwidget,pi)
即是当点击桌面的时钟widget时(布局文件是analog_appwidget)时,启动pi所捎带的Intent.于是就会启动AlarmClock类,它是一个Activity.
关于PendingIntent的更多说明,请查阅文档,或者问下Google大人。
其它的三行代码就比较好理解了。
1
2
3
4
5
6
|
int
[] appWidgetIds = intent.getIntArrayExtra(
AppWidgetManager.EXTRA_APPWIDGET_IDS);
AppWidgetManager gm = AppWidgetManager.getInstance(context);
gm.updateAppWidget(appWidgetIds, views);
|
(1)获得些widget的ID,注意是数组。
(2)获得AppWidgetManager
(3)使用AppWidgetManager的单例,及appWidgetIds,及RemoteViews的views更新此widget.
对于些widget类还有一个地方没有提及的就是:
1
2
3
|
<
meta-data
android:name
=
"android.appwidget.provider"
android:resource
=
"@xml/analog_appwidget"
/>
|
这个是android中widget必须提供一些信息。
看看@xml/analog_appwiget便知,
推荐完全参数android中关于app widget的文档。