桌面widget详解(一)——基本demo构建

来源:互联网 发布:哈尔滨php在哪找工作 编辑:程序博客网 时间:2024/05/18 08:30

前言:这段时间真的是有点堕落了,没怎么看书,项目也做的乱七八糟,基本没什么长进,好像男人也有生理期一样,每个月总有那么几天提不起精神,等自己彻底感到罪恶感的时候再重新整装前行。这几天做桌面widget,现将所涉及内容整理分享给大家。写博客时间长了,觉得只是把学到的知识写出来才算是已经学会了的。这也算是强迫症了吧。今天头有点痛,心情不太好,就不多请废话了,估计也没几个人会看我的前言部分,哈哈。开整吧。

相关文章:

1、《桌面widget详解(一)——基本demo构建》
2、《桌面widget详解(二)—— 基本的与service通信》
3、《桌面widget详解(三)——桌面widget中的控件交互方法》
4、《桌面widget详解(四)——桌面音乐播放器(实战)》


一、概述

App Widget是应用程序窗口小部件(Widget)是微型的应用程序视图,它可以被嵌入到其它应用程序中(比如桌面)并接收周期性的更新。你可以通过一个App Widget Provider来发布一个Widget。官方文档地址:《App Widgets》

这里涉及到两个方面的内容:AppWidgetProvider类和appwidget-provider标签;

1、appwidget-provider标签:

这个玩意是用来定义桌面widget的大小,初始状态等等信息的,它的位置应该放在res/xml文件夹下,具体的xml参数如下:

  • android:minWidth : 最小宽度
  • android:minHeight : 最小高度
  • android:updatePeriodMillis : 更新widget的时间间隔(ms),"86400000"为1个小时
  • android:previewImage : 预览图片
  • android:initialLayout : 加载到桌面时对应的布局文件
  • android:resizeMode : widget可以被拉伸的方向。horizontal表示可以水平拉伸,vertical表示可以竖直拉伸
  • android:widgetCategory : widget可以被显示的位置。home_screen表示可以将widget添加到桌面,keyguard表示widget可以被添加到锁屏界面。
  • android:initialKeyguardLayout : 加载到锁屏界面时对应的布局文件

至于具体怎么用,等下实战的时候会讲。

2、AppWidgetProvider类:

上面我们通过appwidget-provider标签就可以得到初始化的布局,视图等,但我们的widget要实时更新怎么办,要响应用户操作怎么办,这就需要额外的类来辅助处理了,这个类就是AppWidgetProvider。

由于AppWidgetProvider要接收到当前widget的状态(是否被添加,是否被删除等),所以要接收通知,必然是派生自BroadcastReceiver。

AppWidgetProvider中的广播处理函数如下:(根据不同的使用情况,重写不同的函数)

onUpdate():

3种情况下会调用OnUpdate()。onUpdate()是在main线程中进行,因此如果处理需要花费时间多于10秒,处理应在service中完成。(第二篇会讲为什么还要有service)
(1)在时间间隔到时调用,时间间隔在widget定义的android:updatePeriodMillis中设置; 
(2)用户拖拽到主页,widget实例生成。无论有没有设置Configure activity,我们在Android4.4的测试中,当用户拖拽图片至主页时,widget实例生成,会触发onUpdate(),然后再显示activity(如果有)。这点和资料说的不一样,资料认为如果设置了Configure acitivity,就不会在一开始调用onUpdate(),而实验显示当实例生成(包括创建和重启时恢复),都会先调用onUpate()。在本例,由于此时在preference尚未有相关数据,创建实例时不能有效进行数据设置。
(3)机器重启,实例在主页上显示,会再次调用onUpdate()

onDeleted(Context, int[]):

当 widget 被删除时被触发。

onEnabled(Context):

当第1个 widget 的实例被创建时触发。也就是说,如果用户对同一个 widget 增加了两次(两个实例),那么onEnabled()只会在第一次增加widget时触发。

onDisabled(Context):

当最后1个 widget 的实例被删除时触发。

onReceive(Context, Intent):

在接收到广播时,调用。

二、实战

先看一下显示效果:


就这么一个桌面widget,一个音乐播放器,这一篇只是显示出来,后面我们会慢慢完善它的功能。

1、appwidget-provider及布局文件

前面我们讲过,appwidget-provider提供了桌面widget的初始化显示状态、默认图标、大小等功能,但它必须放在res/xml文件夹下,看看这里的代码:

