从零开始创建一个Android主屏幕Widget

news/2025/2/12 8:17:35/
IT168技术开发频道
IT168首页 >  技术开发 >  技术开发技术 > 正文

从零开始创建一个Android主屏幕Widget

0条评论
2009-12-23 07:00    IT168网站原创  作者: IT168 黄永兵 编辑:  景保玉

  【IT168技术】当最基本的控件,如Clock和Picture Frame Home Screen ,随第一款Android手机的发布后,Android用户就开始尝试编写各种应用Widget(小工具)了,随着Widget API的公开,为开发人员带来了全新有趣的开发模式,除了传统的电话应用外,还可以做其它方面的应用开发。开发人员可以使用Widget API(包含在Android 1.5中,最新版本已经到Android 2.0了)创建简单的控件,然后在新的Widget中显示和使用这些控件。

  本文向你介绍如何从零开始创建一个主屏幕应用Widget,通过使用AlarmManager接口,以用户设定的时间间隔更新图片。你将看到如何创建一个Widget,以及如何随机地从一组图片中选择一张图片显示,根据用户设定的时间间隔周期性改变显示的图片。

  创建一个简单的Widget包括以下几个步骤:

  1、创建一个RemoteView,由它为Widget提供用户界面;

  2、将RemoteView绑定一个Activity(行为)实现AppWidgetProvider接口;

  3、在Android manifest配置文件中提供Widget的关键配置信息。

  项目准备

  一个Widget就是一个处理特定行为的BroadcastReceiver,AppWidgetProvider接口为开发人员提供了一个框架来简化处理这些行为,它包括以下方法:

  1、onEnabled():创建第一个Widget时调用,如果可以,应在这里进行全局初始化。

  2、onDisabled():它和onEnabled()相反,创建最后一个Widget时才调用它,如果可以,应在这里进行全局清理。

  3、onUpdate():当Widget需要更新它的View时调用,用户第一次创建Widget时也需要调用它。

  4、onDeleted():当Widget的一个特定实例被删除时调用,清理特定实例应放在这里进行。

  5、onReceive():此方法默认情况下处理BroadcastReceiver行为,并调用上面的方法(警告:根据相关文档记载,需要开发人员自己处理某些特殊情况,更多信息请看下面的说明)。

  作者注:点击此链接(http://groups.google.com/group/android-developers/browse_thread/thread/365d1ed3aac30916/e405ca19df2170e2?pli=1)检查有关AppWidget框架的缺陷信息,讨论内容包括解决此问题的代码(也可从本文下载示例代码,http://www.developer.com/img/2009/08/3833306_appwidget_code.zip),如果它们并不存在,可以将Widget标识符传递给onUpdate()方法。

  为了让Android识别Widget,需要在manifest文件中加入一个标准的标记,下面的代码片段显示了一个示例:

1  < receiver android:name = " ImagesWidgetProvider " >
2      < intent - filter >
3      < action
4     android:name = " android.appwidget.action.APPWIDGET_UPDATE "   />
5      </ intent - filter >
6      < meta - data
7     android:name = " android.appwidget.provider "
8     android:resource = " @xml/imageswidget_info "   />
9  </ receiver >
10
 

  你可能已经注意到,和常见的定义不一样,小节引用了一个XML文件资源,这个文件为Widget定义了额外的数据,与AppWidgetProviderInfo类一致,这里定义的信息是不变的,因此这个例子不包括updatePeriodMillis的值,因为这个程序允许用户修改与更新时间,如果你在这里分配updatePeriodMillis,它就不能这样做。下面是imageswidget_info.xml文件的完整代码:

1  < ?xml version = " 1.0 "  encoding = " utf-8 " ? >
2  < appwidget - provider 
3     xmlns:android = " http://schemas.android.com/apk/res/android "
4     android:minWidth = " 146dp "
5     android:minHeight = " 146dp "
6     android:initialLayout = " @layout/widget "
7     android:configure =
8         " com.mamlambo.imageswidget.ImagesWidgetConfiguration "   />
9

  标记定义了Widget的大小,默认布局和创建Widget实例时的启动行为配置,为了让Widget在主屏幕上更好地显示,Widget必须保持一定的大小,主屏幕分为特定大小的单元格,Google提供的基本原则是用你想占用的单元格数量乘以74,再减去2。在这个例子中,Widget应该是一个正方形,长和宽都各占两个单元格,因此大小就是74*2-2=146.

  实现onUpdate()

  不显示内容的Widget是没有用的,幸好这个Widget的RemoteView对象很容易实现,它使用一组存储在应用程序的drawable资源目录下的图片,程序使用R.drawable.[imagename]引用这些图片资源,代码需要创建一个数组容纳图片的名字,这样从这些图片名字中随机选择一个就可以了。下面的代码片段显示了onUpdate()的实现,它随机显示一张图片: 

1  @Override
2  public  void onUpdate(Context context,
3     AppWidgetManager appWidgetManager,
4      int [] appWidgetIds) {
5      for  ( int  appWidgetId : appWidgetIds) {
6         int  imageNum  =  ( new
7           java.util.Random().nextInt(IMAGES.length));
8        RemoteViews remoteView  =   new
9           RemoteViews(context.getPackageName(),
10           R.layout.widget);
11        remoteView.setImageViewResource(
12           R.id.image, IMAGES[imageNum]);
13        appWidgetManager.updateAppWidget(
14           appWidgetId, remoteView);
15     }
16  }
17

  注意onUpdate()方法使用Widget实例列表作为最后的参数,每个实例必须分开处理,由于App Widget框架的现有缺陷,有些实例可能不可见或不能启用,但在这个例子中可以忽略这些问题。请记住,你自己在实现时可能想跟踪哪个Widget是真正激活的。

  你可以下载本文提供的代码(http://www.developer.com/img/2009/08/3833306_appwidget_code.zip),查看其中的R.layout.widget XML布局定义,它基本上只是一个ImageView,RemoteViews只能使用一组有限的View对象,包括Button,ImageButton,ImageView,TextView,AnalogClock,Chronometer和ProgressBar,并且只能在FrameLayout,LinearLayout或RelativeLayout内使用。请保持RemoteView简单,因为访问是通过setImageViewResource() 和 setTextViewText()方法控制的,它们的目的是在另一个进程内画一个View,因此你的应用程序比正常布局要少些控制。

  自此,Widget最基本的部分完成了,但为了让用户配置图片更新之间的时间间隔,你必须要实现配置Activity,然后处理RemoteView更新的调度问题。

  实现Widget的Activity配置

  和manifest 文件中定义的ImagesWidgetConfiguration类似,任何Activity配置都有两个特殊情况:

  1、只要一启动,它的目的就是返回结果,因此必须要调用setResult()方法返回一个适当的结果(结果要么是RESULT_CANCELED或RESULT_OK)。

  2、在设置结果时,Widget标识值必须放在额外引用的AppWidgeManager.EXTRA_APPWIDGET_ID中。

  下面的代码片段显示了如何处理这两个例外,如果用户中途退出Activity,调用setResult()将默认值设为RESULT_CANCELED。

1  Bundle extras  =  launchIntent.getExtras();
2  if  (extras  !=   null ) {
3     appWidgetId  =  extras.getInt(
4        AppWidgetManager.EXTRA_APPWIDGET_ID,
5        AppWidgetManager.INVALID_APPWIDGET_ID);
6     Intent cancelResultValue  =   new  Intent();
7     cancelResultValue.putExtra(
8        AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
9     setResult(RESULT_CANCELED, cancelResultValue);
10  }
11

    除了这两个限制外,你可能还要实现你喜欢的Activity配置,图1显示了这个例子的简单Activity配置,如果你RESULT_CANCELED,Widget不会显示给用户,如果你返回RESULT_OK,用户才看得见Widget,你可以使用任意存储机制保存Widget实例的配置数据,这个例子使用的是SharedPreferences接口,存储Widget标识更新之间的时间,你可以下载本文配套的代码查看完整的实现(http://www.developer.com/img/2009/08/3833306_appwidget_code.zip)。

  

  图 1 配置界面:这个简单的配置界面让用户设置图片刷新间隔时间

  实现更新调度

  正如前面提到的,AppWidgetProviderInfo类中的配置值是不变的,因为updateTimeMillis值就在这个类中,任何有AppWidgetProviderInfo的Widget实例,只要设置了这个值,Widget就会根据其频率更新,没有办法修改它,因为这个应用程序应该让用户配置Widget中图片刷新的频率,因此你必须自动动手实现。

  AlarmManager类是最常用的更新机制,因为它支持重复通知,这些通知是将被触发的简单的PendingIntent对象。

  你可能会想你可以创建一个具有AppWidgetManager.ACTION_APPWIDGET_UPDATE的Intent对象,然后给特定的Widget标识符设置额外的值,接着你就可以通过调用AlarmManager的setRepeating()方法,采用调度机制反复地更新,遗憾的是,这种做法行不通,Android系统反复使用Intents匹配行为和方案值,那些“额外的”值是不会拿去对比的。实际上,解决方案非常简单:首先为你的Widget定义一个方案,然后用它定义唯一的Intent实例。下面的代码片段显示如何实现这个目标:

1  Intent widgetUpdate  =   new  Intent();
2  widgetUpdate.setAction(
3     AppWidgetManager.ACTION_APPWIDGET_UPDATE);
4  widgetUpdate.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, 
5      new   int [] { appWidgetId });
6  //  make this pending intent unique
7  widgetUpdate.setData(
8     Uri.withAppendedPath(Uri.parse(
9     ImagesWidgetProvider.URI_SCHEME  +   " ://widget/id/ " ), 
10     String.valueOf(appWidgetId)));
11  PendingIntent newPending  =  PendingIntent.getBroadcast(
12      getApplicationContext(),  0 , widgetUpdate, 
13      PendingIntent.FLAG_UPDATE_CURRENT);
14  //  now schedule it
15  AlarmManager alarms  =  (AlarmManager) getApplicationContext().
16     getSystemService(Context.ALARM_SERVICE);
17  alarms.setRepeating(AlarmManager.ELAPSED_REALTIME, 
18     SystemClock.elapsedRealtime(), updateRateSeconds  *   1000
19     newPending);
20

  在ImagesWidgetConfiguration Activity中你会发现前面的代码,manifest文件显示块处理这个特定的scheme,你也需要在AppWidgetProvider接口的onDeleted()方法内停止重复的警报。最后,当手机重启后,更新调度也必须重启。

  在AppWidgetProvider的onReceive()方法内提供了一个简单的解决方案,首先,检查更新行为,如果它是一个更新,确保它不包含scheme值,如果它不是更新,那么调度AlarmManager 的PendingIntent不会触发这个行为,在这种情况下,检查每个Widget标识符是否有一个配置选项值,如果没有,那么在配置Widget之前,你知道这个更新行为被接收到。但如果选项值有效,那么你知道可以调度PendingIntent,在onReceive()方法中你可以看到完整的逻辑实现。

  这个方案允许多个Widget同时显示,如图2所示。更新也可以以不同的频率进行,每个显示的图片是从图片集中随机选择的。

  

  图 2 多个Widget实例:这里显示了两个不同的同时运行的实例

  至此,你已经看到了如何在Android平台上创建一个基本的Widget,每个Widget实例按独立的方式调度,由用户自行配置,但App Widge框架不直接支持,因此需要自动动手编码实现。以后我将在此Widget基础上讲解如何从互联网上下载图片,以及如何直接在屏幕上控制图片,敬请期待吧!

标签:  Android , 移动开发 , 移动开发平台
分享到:
0 个人觉得赞+1
相关文章
Widget 移动开发平台 移动开发 android
广告
网友评论
已有 0条评论
猜您喜欢
  • 本月新机汇总:索尼XZP与三星S8的对决
    本月新机汇总:索尼XZP与三星S8的对决
  • 劲爽!2015“妹子杯”LOL大赛火爆开启
    劲爽!2015“妹子杯”LOL大赛火爆开启
  • 因众筹爆红 乐凡Core M平板3月18日发布
    因众筹爆红 乐凡Core M平板3月18日发布
  • 安卓平台最强旗舰 三星Galaxy S6评测
    安卓平台最强旗舰 三星Galaxy S6评测
  • 制冷效果好 海尔统帅三门冰箱仅1299元
    制冷效果好 海尔统帅三门冰箱仅1299元
  • 屏占比飙升 小米Note3渲染图曝光
    屏占比飙升 小米Note3渲染图曝光
  • 薄至4.9mm 小米电视4 65英寸首发评测
    薄至4.9mm 小米电视4 65英寸首发评测
  • iOS8+指纹识别 iPhone5s国行3599冰点价
    iOS8+指纹识别 iPhone5s国行3599冰点价
  • 这次有点狠 努比亚旗舰发布会看点汇总
    这次有点狠 努比亚旗舰发布会看点汇总
  • 新低价 魅族MX4 Pro/1865 魅蓝/658元
    新低价 魅族MX4 Pro/1865 魅蓝/658元
  • 努比亚Z17评测:升级不单是加个摄像头
    努比亚Z17评测:升级不单是加个摄像头
  • 7势磅礴?i7-7700HQ/6700HQ对比测试
    7势磅礴?i7-7700HQ/6700HQ对比测试
  • 小米6真机图赏:这样的米6 美得不要不要!
    小米6真机图赏:这样的米6 美得不要不要!
  • 噱头or创新?曲面显示器到底值得买吗
    噱头or创新?曲面显示器到底值得买吗
  • 那个被写死的迪拜王子 你过的还好么?
    那个被写死的迪拜王子 你过的还好么?
  • IT168企业级IT168企业级
  • IT168文库IT168文库

扫码送文库金币

文库文集
  • 别人的文案是怎样炼成的?经典文案合集
  • 关于数字营销研究与市场分析的25份资料
  • 渴望力量吗?权威公司25份互联网相关报
  • 16年的营销行业盘点 必备的25份资料
  • “微时代”下的危机公关应该怎么做?
  • 数字营销新趋势,全在这25份报告
  • 2016年VR/AR领域最具藏收价值的25份报告
  • 人人都在谈“区块链” 这25份报告必须要
  • 不看会后悔!来自京东内部的25份资料
  • 2月精选推荐高质量互联网相关资料报告集
一周热文
  • 从代码看Java和Kotlin有哪些区别?
  • Kotlin新框架发布,据说是Swift转换神器
  • 程序员应收藏的18款优秀Web工具及服务
  • 易进难出,“Vim退出”难住百万程序员
  • 2017年最佳JavaScript框架,库和工具
  • 盘点谷歌最实用的10款营销工具
  • HTML5是否会成为现代Web技术的核心?
编辑推荐
  • 试客发言区:情不知所起,一往而深——我和小米的“孽缘”!试客发言区:情不知所起,一往而深——我和小米的“孽缘”!
  • 试客发言区:买不起的双摄手机都是耍流氓,小辣椒双摄新品A1试客发言区:买不起的双摄手机都是耍流氓,小辣椒双摄新品A1
  • 试客发言区:700元的大屏长续航酷比魔方iplay10平板畅玩王者荣耀试客发言区:700元的大屏长续航酷比魔方iplay10平板畅玩王者荣耀
  • 试客发言区:盲目崇拜AirPods?其实Nokia J早就玩过充电盒了试客发言区:盲目崇拜AirPods?其实Nokia J早就玩过充电盒了
  • 每周都有免费试用每周都有免费试用

http://www.ppmy.cn/news/401867.html

相关文章

ajax方法参数的用法和他的含义

1.url:   要求为String类型的参数&#xff0c;&#xff08;默认为当前页地址&#xff09;发送请求的地址。 2.type:   要求为String类型的参数&#xff0c;请求方式&#xff08;post或get&#xff09;默认为get。注意其他http请求方法&#xff0c;例如put和delete也可以…

java 生成 模板文件 excel,word

生成excel 两种方式:1.模板文件为.xls或.xlsx 2.模板文件.ftl 当然两种生成文件的方式都有各自的优点与缺点 以及技术上的不同。个人意见。本人亲自做了两种例子。 1.模板文件为.xls(.xlsx)&#xff0c;我用的是org.apache.poi的包。优点就是&#xff1a;通俗易懂&#xff…

桂电计算机专业2021推免人数,2021届计算机科学与技术学院推免公示

计算机科学与技术学院关于推荐2021届优秀本科毕业生免试攻读研究生工作细则变更及拟推荐名单公示 根据教育部《关于做好2021年推荐优秀应届本科毕业生免试攻读研究生工作的通知》(教学司函〔2020〕38号)文件精神及学校教务处《华东师范大学推荐优秀应届本科毕业生免试攻读研究生…

Linux 查看进程ps命令详解

介绍 ps 命令是 Linux 系统中常用的进程查看工具&#xff0c;它可以查看当前系统中正在运行的进程信息。ps 命令可以显示进程的 ID、状态、执行命令、占用内存等信息&#xff0c;对于系统管理员来说&#xff0c;使用 ps 命令可以方便地监控和管理系统中的进程。 ps 命令语法及…

存储圈秘史,细说“配额管理”的那些事儿

江湖乱战 分布式存储圈管理者“配额管理”出手划天下 各方数据混战之际 管理员划分空间应接不暇 不可避免的产生资源划分不合理等问题 各路“配额管理”豪杰陆续上线&#xff0c;力求结束纷争一统江湖 职场人所熟知的办公软件“共享盘”冲锋在前 共享盘可支持多人实时上…

django REST框架- Django-ninja

Django 是我学习的最早的web框架&#xff0c;大概在2014年&#xff0c;当时选他原因也很简单就是网上资料比较丰富&#xff0c;自然是遇到问题更容易找答案&#xff0c;直到 2018年真正开始拿django做项目&#xff0c;才对他有了更全面的了解。他是一个入门有门槛&#xff0c;学…

MQTT服务等级

1.QoS含义 Quality of Service,服务质量 很多时候&#xff0c;使用 MQTT 协议的设备都运行在网络受限的环境下&#xff0c;而只依靠底层的 TCP传输协议&#xff0c;并不能完全保证消息的可靠到达。因此&#xff0c;MQTT 提供了 QoS机制&#xff0c;其核心是设计了多种消息交互…

使用GRUB2引导加载程序

Fedora 27是与GNU GRand Unified Boot loader (GRUB) version 2引导加载程序一起发布的,它允许用户在系统引导时选择要加载的操作系统或内核。GRUB 2还允许用户向内核传递参数。 GRUB 2介绍 GRUB 2在传统的基于bios的机器上从/boot/grub2/grub.cfg文件读取配置,在UEFI机器上…