当前位置: 代码迷 >> Android >> Android开发指南-窗口小元件(App Widgets)
  详细解决方案

Android开发指南-窗口小元件(App Widgets)

热度:254   发布时间:2016-05-01 14:02:26.0
Android开发指南-窗口小部件(App Widgets)
应用程序窗口小部件(Widget)是微小的应用程序视图,可以被嵌入到其它应用程序中(比如桌面)并接收周期性的更新。你可以通过一个App Widget provider来发布一个Widget。可以容纳其它App Widget的应用程序组件被称为App Widget宿主。

为了创建一个App Widget,你需要下面这些:

AppWidgetProviderInfo 对象
描述一个App Widget元数据,比如App Widget的布局,更新频率,以及AppWidgetProvider 类。这应该在XML里定义。

AppWidgetProvider 类的实现
定义基本方法以允许你编程来和App Widget连接,这基于广播事件。通过它,当这个App Widget被更新,启用,禁用和删除的时候,你都将接收到广播通知.


视图布局
为这个App Widget定义初始布局,在XML中。
另外,你可以实现一个App Widget配置活动。这是一个可选的活动Activity,当用户添加App Widget时加载并允许他在创建时来修改App Widget的设置。


在清单中声明一个应用小部件
首先,在应用程序AndroidManifest.xml文件中声明AppWidgetProvider 类,比如:

<receiver android:name="ExampleAppWidgetProvider" >
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data android:name="android.appwidget.provider"
               android:resource="@xml/example_appwidget_info < src="http://hi.images.csdn.net/js/blog/tiny_mce/themes/advanced/langs/zh.js" type="text/javascript"> < src="http://hi.images.csdn.net/js/blog/tiny_mce/plugins/syntaxhl/langs/zh.js" type="text/javascript">"
/>
</receiver>

<receiver>元素需要android:name属性,它指定了App Widget使用的AppWidgetProvider 。
<intent-filter> 元素必须包括一个含有android:name属性的<action>元素。该元素指定AppWidgetProvider接受ACTION_APPWIDGET_UPDATE 广播。这是唯一你必须显式声明的广播。当需要的时候,AppWidgetManager 会自动发送所有其他App Widget广播给AppWidgetProvider。

<meta-data> 元素指定了AppWidgetProviderInfo 资源并需要以下属性:
·         android:name – 指定元数据名称。
·         android:resource – 指定AppWidgetProviderInfo 资源路径。

增加AppWidgetProviderInfo元数据
AppWidgetProviderInfo定义一个App Widget的基本特性,比如最小布局尺寸,初始布局资源,刷新频率,以及(可选的)创建时加载的一个配置活动。使用单独的一个<appwidget-provider>元素在XML资源里定义AppWidgetProviderInfo 对象并保存到项目的res/xml/目录下。

比如:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="294dp" <!-- density-independent pixels -->
    android:minHeight="72dp"
    android:updatePeriodMillis="86400000" <!-- once per day -->
    android:initialLayout="@layout/example_appwidget"
    android:configure="com.example.android.ExampleAppWidgetConfigure" >
</appwidget-provider>

下面是<appwidget-provider>属性的总结:
.
minWidth 和minHeight 属性的值指定了这个App Widget布局需要的最小区域。
缺省的App Widgets所在窗口的桌面位置基于有确切高度和宽度的单元网格。如果App Widget的最小长宽和这些网格单元的尺寸不匹配,那么这个App Widget将收缩到最接近的单元尺寸。(参见App Widget Design Guidelines 以获取更多关于桌面单元尺寸的信息)
因为桌面布局方向(由此,单元的尺寸)可以变化,按照拇指规则,你应该假设最坏情况单元尺寸是74像素高和宽。不过,你必须从最后的尺寸中减去2以把像素计算过程中产生的任何的整数舍入误差考虑在内。要找到像素密度无关的最小宽度和高度,使用这个公式:
(number of cells * 74) - 2
遵循这个公式,你应该使用72dp为每一个单元高度,294dp为四个单元宽度。

.
updatePerdiodMillis 属性定义了App Widget框架调用onUpdate()方法来从AppWidgetProvider请求一次更新的频度。实际更新时间并不那么精确,而且我们建议更新频率越低越好-也许每小时不超过一次以节省电源。你也许还会允许用户在配置中调整这个频率-一些人可能想每15分钟一次股票报价,或者一天只要四次。

.
initialLayout属性指向定义App Widget布局的资源。

