Android中的AppWidget

来源:互联网 发布:java中的延时函数 编辑:程序博客网 时间:2024/04/23 16:31

Android中的AppWidget与google widget和中移动的widget并不是一个概念,这里的AppWidget只是把一个进程的控件嵌入到别外一个进程的窗口里的一种方法。View在另 外一个进程里显示,但事件的处理方法还是在原来的进程里。这有点像 X Window中的嵌入式窗口。
broncho-a1-widget

Android中的AppWidget包括以下几个部分:

AppWidgetProvider

AppWidgetProvider是AppWidget提供者需要实现的接口,它实际上是一个BroadcastReceiver。只不过子类要实现的不再是onReceive,而是转换成了几个新的函数:

1 public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
2  public void onDeleted(Context context, int[] appWidgetIds)
3  public void onEnabled(Context context)
4 public void onDisabled(Context context)

这几个函数用来响应AppWidgetService发出的相应的广播消息。

AppWidgetProvider的实现者

作为AppWidgetProvider的实现者,一定要实现onUpdate函数,因为这个函数决定widget的显示方式,如果没有这个函数widget根本没办法出现。

1 void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)

onUpdate的实现基本上遵循下面的流程:

o 创建RemoteViews
o 调用AppWidgetManager的updateAppWidget去更新widget.

现在我们看下Music里的MediaAppWidgetProvider实现:

复制代码
1 public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
2 defaultAppWidget(context, appWidgetIds);
3
4 // Send broadcast intent to any running MediaPlaybackService so it can
5 // wrap around with an immediate update.
6 Intent updateIntent = new Intent(MediaPlaybackService.SERVICECMD);
7 updateIntent.putExtra(MediaPlaybackService.CMDNAME,
8 MediaAppWidgetProvider.CMDAPPWIDGETUPDATE);
9 updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
10 updateIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11 context.sendBroadcast(updateIntent);
12 }
复制代码

在defaultAppWidget里面:
o 创建RemoteViews,并设置相应的属性。

复制代码
1 final Resources res = context.getResources();
2 final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.album_appwidget);
3
4 views.setViewVisibility(R.id.title, View.GONE);
5 views.setTextViewText(R.id.artist, res.getText(R.string.emptyplaylist));
复制代码

o 为View上的控制设置事件处理方法。

复制代码
1 linkButtons(context, views, false /* not playing */);
2
3 private void linkButtons(Context context, RemoteViews views, boolean playerActive) {
4 // Connect up various buttons and touch events
5 Intent intent;
6 PendingIntent pendingIntent;
7
8 final ComponentName serviceName = new ComponentName(context, MediaPlaybackService.class);
9
10 if (playerActive) {
11 intent = new Intent(context, MediaPlaybackActivity.class);
12 pendingIntent = PendingIntent.getActivity(context,
13 0 /* no requestCode */, intent, 0 /* no flags */);
14 views.setOnClickPendingIntent(R.id.album_appwidget, pendingIntent);
15 } else {
16 intent = new Intent(context, MusicBrowserActivity.class);
17 pendingIntent = PendingIntent.getActivity(context,
18 0 /* no requestCode */, intent, 0 /* no flags */);
19 views.setOnClickPendingIntent(R.id.album_appwidget, pendingIntent);
20 }
21
22 intent = new Intent(MediaPlaybackService.TOGGLEPAUSE_ACTION);
23 intent.setComponent(serviceName);
24 pendingIntent = PendingIntent.getService(context,
25 0 /* no requestCode */, intent, 0 /* no flags */);
26 views.setOnClickPendingIntent(R.id.control_play, pendingIntent);
27
28 intent = new Intent(MediaPlaybackService.NEXT_ACTION);
29 intent.setComponent(serviceName);
30 pendingIntent = PendingIntent.getService(context,
31 0 /* no requestCode */, intent, 0 /* no flags */);
32 views.setOnClickPendingIntent(R.id.control_next, pendingIntent);
33 }
复制代码

o 更新widget

复制代码
1 pushUpdate(service, appWidgetIds, views);
2 private void pushUpdate(Context context, int[] appWidgetIds, RemoteViews views) {
3 // Update specific list of appWidgetIds if given, otherwise default to all
4 final AppWidgetManager gm = AppWidgetManager.getInstance(context);
5 if (appWidgetIds != null) {
6 gm.updateAppWidget(appWidgetIds, views);
7 } else {
8 gm.updateAppWidget(THIS_APPWIDGET, views);
9 }
10 }
复制代码

RemoteViews

RemoteViews并不是一个真正的View,它没有实现View的接口,而只是一个用于描述View的实体。比如:创建View需要的资源ID和各个控件的事件响应方法。RemoteViews会通过进程间通信机制传递给AppWidgetHost。

现在我们可以看出,Android中的AppWidget与google widget和中移动的widget并不是一个概念,这里的AppWidget只是把一个进程的控件嵌入到别外一个进程的窗口里的一种方法。View在另 外一个进程里显示,但事件的处理方法还是在原来的进程里。这有点像 X Window中的嵌入式窗口。

AppWidgetHost

AppWidgetHost是真正容纳AppWidget的地方,它的主要功能有两个:

o 监听来自AppWidgetService的事件:

复制代码
1 class Callbacks extends IAppWidgetHost.Stub {
2 public void updateAppWidget(int appWidgetId, RemoteViews views) {
3 Message msg = mHandler.obtainMessage(HANDLE_UPDATE);
4 msg.arg1 = appWidgetId;
5 msg.obj = views;
6 msg.sendToTarget();
7 }
8
9 public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
10 Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);
11 msg.arg1 = appWidgetId;
12 msg.obj = info;
13 msg.sendToTarget();
14 }
15 }
复制代码

