一,项目初看
(事先要说明的一点就是,我使用的是android4.1的源代码哦,虚拟机也是Jelly Bean的哦。
(1)项目主要由com.android.deskclock及com.android.alarmclock组成。总共
26个源文件
其中最简单的一个要数Log.java类了,相信只要有基本的Java基础的人都能够看懂。
从AndroidManifest.xml文件中可以看出,应用的入口是DeskClock.java文件的DeskClock类.
二,进入应用,Jelly Bean的虚拟机的话,应用的主界面,就有一个时钟。
显然这个时钟是一个Widget。我们就先来看看这个吧。widget在清单文件中上的声明吧:
<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类代码如下:
/** * 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
为也好说明,将上面的其中的两行代码改写如下:
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如你所想像中那样还有下面的这些方法:
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大人。
其它的三行代码就比较好理解了。
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类还有一个地方没有提及的就是:
<meta-data android:name="android.appwidget.provider" android:resource="@xml/analog_appwidget" />
这个是android中widget必须提供一些信息。
看看@xml/analog_appwiget便知,
推荐完全参数android中关于app widget的文档。