.
configure属性定义了Activity ,当用户添加App Widget时启动,以为他或她配置App Widget特性。这是可选的(阅读下面的Creating an App Widget Configuration Activity)。
参见AppWidgetProviderInfo 类以获取更多可以被<appwidget-provider>元素接受的属性信息。


创建App Widget布局
你必须在XML中为你的App Widget定义一个初始布局并保存到项目的res/layout/ 目录下。你可以使用如下所列的视图对象来设计你的App Widget,但是在此之前,请先阅读并理解App Widget Design Guidelines.

如果你熟悉在XML中声明布局,那么创建这个App Widget布局是很简单的。但是,你必须意识到那个App Widget布局是基于RemoteViews, 这并不支持所有类型的布局或视图小部件。

一个RemoteViews对象(以及,相应的,一个App Widget)可以支持下面这个布局类:
·         FrameLayout
·         LinearLayout
·         RelativeLayout
以及下面的小部件类:
·         AnalogClock
·         Button
·         Chronometer
·         ImageButton
·         ImageView
·         ProgressBar
·         TextView
不支持这些类的派生。


使用AppWidgetProvider类

你必须通过在清单文件中使用<receiver>元素来声明你的AppWidgetProvider 类实现为一个广播接收器(参见上面的Declaring an App Widget in the Manifest)。

AppWidgetProvider 类扩展BroadcastReceiver 为一个简便类来处理App Widget广播。AppWidgetProvider只接收和这个App Widget相关的事件广播,比如这个App Widget被更新,删除,启用,以及禁用。当这些广播事件发生时,AppWidgetProvider 将接收到下面的方法调用:

onUpdate(Context, AppWidgetManager, int[])

这个方法调用来间隔性的更新App Widget,间隔时间用AppWidgetProviderInfo 里的updatePeriodMillis属性定义(参见添加AppWidgetProviderInfo元数据)。这个方法也会在用户添加App Widget时被调用,因此它应该执行基础的设置,比如为视图定义事件处理器并启动一个临时的服务Service,如果需要的话。但是,如果你已经声明了一个配置活动,这个方法在用户添加App Widget时将不会被调用,而只在后续更新时被调用。配置活动应该在配置完成时负责执行第一次更新。(参见下面的创建一个App Widget配置活动Creating an App Widget Configuration Activity。)

onDeleted(Context, int[])

当App Widget从宿主中删除时被调用。

onEnabled(Context)

当一个App Widget实例第一次创建时被调用。比如,如果用户添加两个你的App Widget实例,只在第一次被调用。如果你需要打开一个新的数据库或者执行其他对于所有的App Widget实例只需要发生一次的设置,那么这里是完成这个工作的好地方。

onDisabled(Context)

当你的App Widget的最后一个实例被从宿主中删除时被调用。你应该在onEnabled(Context)中做一些清理工作,比如删除一个临时的数据库。

onReceive(Context, Intent)

这个接收到每个广播时都会被调用,而且在上面的回调函数之前。你通常不需要实现这个方法,因为缺省的AppWidgetProvider 实现过滤所有App Widget 广播并恰当的调用上述方法。

注意: 在Android 1.5中, 有一个已知问题,onDeleted()方法在该调用时不被调用。为了规避这个问题,你可以像Group post中描述的那样实现onReceive() 来接收这个onDeleted()回调。

最重要的AppWidgetProvider 回调函数是onUpdated(), 因为它是在每个App Widget添加进宿主时被调用的(除非你使用一个配置活动)。如果你的App Widget 要接受任何用户交互事件,那么你需要在这个回调函数中注册事件处理器。如果你的App Widget不创建临时文件或数据库,或者执行其它需要清理的工作,那么onUpdated() 可能是你需要定义的唯一的回调函数。比如,如果你想要一个带一个按钮的App Widget,当点击时启动一个活动,你可以使用下面的AppWidgetProvider实现:

public class ExampleAppWidgetProvider extends AppWidgetProvider {
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        final int N = appWidgetIds.length;
        // Perform this loop procedure for each App Widget that belongs to this provider
        for (int i=0; i<N; i++) {
            int appWidgetId = appWidgetIds[i];
            // Create an Intent to launch ExampleActivity
            Intent intent = new Intent(context, ExampleActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
            // Get the layout for the App Widget and attach an on-click listener to the button
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
            views.setOnClickPendingIntent(R.id.button, pendingIntent);
            // Tell the AppWidgetManager to perform an update on the current App Widget
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }
    }
}