这是主要处理update和provider_changed两个事件,根据这两个事件更新widget。

复制代码
1 class UpdateHandler extends Handler {
2 public UpdateHandler(Looper looper) {
3 super(looper);
4 }
5
6 public void handleMessage(Message msg) {
7 switch (msg.what) {
8 case HANDLE_UPDATE: {
9 updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj);
10 break;
11 }
12 case HANDLE_PROVIDER_CHANGED: {
13 onProviderChanged(msg.arg1, (AppWidgetProviderInfo)msg.obj);
14 break;
15 }
16 }
17 }
18 }
复制代码

o 另外一个功能就是创建AppWidgetHostView。前面我们说过RemoteViews不是真正的View,只是View的描述,而 AppWidgetHostView才是真正的View。这里先创建AppWidgetHostView,然后通过AppWidgetService查询 appWidgetId对应的RemoteViews,最后把RemoteViews传递给AppWidgetHostView去 updateAppWidget。

复制代码
1 public final AppWidgetHostView createView(Context context, int appWidgetId,
2 AppWidgetProviderInfo appWidget) {
3 AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);
4 view.setAppWidget(appWidgetId, appWidget);
5 synchronized (mViews) {
6 mViews.put(appWidgetId, view);
7 }
8 RemoteViews views = null;
9 try {
10 views = sService.getAppWidgetViews(appWidgetId);
11 } catch (RemoteException e) {
12 throw new RuntimeException("system server dead?", e);
13 }
14 view.updateAppWidget(views);
15 return view;
16 }
复制代码

AppWidgetHostView

AppWidgetHostView是真正的View,但它只是一个容器,用来容纳实际的AppWidget的View。这个AppWidget的View是根据RemoteViews的描述来创建。这是在updateAppWidget里做的:

复制代码
1 public void updateAppWidget(RemoteViews remoteViews) {
2 ...
3 if (content == null && layoutId == mLayoutId) {
4 try {
5 remoteViews.reapply(mContext, mView);
6 content = mView;
7 recycled = true;
8 if (LOGD) Log.d(TAG, "was able to recycled existing layout");
9 } catch (RuntimeException e) {
10 exception = e;
11 }
12 }
13
14 // Try normal RemoteView inflation
15 if (content == null) {
16 try {
17 content = remoteViews.apply(mContext, this);
18 if (LOGD) Log.d(TAG, "had to inflate new layout");
19 } catch (RuntimeException e) {
20 exception = e;
21 }
22 }
23 ...
24 if (!recycled) {
25 prepareView(content);
26 addView(content);
27 }
28
29 if (mView != content) {
30 removeView(mView);
31 mView = content;
32 }
33 ...
34 }
复制代码

remoteViews.apply创建了实际的View,下面代码可以看出:

复制代码
1 public View apply(Context context, ViewGroup parent) {
2 View result = null;
3
4 Context c = prepareContext(context);
5
6 Resources r = c.getResources();
7 LayoutInflater inflater = (LayoutInflater) c
8 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
9
10 inflater = inflater.cloneInContext(c);
11 inflater.setFilter(this);
12
13 result = inflater.inflate(mLayoutId, parent, false);
14
15 performApply(result);
16
17 return result;
18 }
复制代码

Host的实现者

AppWidgetHost和AppWidgetHostView是在框架中定义的两个基类。应用程序可以利用这两个类来实现自己的Host。Launcher是缺省的桌面,它是一个Host的实现者。

LauncherAppWidgetHostView扩展了AppWidgetHostView,实现了对长按事件的处理。

LauncherAppWidgetHost扩展了AppWidgetHost,这里只是重载了onCreateView,创建LauncherAppWidgetHostView的实例。

AppWidgetService

AppWidgetService存在的目的主要是解开AppWidgetProvider和AppWidgetHost之间的耦合。如果 AppWidgetProvider和AppWidgetHost的关系固定死了,AppWidget就无法在任意进程里显示了。而有了 AppWidgetService,AppWidgetProvider根本不需要知道自己的AppWidget在哪里显示了。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 油锅着火时应该怎么办 大唐机考错过了怎么办 天然气ic卡丢了怎么办 贷上钱逾期2个月怎么办 法院不给执行款怎么办 社保多交一个月怎么办 成都医保断保了怎么办 欠了几万网贷怎么办 欠了很多网贷怎么办 医院就诊卡丢了怎么办 儿童医保本丢了怎么办 中山三院诊疗卡怎么办 工厂办不了环评怎么办 小区移动4g差怎么办 梵妮印台干了怎么办 贴了膏药后过敏怎么办 贴药膏后皮肤痒怎么办 贴完膏药过敏了怎么办 骨折后骨密度低怎么办 食品经营许可证过期了怎么办 40年的产权满后怎么办 五证合一后税务怎么办 互联业务登录页怎么办 vivo音量键坏了怎么办 琴岛通学生卡怎么办 云卡会员删除了怎么办 办健康证没空腹怎么办 办健康证吃饭了怎么办 发票盖了财务章怎么办 发票盖成公章了怎么办 发票上盖了公章怎么办 进京证怎么办在哪里办 去北京没进京证怎么办 单位的车怎么办进京证 房贷合同丢了怎么办 农合医疗卡丢失怎么办 手指断了怎么办能好吗? 被劳务派遣公司骗了怎么办 餐饮服务许可证过期了怎么办 中行u盾证书过期怎么办 84消毒液吸多了怎么办