[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:initialLayout="@layout/example_appwidget"  
  3.     android:minHeight="60dp"  
  4.     android:minWidth="180dp"  
  5.     android:previewImage="@drawable/preview"  
  6.     android:resizeMode="horizontal|vertical"  
  7.     android:widgetCategory="home_screen|keyguard" >  
  8.   
  9. </appwidget-provider>  
这里有几个参数:

prviewImage:就是添加桌面控件时,我们的控件在列表中的显示状态,如下图所示,下面这个丑娃娃就是我们的显示图标……

android:initialLayout="@layout/example_appwidget":这个就是指定初始化显示时,应该显示的布局;

下面看看这个布局文件:example_appwidget.xml

[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="#33000000"  
  6.     android:gravity="center"  
  7.     android:orientation="horizontal" >  
  8.       
  9.     <TextView   
  10.         android:layout_width="wrap_content"  
  11.         android:layout_height="wrap_content"  
  12.         android:layout_marginRight="8dip"  
  13.         android:background="@drawable/car_musiccard_up"/>  
  14.       
  15.     <TextView   
  16.         android:layout_width="wrap_content"  
  17.         android:layout_height="wrap_content"  
  18.         android:layout_marginRight="8dip"  
  19.         android:background="@drawable/car_musiccard_play"/>  
  20.       
  21.     <TextView   
  22.         android:layout_width="wrap_content"  
  23.         android:layout_height="wrap_content"  
  24.         android:background="@drawable/car_musiccard_down"/>  
  25.   
  26. </LinearLayout>  
这个布局就是最上头显示出来的那个播放器的布局。

2、ExampleAppWidgetProvider extends AppWidgetProvider

在布局成功之后,下面就是根据通知实现逻辑了,这篇我们只接收通知,逻辑下篇再说。首先新建一个类ExampleAppWidgetProvider,将其派生自AppWidgetProvider;然后就会有下面的代码:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class ExampleAppWidgetProvider extends AppWidgetProvider {  
  2.   
  3.      /* 
  4.       * 在3种情况下会调用OnUpdate()。onUpdate()是在main线程中进行,因此如果处理需要花费时间多于10秒,处理应在service中完成。 
  5.       *(1)在时间间隔到时调用,时间间隔在widget定义的android:updatePeriodMillis中设置;  
  6.       *(2)用户拖拽到主页,widget实例生成。无论有没有设置Configure activity,我们在Android4.4的测试中,当用户拖拽图片至主页时,widget实例生成,会触发onUpdate(),然后再显示activity(如果有)。这点和资料说的不一样,资料认为如果设置了Configure acitivity,就不会在一开始调用onUpdate(),而实验显示当实例生成(包括创建和重启时恢复),都会先调用onUpate()。在本例,由于此时在preference尚未有相关数据,创建实例时不能有效进行数据设置。 
  7.       *(3)机器重启,实例在主页上显示,会再次调用onUpdate() 
  8.       */   
  9.     @Override  
  10.     public void onUpdate(Context context, AppWidgetManager appWidgetManager,  
  11.             int[] appWidgetIds) {  
  12.   
  13.         super.onUpdate(context, appWidgetManager, appWidgetIds);  
  14.     }  
  15.   
  16.     // widget被删除时调用  
  17.     @Override  
  18.     public void onDeleted(Context context, int[] appWidgetIds) {  
  19.         Log.d(TAG, "onDeleted(): appWidgetIds.length=" + appWidgetIds.length);  
  20.   
  21.         super.onDeleted(context, appWidgetIds);  
  22.     }  
  23.   
  24.     // 最后一个widget被删除时调用  
  25.     @Override  
  26.     public void onDisabled(Context context) {  
  27.         Log.d(TAG, "onDisabled");  
  28.   
  29.         super.onDisabled(context);  
  30.     }  
  31.   
  32.     // 第一个widget被创建时调用  
  33.     @Override  
  34.     public void onEnabled(Context context) {  
  35.   
  36.         super.onEnabled(context);  
  37.     }  
  38.   
  39.     // 接收广播的回调函数  
  40.     @Override  
  41.     public void onReceive(Context context, Intent intent) {  
  42.   
  43.         super.onReceive(context, intent);  
  44.     }  
  45. }  

这里不是继承接口,这几个函数并不是需要全部重写的,根据需要,要用到哪个可以重写哪个。

3、注册ExampleAppWidgetProvider

前面我们讲到AppWidgetProvider派生自BroadcastReciver,所以要提前注册,有关BroadcastReciver的注册有两种方法,静态注册和动态注册,因为这里要接收来自的消息,而且在程序启动时就开始自动监听,所以,这里需要静态注册。有关BroadcastReciver的问题,可以参看《BroadcastReceiver详解》

[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <!-- 声明widget对应的AppWidgetProvider -->  
  2. <receiver android:name=".ExampleAppWidgetProvider" >  
  3.     <intent-filter>  
  4.     <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />  
  5.     </intent-filter>  
  6.     <meta-data android:name="android.appwidget.provider"  
  7.     android:resource="@xml/example_appwidget_info" />  
  8. </receiver>  
(1)接收的action定义为:"android.appwidget.action.APPWIDGET_UPDATE"这表明接收系统发来的有关这个app的所有widget的消息(主要是增加、删除)。

(2)<meta-data> 指定了 AppWidgetProviderInfo 对应的资源文件
android:name -- 指定metadata名,指定为android.appwidget.provider表示这个data中的数据是AppWidgetProviderInfo 类型的
android:resource -- 指定 AppWidgetProviderInfo 对应的资源路径。即,xml/example_appwidget_info.xml。

三、可能出现的错误:

1、有关布局错误

在构造Widget布局时,App Widget支持的布局和控件非常有限,有如下几个:

App Widget支持的布局:

  •   FrameLayout
  •   LinearLayout
  •   RelativeLayout
  •   GridLayout

 App Widget支持的控件:

  •   AnalogClock
  •   Button            
  •   Chronometer
  •   ImageButton
  •   ImageView
  •   ProgressBar
  •   TextView
  •   ViewFlipper
  •   ListView
  •   GridView
  •   StackView
  •   AdapterViewFlipper

除此之外的所有控件(包括自定义控件)都无法显示,无法显示时,添加出来的widget会显示“加载布局出错”

2、appwidget-provider出现错误

如果appwidget-provider页面出现错误提示:error: No resource identifier found for attribute 'widgetCategory' in package 'android'

这是由于build target应该在17以上,有两种方法解决:

方法1:找到工程中的project.properties文件将target=android-14改为target=android-17   

方法2:工程上右键-》properties  选择Android,将Project Build Target改为17或以上,如图:(改完之后rebuild一下工程)





如果我的文章有帮到你,记得加关注哦!

源码来啦,本文所涉及源码下载地址:http://download.csdn.net/detail/harvic880925/8193853

请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/41445407  谢谢!

0 0