这个AppWidgetProvider 仅定义了onUpdated() 方法,为了定义一个PendingIntent,来启动一个活动并使用setOnClickPendingIntent(int, PendingIntent)方法把它附着到这个App Widget的按钮上。注意它包含了一个遍历appWidgetIds中所有项的循环,这是一个IDs数组,每个ID用来标识由这个Provider创建的一个App Widget。这样,如果用户创建多于一个这个App Widget的实例,那么它们将被同步更新。不过,对于所有的App Widget实例,只有一个updatePeriodMillis 时间表被管理。比如,如果这个更新时间表被定义为每隔两个小时,而且App Widget的第二个实例是在第一个后面一小时添加的,那么它们将按照第一个所定义的周期来更新而第二个被忽略(它们将都是每2个小时进行更新,而不是每小时)。

注意: 因为这个AppWidgetProvider 是一个广播接收器BroadcastReceiver,不能保证你的进程在回调函数返回后仍然继续运行(参见应用程序基础>广播接收器的生命周期Application Fundamentals > Broadcast Receiver Lifecycle以获取更多信息)。如果你的App Widget设置过程能持续几秒钟(也许当执行网页请求时)而且你要求你的进程继续,考虑在onUpdated()方法里启动一个服务Service 。从这个服务里,你可以执行自己的App Widget更新,而不必担心AppWidgetProvider 由于一个应用程序无响应错误Application Not Responding (ANR)而关闭。参见Wiktionary sample's AppWidgetProvider,这是个App Widget运行一个Service的例子。

同样参见ExampleAppWidgetProvider.java 例子类。
接收App Widget广播意图
AppWidgetProvider 只是一个简便类。如果你想直接接收App Widget 广播,你可以实现自己的BroadcastReceiver 或者重写 onReceive(Context, Intent) 回调函数。你需要注意的4个意图如下:
·         ACTION_APPWIDGET_UPDATE
·         ACTION_APPWIDGET_DELETED
·         ACTION_APPWIDGET_ENABLED
·         ACTION_APPWIDGET_DISABLED

创建一个App Widget 配置活动
如果你想让用户在添加一个新的App Widget时调整设置,你可以创建一个App Widget配置活动。这个活动将被App Widget宿主自动启动并允许用户在创建时配置可用的设置,比如App Widget颜色,尺寸,更新周期或者其它功能设置。
这个配置活动应该在Android清单文件中声明为一个通用活动。不过,它将被通过ACTION_APPWIDGET_CONFIGURE活动而被App Widget宿主启动,因此这个活动需要接受这个意图。比如:
<activity android:name=".ExampleAppWidgetConfigure">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
    </intent-filter>
</activity>

同样的,活动必须在AppWidgetProviderInfo XML 文件中声明,通过android:configure属性(参见上面的添加AppWidgetProviderInfo元数据Adding the AppWidgetProviderInfo Metadata)。比如,配置活动可以声明如下:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:configure="com.example.android.ExampleAppWidgetConfigure"
    ... >
</appwidget-provider>

注意这个活动是用全名声明的,因为它将从你的程序包外被引用。

这就是所有关于配置活动你一开始需要了解的。现在你需要一个真实的活动。这儿就有,不过,当你实现这个活动时记住两件重要的事情:

?  App Widget 宿主调用配置活动而且配置活动应该总是返回一个结果.这个结果应该包含这个通过启动该活动的意图传递的App Widget ID(以EXTRA_APPWIDGET_ID保存在意图的附加段Intent extras中)

?  当这个 App Widget 被创建时将不会调用onUpdate() 方法(当一个配置活动启动时,系统将不会发送ACTION_APPWIDGET_UPDATE广播).配置活动应该在 App Widget 第一次被创建时负责从AppWidgetManager请求一个更新.不过, onUpdate() 将在后续更新中被调用-只忽略第一次.



参见下面章节的代码片断,该示例说明了如何从配置中返回一个结果并更新这个App Widget.

从配置活动中更新一个App Widget
当一个App Widget使用一个配置活动,那么当配置结束时,就应该由这个活动来更新这个App Widget.你可以直接AppWidgetManager里请求一个更新来这么做.

下面是恰当的更新App Widget 以及关闭配置活动这个过程的一个概要描述:

首先,从启动这个活动的意图中获取App Widget ID:
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
    mAppWidgetId = extras.getInt(
            AppWidgetManager.EXTRA_APPWIDGET_ID,
            AppWidgetManager.INVALID_APPWIDGET_ID);
}
实施你的App Widget 配置。
当配置完成后,通过调用getInstance(Context)获取一个AppWidgetManager实例:
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
以一个RemoteViews布局调用updateAppWidget(int, RemoteViews)更新App Widget:
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget);
appWidgetManager.updateAppWidget(mAppWidgetId, views);
最后,创建返回意图,设置活动结果,并结束这个活动:
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();

提示: 当你的配置活动第一次打开时,设置活动结果为RESULT_CANCELED。这样,如果用户在结束之前从活动外返回,这个App Widget 宿主会接收到配置取消通知而不会添加这个App Widget。

参见ApiDemos里面的ExampleAppWidgetConfigure.java 例子。

--------------------------------------------------------------------------

对于什么是Widget ,以及Android的Widget大家通过以前的文章基本上已经了解了。而本次调查哦报告将带大家更好得认识Android的Widget。让大家更加熟练Widget的开发。

那么刚开始,希望大家回顾一下第四期的第一篇文章《让我们再次从Widget的Helloworld开始》。

当时我将代码全部贴出,我们可以看到这个Widget非常简单,他的结构就是Mainfest注册文件,一些布局信息,再加上最后一个集成了appWidget的类,类中东西也非常简单,就是一个RemoteViews!

而对于Widget来说,RemoteViews就是Widget表现层的最核心的要素!
也因此,Android平台的Widget表现力就这样被判了重刑。Widget为什么弱,到底弱到了什么程度,我们接下来通过对SDK的分析来继续。

2.探究Appwidget还有Widget之间的关系
当下载好了Android的SDK后,将你的路径中的这个地址/android-sdk-windows-1.5_r2/docs/index.html,复制到你的浏览器,或者直接打开就可以进入离线版的SDK了。
然后我们点击Reference,看到左边的类的列表,我们就会看到Appwidget这个就是我们要来分析的。
这里我想特别说明一下,虽然都是Widget,但是在Android平台却存在两种不同的Widget
在SDK目录中,我们也可以看到这里有一个android.appwidget,还有一个android.widget。前者就是我们本期的主题widget。而后者则是小部件的意思,我们可以打开ImageView还有textview的SDK中来看,会发现,他们全都是继承这个类。

其实我们app中的每一个UI层的表现元素,都是以widget的名义存在的。
但是后来Google发现当初这样做不太好,因为大家公认的widget发展越来越好,可是widget名称已经被占用了,所以只能做一个Appwidget了。

所以在你看SDK并且希望将相关的内容应用到你自己的程序中的时候一定要分析清楚,也许平时可以直接用Widget指代我们所说的appWidget,但是在SDK中,两者必须区分开。
那我们打开Appwidget以后,我们会出现
?AppWidgetHost
?AppWidgetHostView
?AppWidgetManager
?AppWidgetProvider
?AppWidgetProviderInfo

这几个类中,我们最常用的是AppwidgetProvider。这各类提供了我们最基本的一个widget。AppwidgetHost 和AppwidgetHostView可以帮助我们来承载Appwidget 。进入程序管理,我们可以发现,Home其实是以一个程序的形式出现,当然这个是不可卸载的。而我们普通点的Widget都是以Home为依托的,Home便使用了AppwidgetHost这个类。那么我们的自己的Activity也可以添加Widget,在你的程序内部只要使用这个Host,然后就可以再你的Activity挂载你需要的appwidget了。

而AppwidgetProviderinfo则可以定义widget的信息,比如说appwidget的大小等等,当然我们通过xml文件也可以达到同样的效果。

另一个AppwidgetManager可以让我们用外部方法来管理Appwidget。我们最常用的就是使用AppwidgetManager来进行appwidget的更新。

最后一个AppwidgetProvider则是我们最重要的类了,因为他决定了我们的widget可以达到什么样的表现效果。

因为这些内容SDK中都有,而且本篇的重点并不是简单罗列SDK,如果大家有什么方法的需要,最有效的方法还是去翻SDK中的相关内容。

所以呢,大家大部分人所说的Widget都是指的是Appwidget,因为大家都默认了,我们也不用关心具体的名称使用了。当然本篇为了区别,当然还是会使用Appwidget指代当前的Widget。

3. Appwidget贫弱的真正罪魁祸首
而我们现在着重分析一下 Appwidgetprovider这各类。首先打开SDK,我们在最左上角的地方就可以看到这个类继承与BroadcastReceiver。BroadcastReceiver是Android平台接受广播的方法。那就是说什么呢?

