田海立@CSDN
2012-8-22
本文结合AppWidget的应用场景,分析Android中RemoteViews的内部具体实现。
从前文《Android中AppWidget的分析与应用:AppWidgetProvider》和《Android中Launcher对于AppWidget的处理的分析:AppWidgetHost角色》中得知,Android中AppWidget的图形资源是由AppWidgetProvider通过RemoteViews提供的;而显示是由AppWidgetHost通过AppWidgetHostView把RemoteView提供的内容显示在本地View上的。AppWidgetProvider和AppWidgetHostView运行在不同的程序中,而它们沟通的图形元素和点击回馈的桥梁就是RemoteViews。
下面为了行文方便和一致,把RemoteViews的内容提供方AppWidgetProvoder称作Remote端;而显示RemoteViews内容的一方AppWidgetHost称作Local端。
一、给RemoteViews提供内容——SettingsAppWidgetProvider
下图是SettingsAppWidgetProvider(位于Settings中的com.android.settings.widget包中)作为AppWidgetProvider得到update通知之后,创建RemoteViews,并把Remote端的响应Intent以及图形元素放进RemoteViews中的顺序图。
图一、为RemoteViews提供内容和侦听
图中,
1.Settings创建RemoteViews时,把packageName和layoutId传进去并保存起来。packageName相当重要,因为这里的layoutId和各种其他资源都是相对这个程序来说的,只有通过packageName获得相应的Context,才能进而获得资源,否则其他程序是无法获得这些资源的[Seq#1]。
2.Settings把layoutId中的viewId指示的View被点击之后获得响应的PendingIntent设置到RemoteViews中[Seq#2~ #5]。
- RemoteViews创建SetOnClickPendingIntent并把id和intent传入,SetOnClickPendingIntent保存这些值;
- SetOnClickPendingIntent是RemoteViews.Action的子类,通过addAction()把SetOnClickPendingIntent加入到mActions:ArrayList<RemoteViews.Action>保存下来。
3.Settings把layoutId中的viewId指示的View的ImageSourceID设置到RemoteViews中[Seq#6~ #10]。
- RemoteViews中有很多setXYZ()的方法,用来根据不同的要设置值的类型来设置;
- setXYZ()创建ReflectionAction并把viewId和value,以及“setImageResource”作为methodName传入,ReflectionAction保存这些值;
- ReflectionAction是RemoteViews.Action的子类,通过addAction()把ReflectionAction加入到mActions:ArrayList<RemoteViews.Action>保存下来。
这里描述的是一个子过程,后续会通过AppWidgetManager把这个创建好的RemoteViews放进AppWidget系统中,从而使得AppWidget的AppWidgetHost端更新显示RemoteViews里承载的内容。
Remote端设置内容的过程,只是设置这些参数,而RemoteViews也只是用不同的RemoteViews.Action保存了这些参数。下文描述内部结构。
注意:这里的参数都是在Remote端的,在RemoteContext有效。
二、RemoteViews的内部结构
下图是RemoteViews相关的类图。
图二、RemoteViews类图
RemoteViews中保存Remote端的mPackage和mLayoutId;并用mActions:ArrayList<RemoteViews.Action>保存各种Action。
mPackage和mLayoutId是在构造RemoteViews时传进去的[上文图中的seq#1];
mActions是设置各种Remote端的响应Intent以及图形元素的时候,保存到相应的Action中,然后把Action加入到这里保存的;
mLayoutId里的各种控件通过setTextViewText()/ setImageViewResource() / setProgressBar(),等函数在remote端设置的。这些方法再调用setType() [Type可为Boolean / Byte / Short / Int/ Long / Char / String / Uri / Bitmap/ Bundle, etc]保存到ReflectionAction中。
SetOnClickPendingIntent是用来在local端用户点击viewId时,发出pendingIntent通知的。在SetOnClickPendingIntent的构造方法中保存viewId和pendingIntent。
ReflectionAction用来在local端显示时,通过Reflect机制执行获得Remote端资源的。在ReflectionAction的构造方法中保存viewId,methodName,type以及value。
ViewGroupAction和SetDrawableParameters也是RemoteViews.Action的子类,在这个场景中并未用到,基本原理相似,读者可自行分析。
三、显示RemoteViews内容——AppWidgetHostView
图一中为RemoteViews提供了内容之后,AppWidgetHost会通过IAppWidgetHost.updateAppWidget()被通知到Remote端有更新,本地端把RemoteViews提供的内容显示在AppWidgetHostView上。下面的顺序图描述这一过程。
图三、本地显示RemoteViews里的内容
图中:
1.获取RemoteViews里Remote端(AppWidgetProvider)的packageName和layoutId,通过packageName创建远端的context——remoteContext。[Seq#1~ 6]
2.通过RemoteViews的apply()方法,真正开始执行侦听Click操作的动作;通过远端Layout获得本地使用的View。[Seq#7~ 20]
2.1. 克隆一个本地的LayoutInflater;[Seq#8]
2.2. 用克隆出的LayoutInflater对remote端的layoutId执行Inflate,获得Layout所描述的View的Hierarchy,亦即后面用到的rootView;[Seq#9~ 10]
2.3. 对2.2中获得的view执行performApply。[Seq#11~ 19]
performApply()对所有mActions中的Action都执行apply()操作。这样,
2.3.1 对于setOnClickPendingIntent来说,[Seq#12~ 15]
- 通过rootView(2.2获得的Remote端的Layout的总的View)的findViewById(viewId),找到要侦听的View;[Seq#13]
- 对找到的要侦听的View设置Click的Listener。[Seq#14]
2.3.2对于ReflectionAction来说,[Seq#16~ 19]
- 通过rootView(2.2获得的Remote端的Layout的总的View)的findViewById(viewId),找到要设置内容的对象View;[Seq#17]
- 然后通过Reflect机制,执行View实现类里的方法(比如这里是setImageResource()),把相应的资源的Id设置给它. [Seq#18]
3.把获得的View加入到本地的View系统中。[Seq#21]
下面是ReflectionAction.apply()通过Reflect机制设置内容的代码片段(忽略了出错处理和非关键部分):
@Override
public void apply(View root) {
final View view = root.findViewById(viewId);
Class param = getParameterType(); // 通过this.type得到class:int.class
Class klass = view.getClass(); // 这个类在Remote的Layout中定义,这里为ImageView
Method method = klass.getMethod(this.methodName, param); // methodName是实现View类里的方法名:setImageResource(int)
try {
// 执行ImageView.setImageResource(value),value为resId
method.invoke(view, this.value);
} catch (Exception ex) {
throw new ActionException(ex);
}
}
四、总结
RemoteViews的内容提供方,提供显示的资源和侦听点击事件的Intent;
RemoteViews的本地显示方,通过RemoteViews获得View中的显示资源,并加入到本地的图形系统中,完成Remote资源的本地显示。
可进一步参考的文章
通过这一系列的其他文章,可获得与本文关联的信息:
Android AppWidget框架
AppWidget系统框架。
Android中选取并绑定AppWidget
Launcher发起选取过程,此文中描述选取并绑定的过程,可结合本文看完整的选取/绑定/加入显示系统的完整过程。
Android中AppWidget的分析与应用:AppWidgetProvider
是此文所描述的AppWidgetProvider创建RemoteViews,并设置了ImageViewResource和OnClickPendingIntent。
Android中Launcher对于AppWidget处理的分析:AppWidgetHost角色
此文描述的AppWidgetProvider提供的RemoteViews,在Launcher中开始真正应用RemoteViews的时机。
Android中RemoteViews的实现
本文。
分享到:
相关推荐
在“Android-remoteviews自定义通知适配android8.0okhttp断点下载”这个项目中,我们将深入探讨如何利用RemoteViews来创建自定义的通知,以及如何结合OkHttp实现Android 8.0(API级别26)及以上的断点下载功能。...
在"Android通过AIDL实现跨进程更新UI"的场景中,AIDL扮演了关键角色。 首先,我们需要创建一个AIDL文件,定义跨进程通信所需的接口。例如,我们可以创建一个名为`IAccessUI.aidl`的文件,其中包含一个方法,用于...
本篇文章将详细讲解如何在Android中实现一个横向滑动的GridView。 首先,了解GridView的基本概念。GridView继承自AbsListView,它会将数据集中的每个项显示为一个单元格,并且可以自动调整列的数量以适应屏幕宽度。...
在Android应用开发中,Widget是桌面小部件,它能让用户在主屏幕上与应用程序进行交互,而无需实际打开应用。Android Studio作为官方推荐的集成开发环境(IDE),为开发者提供了便捷的方式来创建和管理Widget。本教程...
- 在`AndroidManifest.xml`中注册Service,并设置权限`android:permission="android.permission.BIND_REMOTEVIEWS"`以防止未经授权的访问。 - 在Service中重写`onGetViewFactory`方法,返回一个实现了`...
在Android系统中,窗口小部件(AppWidget)是一种能够让用户在Home屏幕上获取应用信息和快捷操作的小部件,它也是实现Launcher功能的一部分。创建AppWidget主要涉及以下几个关键组件和概念: #### 1. ...
5.2 REMOTEVIEWS的局限 34 5.3 在WIDGET中显示图片 35 5.4 在ANDROIDMANIFEST.XML中进行权限声明 35 5.5 为WIDGET中的按钮设置ONCLICK事件 36 5.6 利用BUNDLE实现消息的传递 37 5.7 在APPWIDGETPROVIDER类中获取...
Android 平台天气预报 widget 的设计与实现需要涉及多种技术和知识,包括 Android 平台基础知识、网络接口和 Google API 的使用、RemoteViews 技术、Android 桌面小部件的设计和实现、天气预报软件的设计和实现、...
Android 平台天气预报 Widget 的设计与实现毕业论文 本文对基于 Android 平台的 Widget 开发技术进行了分析和研究,涵盖了 Android 开发必备基础知识、软件实现过程和关键技术等方面。 一、Android 开发环境 ...
"Android平台天气预报Widget的设计与实现" Android 平台天气预报 ...Android 平台天气预报 Widget 的设计与实现需要考虑到用户界面、数据存储和网络通信三个方面,并使用 RemoteViews、XML 解析和网络通信等关键技术。
本教程将引导你实现一个Android小窗口部件,特别是一个时钟部件,这对于熟悉Android开发和提高用户体验至关重要。 首先,我们需要创建一个新的Android项目,并确保在`AndroidManifest.xml`文件中声明支持App Widget...
在软件实现中,我们需要实现类的设计和实现。我们可以使用Java语言来实现类的设计和实现。类的设计和实现包括类的结构设计、类的方法设计、类的变量设计等。 9. 用户界面设计 在软件实现中,我们需要设计用户界面...
在Android平台上,实现天气预报功能通常涉及到多个技术层面和组件的整合。首先,我们要了解`Android Widget`,这是Android系统提供的一种小型应用组件,可以直接在用户的主屏幕上显示实时信息,如时间、天气、新闻等...
在Android开发中,Widget是应用在主屏幕上的小型UI组件,它们可以提供用户与应用程序的交互,无需打开应用本身。ListView是一种常用的布局管理器,它允许用户在一个滚动列表中显示大量数据。本教程将深入探讨如何在...
- 使用`RemoteViews`将这个布局应用到锁屏界面,`RemoteViews`允许你在系统的其他组件中展示自定义视图。 4. **权限申请**: - 需要申请`SYSTEM_ALERT_WINDOW`权限,允许在所有窗口之上显示内容,以便自定义锁屏...
在`PagerAdapter`的实现中,通常需要一个数据集(如ArrayList)来存储页面数据,然后在`InstantiateItem()`和`destroyItem()`方法中创建和销毁页面视图。在`JavaApk源码说明.txt`中,可能会详细解释如何将应用快捷...
本教程将深入探讨如何在Android中实现一个Widget闹钟功能,这对于Android开发者来说是一个非常实用的学习案例。 首先,我们需要了解Android的App Widget体系结构。App Widget是基于Android系统的RemoteViews类,它...
在本项目中,SDK中的Android Studio是主要的集成开发环境,用于编写源代码、配置项目结构和管理依赖。 2. **Widgets API**: Android Widgets是运行在用户主屏幕上的小型应用程序,类似于iOS的小部件。开发Widgets...