1
回答
探秘 widget 之 widget 背后的故事
利用AWS快速构建适用于生产的无服务器应用程序,免费试用12个月>>>   
之前分析了下widget添加到laucher的过程,现在我们来分析下widget被添加到laucher之后发生的故事。

AppWidgetProvider

桌面组件实现的组要类,它的父类是一个广播接收器,它主要作用就是接收更新桌面组件的广播消息,然后更新桌面组件

i. public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)

该方法对应事件:android.appwidget.action.APPWIDGET_UPDATE当桌面组件被周期更新的时候它被调用,深入父类的onReceive方法就会了解到,当父类的onReceive方法接收到android.appwidget.action.APPWIDGET_UPDATE消息就会调用该update方法。

ii. public void onReceive(Context context, Intent intent)

AppWidgetProvider本身是一个广播接收器,父类已经覆盖了该方法,你重新覆盖该方法的时候,注意要添加super. onReceive到你的方法中,否则onUpdate将不再会被调用

iii. public void onDeleted(Context context, int[] appWidgetIds)

AppWidgetProvider接收消息android.appwidget.action.APPWIDGET_DELETED时候调用该方法。

每个桌面组件就是一个AppWidget,当你需要在代码中实现一个桌面组件,首先你必须得实现AppWidgetProvider类,当你点击AppWidgetProvider类你会发现其实AppWidgetProvider就是一个BroadcastReceiver子类,也就是说它也是一个广播接收器。桌面组件内容显示更新全部是通过RemoteViews对象,刚创建桌面组件的时候系统会绑定AppWidgetProvider到一个AppWidgetId,然后后面通过AppWidgetManager.updateAppWidget方法把RemoteViews对象更新到对应的桌面组件。

回到之前添加widget时的流程,在桌面组件刚被添加的时候,系统通过AppWidgetHost.allocateAppWidgetId函数为桌面组件分配一个新的AppWidgetId。在选择widget的时候,通过点击的列表选项可获取到对应桌面组件对应的ComponentName,一个ComponentName由一个包名和一个AppWidgetProvider类名称唯一指定,然后通过AppWidgetManager.bindAppWidgetId(int appWidgetId, ComponentName provider)把前面生成的AppWidgetId与一个ComponentName绑定,一个ComponentName可以绑定多个AppWidgetId。所以你可以在桌面上放置几个一样的widget。

一个AppWidgetProvider可以由一个ComponentName唯一确定,在一般的widget应用中:

//先获取一个AppWidgetManager对象
           AppWidgetManager appWidgetMgr = AppWidgetManager.getInstance(context);
//新建一个ComponentName对象,用来获取获取桌面组件widgetIds
           ComponentName compName = new ComponentName(context,
                  ExampleWidgetProvider.class);
//返回的是由 ComponentName对应的  int[] widgetIds   
      int[] widgetIds = appWidgetMgr.getAppWidgetIds(compName);

每一个AppWidgetProvider上可能建立了多个桌面组件,每一个桌面组件对以应一个AppWidgetId,要获取一个AppWidgetProvider上所有的桌面组件的AppWidgetId数据,可以先建一个ComponentName对象,设置ComponentName中的类名和包名为AppWidgetProvider的类名和包名,然后可通过AppWidgetManager. getAppWidgetIds(ComponentName provider)方法获取AppWidgetId列表。

通过AppWidgetId我们便可以操作指定的widget。

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

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

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

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

Remoteviews更新桌面组件最终还是要在launcher进程中执行,在launcher中有一个handler: AppWidgetHost.UpdateHandler,该handler就是用来处理Remoteviews更新的,一旦我们调用appWidgetManager.updateAppWidget(appWidgetId, views)这个方法,AppWidgetHost.UpdateHandler. handleMessage事件就会响应,不过要注意是该事件响应是在launcher进程中执行:

 switch (msg.what) {
      case HANDLE_UPDATE: {
       updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj);//执行Remoteviews更新
                    break;
                }

原文出处:http://blog.csdn.net/hmg25/article/details/6439696

举报
鉴客
发帖于6年前 1回/1K+阅
顶部