也许Google一开始就没想过让appWidget有什么表现力,限制他做输出,继承BroadcastReceiver更加有利于Appwidget进行数据的接受。
也许有朋友会说了,这下好了啊,甚至都不用引入了BroadcastReceiver了,那你就大错特错了。因为Appwidget继承这个只是为了给自己图方便。

他是Appwidget,他不是我们平常所用的Activity。
也就是说,很多适用于Activity的东西,Appwidget绝大多数都无法使用。这是真的,就拿一点简单的来说吧每次我们从app引入东西,我们最常用的获取控件Id的方式,就是findviewbyid。

而我们可以很明确的告诉大家,Appwidget不支持这种方法!而且这个方法很重要,没了他很多东西基本上就类似判了死刑。

这里首先来探讨一下控件与我们后台代码之间的关系
~~~~~~~~~~~~~~~
可能有些朋友会认为,起码之前我是这么认为的。就是所有的控件都是被后台代码获取,然后后台代码来进行对屏幕的输出。但实际并不是这样的,只要后台代码声明了布局中的控件,只告诉屏幕有这个东西,但是如何控制它则是另外一种方法。
这样来说吧!假如说Android是一个大饭店的老板,我们的UI控件相当于老板点的菜。 我们的后台代码则像是服务生。
有的时候,我们之需要让服务生通知到老板要这个菜就可以了,然后菜就直接被送到了。这里服务生可以不对这些菜品做任何变动,老板也满意。也就是之前所说的直接声明控件。

但有的时候,为了让老板满意,服务生必须对菜品进行控制,比如过热的菜需要冷却一下,不太好的东西要去掉。等等。但是服务生怎么知道是那些菜品呢?这里就需要一个findviewbyid了。

他就像是超市中的读取条形码的那个设备。我们的动画效果,图片切换,等等都是通过这个来做到的。
而appWidget很明确不支持这个方法。就像是这个老板很苛刻,如果菜品不好,他也不愿让服务生来加一些作料进行调整。
~~~~~~~~~~~~~~~~~~
在Appwidget上,你可以让一个 ImageView显示出来,但是你没办法控制它。
Android的Appwidget简直就和一个聋子一样,改变它的唯一方法,就是更新整个Widget,这个类似于让厨房重新做菜
我真感觉Android真的是给Widget安了只猪耳朵(Android谐音)!
不支持findviewbyid,这让很多特效就这样和你的widget,say goodbye了

当然我和在做我们的Widget的时候,也不甘心与就那么放纵大好的Animation效果不用,但是试了很多的方法,但是最后除了惨痛的教训什么都没有获得!

Appwidget最支持什么呢?是RemoteViews,这个是Appwidget支持最好的一个控件了,所以你无论如何得保证你的Appwidget中至少有一个RemoteViews。
RemoteViews可以支持你将Widget自由拖动。

4.不要对UI说无所谓
也许有朋友会对此不屑一顾,但是我想特别声明一下,如果手机平台不去关注UI,不去考虑表现,他还应该考虑些什么呢?界面层是手机最总要的一层,手机屏幕狭小,不像PC。所以一个明了的界面会给你的app带来和那的提升。
现在的手机很想当年的PC,性能已经不算数特别大的问题了。这是事实,而手机的品种越来越多,而现在的消费者角度,普通的消费者(除了那些技术出身的发烧友),他们才不会管你是用了什么技术、什么系统。
他们只在乎自己的使用体验。
如果一个手机app,功能再强大,没有一个号的UI,没有一个强大的表现层,用户还是不买账的。那些山寨系统能获得消费者的青睐也是抓住了消费者的这一心里

5. Widget的救命稻草 Service
Appwidget的贫弱 不仅仅是在已经被我们无奈的布局上。appWidget还被Android做了很多限制,甚至Widget不能调用线程!反正我们一直没能成功调用线程。
如果你要在AppwidgetProvider里面写东西,你所能调用的资源相当有限。
我感觉apwidget像是寄生在Home程序中的,所以也受相应的很多限制。我们的经验告诉我们,除了在RemoteViews中方一些固定的东西,不要指望你的widget能自己做什么,最好的方法是让他当一个被动接受的傀儡。

既然Widget成了傀儡了,那么我们就应该把更多的事务交给别人。Service就是个很好的选择,他可以让Widget重焕生机。
其实Service 是Activity还有Appwidget都可以调用的东西。而且他也有很高的灵活度。
而且更加重要的是,你甚至可以存在于你的Widget里面作为一个内部类。因为Service占用了进程,他可以完成很多Widget无法做到的事情。
Service在做好了自己的工作以后,可以用广播的形式发送给Widget,因为appWidgetManager可以在Widget之外调用,那么我们完全可以在Service里面控制Widget的更新。
Widget的接受方法解释使用BroadcastReceiver原声的继承方法,在本篇调用系统时钟那个例子就很好的讲述了这个方法

6. 从Widget逃出来的信息
如果什么事情都让别人来做,也不好,appwidget虽然被限制很多,但是我们还是有办法从Widget分出点东西来。RemoteViews给我们提供了原生的 setOnClickPendingIntent方法。
PendingIntent这个想必大家都应该很清楚。因为RemoteViews没有按键时间,所以这个方法就可以出发PendingIntent
而Widget的点击事件很有特点,之前点击我们Activity的控件,会有专门的按键监听,他会根据案件的ID,来控制按键范围,比如你的ImageViewButton的id 是 R.id.imagebutton。
在下面你只要引入将这个id,按钮事件发出只会在你点击这个区域以后才会发生。

下面这个例子就是点击整个Widget的时候会触发时间。
                 updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_word);
                 updateViews.setOnClickPendingIntent(R.id.widget, pendingIntent);
PendingIntent被出发后,发出信息,所以送出送出的消息全部在Intent里面。

至于Android上的传值,大家可以去这个地址来学习一下。
http://www.eoeandroid.com/viewthread.php?tid=967&extra=page%3D1

我觉得我讲的还算是很明白的。
PendingIntent提供了三种方法,一个事getActivity()另一个是getBroadcast()最后一个事getService()
从字面上我们就可以看出这三种方法是启动一个新的Activity、发送一个广播、还有启动一个服务。getService启动的服务如果已经启动了,执行这个语句将会保持服务的运行。
一些具体编程细节问题,本片的 AppWidget 编程实战三部曲已经给打击很明确的答案了。这里不再编码赘述。
源自:http://www.cnblogs.com/pcedb0189/archive/2009/06.html


Android Widget搭建过程
Android平台下Widget的搭建过程为:
1.在res/layout下创建Widget的布局文件:digitalclock.xml
代码
<?xml version="1.0" encoding="UTF-8"?>
<TextView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/time"
    android:textSize="45px"
    android:scrollX="30px"
    android:scrollY="30px"
    android:textStyle="bold"
    android:textColor="#ff000000"
    android:background="@drawable/bg"
    />
2.在res/xml下创建Widget的描述文件:est_appwidget.xml
代码
<?xml version="1.0" encoding="UTF-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="186dip"
    android:minHeight="212dip"
    android:updatePeriodMillis="1000"
    android:initialLayout="@layout/digitalclock"/>
3. 从AppWidgetProvider继承一个类(ESTTime),重写其虚方法
代码
package com.android.test.esttime;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.text.format.Time;
import android.widget.RemoteViews;
public class ESTTime extends AppWidgetProvider {
    /** Called when the activity is first created. */
    @Override
    public void onUpdate(Context context,AppWidgetManager appWidgetManager,int[] appWidgetIds ){
        context.startService(new Intent(context,UpdateService.class));       
    }
   
  //Service类
    public static class UpdateService extends Service {
        @Override
        public void onStart(Intent intent,int startId){
            Time estTime = new Time("EST");
            estTime.setToNow();
            RemoteViews updateViews =
                new RemoteViews(getPackageName(),
                        R.layout.digitalclock);
            updateViews.setTextViewText(R.id.time, estTime.format("%H:%M"));
           
            ComponentName thisWidget = new ComponentName(this,ESTTime.class);
           
            AppWidgetManager manager = AppWidgetManager.getInstance(this);
            manager.updateAppWidget(thisWidget, updateViews);
        }

        @Override
        public IBinder onBind(Intent intent) {
            // TODO Auto-generated method stub
            return null;
        }
    }
}
4.在AndroidManifest.xml中注册本Widget
代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.test.esttime"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <receiver android:name=".ESTTime"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
            android:resource="@xml/est_appwidget"/>           
        </receiver>
        <service android:name=".ESTTime$UpdateService"/>
    </application>
    <uses-sdk android:minSdkVersion="3" />
</manifest>
最后,编译运行。这样在Home上长按弹出的Widget列表中就有新创建的Weiget了 。
  相关解决方案