所谓桌面小控件,就是能之间显示在Android系统桌面的小程序。

桌面小控件的实现是基于Broadcast的形式实现的,因此,每一个桌面小控件都对应于一个BroadcastReceiver类。Android系统提供了一个AppWidgetProvider类(它就是BroadcastReceiver的子类),这个类很关键,你在写桌面小控件时只需继承这个类就行。继承了AppWidgetProvider类之后,你可以根据自己的需要覆盖它的不同的生命周期的方法,来达到自己的目的。AppWidgetProvider类的主要提供如下不同生命周期的方法:

void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) { }
// 这个方法字面意思是负责更新桌面小控件,但貌似只有在小控件被用户放到桌面上时被调用了一次,读者可以自己通过输出Log来测试
// 实现桌面控件是通常都会考虑重写该方法 void onDeleted(Context context, int[] appWidgetIds)
// 在小控件被删除时调用该方法

一般来说,开发桌面小控件只需要定义一个AppWidgetProvider的子类,并重新写它的pnUpdate方法即可。

下面上代码,有不足之处请指教:

DesktopClock.java,这个类继承了上面说的AppWidgetProvider类(记住它是继承自BroadcastReceiver类):

package org.ls;import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;public class DesktopClock extends AppWidgetProvider {@Overridepublic void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) {Log.e("appwidget", "--update--");// 创建RemoteViews对象RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.main);views.setImageViewResource(R.id.double_dot,R.drawable.blue_modern_middle);// 将刷新UI的service的必要的数据设置好(此处没有使用Bundle传递数据)UpdateUIService.appWidgetManager = appWidgetManager;UpdateUIService.context = context;UpdateUIService.remoteViews = views;// 启动刷新UI的ServiceIntent intent = new Intent(context, UpdateUIService.class);context.startService(intent);}// 在小控件被删除时调用该方法停止Service@Overridepublic void onDeleted(Context context, int[] appWidgetIds) {super.onDeleted(context, appWidgetIds);Log.e("appwidget", "--deleted--");Intent intent = new Intent(context, UpdateUIService.class);context.stopService(intent);}
}

UpdateUIService.java,这个类继承自Service类,是一个后台运行的服务,它的主要职责是在它里面有一个动态注册的BroadcastReceiver的实例(也即调用了Context里面的registerReceiver( )方法注册的一个BroadcastReceiver的实例,而不是在xml中注册),负责监听系统的时间变化的广播,然后更新小控件的UI。

还有一点要注意的是,读者可能会有这样的疑问,不是说AppWidgetProvider本身就是一个BroadcastReceiver吗,为什么不让它直接监听系统的时间变化的广播呢?注意,虽然AppWidgetProvider本身就是一个BroadcastReceiver,但是它是一个“分化”了的BroadcastReceiver,不能再监听其它的系统广播了。一般的BroadcastReceiver是这样的:每次系统的Broadcast事件发生后,系统就会创建对应的BroadcastReceiver的实例,并自动触发它的onReceive( )方法,onReceive( )执行完后,BroadcastReceiver的实例就会被销毁。但是这个“分化”了的BroadcastReceiver——AppWidgetProvider显然做不到这样,也即系统尝试再创建它的实例时会发生异常,因此不能用它之间监听系统的Broadcast了。

那我为什么不在AppWidgetProvider里面新动态注册一个BroadcastReceiver,而是要新开一个Service呢?笔者也曾经尝试过这样做,但是当调用registerReceiver( )方法时编译通不过,此外,如果不在AppWidgetProvider里面新开一个Service,AppWidgetProvider并不是会一直在后台运行的,执行完onUpdate方法后就会退出执行,因此最好的方法就是在onUpdate里面新开一个Service。

package org.ls;import java.text.SimpleDateFormat;
import java.util.Date;import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.util.Log;
import android.widget.RemoteViews;public class UpdateUIService extends Service {private SimpleDateFormat df = new SimpleDateFormat("HHmmss");public static Context context;public static AppWidgetManager appWidgetManager;public static RemoteViews remoteViews;// 数字图片的IDprivate int[] numberIcon = new int[] { R.drawable.blue_modern_zero,R.drawable.blue_modern_one, R.drawable.blue_modern_two,R.drawable.blue_modern_three, R.drawable.blue_modern_four,R.drawable.blue_modern_five, R.drawable.blue_modern_six,R.drawable.blue_modern_seven, R.drawable.blue_modern_eight,R.drawable.blue_modern_nine };// 用于显示数字的ImageView的IDprivate int[] numberView = new int[] { R.id.hour01, R.id.hour02,R.id.minute01, R.id.minute02 };// 覆盖基类的抽象方法@Overridepublic IBinder onBind(Intent intent) {return null;}// 在本服务创建时将监听系统时间的BroadcastReceiver注册@Overridepublic void onCreate() {super.onCreate();Log.e("service", "--service created--");IntentFilter intentFilter = new IntentFilter();intentFilter.addAction(Intent.ACTION_TIME_TICK); // 时间的流逝intentFilter.addAction(Intent.ACTION_TIME_CHANGED); // 时间被改变,人为设置时间registerReceiver(boroadcastReceiver, intentFilter);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.e("service", "--service started--");updateUI(); // 开始服务前先刷新一次UIreturn START_STICKY;}// 在服务停止时解注册BroadcastReceiver@Overridepublic void onDestroy() {super.onDestroy();unregisterReceiver(boroadcastReceiver);}// 用于监听系统时间变化Intent.ACTION_TIME_TICK的BroadcastReceiver,此BroadcastReceiver须为动态注册private BroadcastReceiver boroadcastReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context acontext, Intent intent) {
//          Log.e("time received", "--receive--");updateUI();}};// 根据当前时间设置小部件相应的数字图片private void updateUI() {String timeString = df.format(new Date());int num;for (int i = 0; i < numberView.length; i++) {num = timeString.charAt(i) - 48;remoteViews.setImageViewResource(numberView[i], numberIcon[num]);}// 将AppWidgetProvider的子类包装成ComponentName对象ComponentName componentName = new ComponentName(context,DesktopClock.class);// 调用AppWidgetManager将remoteViews添加到ComponentName中appWidgetManager.updateAppWidget(componentName, remoteViews);}
}

下面是一些xml文件:

布局文件main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="horizontal" ><ImageViewandroid:id="@+id/hour01"  android:layout_weight="1"android:layout_width="wrap_content" android:layout_height="wrap_content" /><ImageViewandroid:id="@+id/hour02"  android:layout_weight="1"android:layout_width="wrap_content" android:layout_height="wrap_content" /><ImageViewandroid:id="@+id/double_dot"  android:layout_width="wrap_content" android:layout_height="wrap_content" /><ImageViewandroid:id="@+id/minute01"  android:layout_weight="1"android:layout_width="wrap_content" android:layout_height="wrap_content" /><ImageViewandroid:id="@+id/minute02"  android:layout_weight="1"android:layout_width="wrap_content" android:layout_height="wrap_content" /></LinearLayout>

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="org.ls"android:versionCode="1"android:versionName="1.0" ><uses-sdk android:minSdkVersion="10" /><applicationandroid:icon="@drawable/ic_launcher"android:label="@string/app_name" ><receiver android:name=".DesktopClock"    android:label="@string/app_name"><intent-filter><action android:name="android.appwidget.action.APPWIDGET_UPDATE" /><category android:name="android.intent.category.DEFAULT" /></intent-filter><meta-data android:name="android.appwidget.provider"android:resource="@xml/appwidget_provider" /></receiver><service android:name=".UpdateUIService" ></service></application></manifest>

用于配置时钟小控件属性的appwidget_provider.xml(在 AndroidManifest.xml中被引用):

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="270px"android:minHeight="103px"android:updatePeriodMillis="1000"android:initialLayout="@layout/main">
</appwidget-provider>

效果图:同步更新时间,完全与系统时间同步:

欢迎讨论。

android桌面时钟小控件开发记录相关推荐

  1. mac下dashboard小控件开发实例(附源码)

    1.背景          用mac的用户都应该知道,mac有一个很好的功能,就是dashboard小控件的功能,按下F12键就可以自由切换.博主最近在背GRE单词,就尝试这开发了一个背单词的dash ...

  2. Silverlight 控件开发记录之 extern alias” 关键字

    早在.net2.0, 微软就发布了"extern alias" C#关键字,目的就是为了解决在参照不同的Assembly时类型全名相同的问题. 以前还没觉得有多大的用处,但在做Si ...

  3. 开发数字时钟桌面小控件

    随时随地技术实战干货,获取项目源码.学习资料,请关注源代码社区公众号(ydmsq666) 所谓桌面小控件,就是指能直接显示在Android系统桌面的小程序,比如模拟时钟等.桌面小控件是通过Broadc ...

  4. Android之RemoteViews篇上————通知栏和桌面小控件

    Android之RemoteViews篇上----通知栏和桌面小控件 一.目录 文章目录 Android之RemoteViews篇上----通知栏和桌面小控件 一.目录 二.RemoteViews的概 ...

  5. 如何在Android实现桌面清理内存简单Widget小控件

    如何在Android实现桌面清理内存简单Widget小控件 我们经常会看到类似于360.金山手机卫士一类的软件会带一个widget小控件,显示在桌面上,上面会显示现有内存大小,然后会带一个按键功能来一 ...

  6. Android UI设计之十一自定义ViewGroup,打造通用的关闭键盘小控件ImeObser

    2019独角兽企业重金招聘Python工程师标准>>> 转载请注明出处:http://blog.csdn.net/llew2011/article/details/51598682 ...

  7. 【Android控件属性记录】

    #Android 控件属性记录 方便查找 控件属性: android属性 android功能强大,界面华丽,但是众多的布局属性就害苦了开发者,下面这篇文章结合了网上不少资料, 第一类:属性值为true ...

  8. Android引用RN第三方控件,Android和RN互调方式,最近开发心得

    "有人住高楼,有人在深沟,有人光万丈,有人一身锈,世人万千种,浮云莫去求,斯人若彩虹,遇上方知有." 时隔四季,我重新开始了我的文章更新,so do you miss me? 前言 ...

  9. android 原理 组合控件_Android自定义控件进阶01-自定义控件开发套路与流程

    Android自定义控件进阶01-自定义控件开发套路与流程本章节为什么要叫进阶篇?(虽然讲的是基础内容),因为从本篇开始,将会逐渐揭开自定义View的神秘面纱,每一篇都将比上一篇内容更加深入,利用所学 ...

最新文章

  1. zabbix 监控 tomcat/jvm性能
  2. 数据结构—链表-单链表基本操作实现
  3. Centos 配置eth0 提示Device does not seem to be present -- 转载
  4. 计算机网络工程师中级软考试题及答案,软考中级历年真题+章节题库
  5. 免费Cron表达式生成器源码
  6. 在Django框架下向MongoDB数据库中导入.scv文件数据
  7. 苹果开发者证书报错证书不受信任
  8. Python爬取国家税务总局纳税信用A级纳税人信息!
  9. Hexo博客使用 Next主题 后的一些相关配置 记录
  10. 简单学JAVA-Java学习方法-费曼学习法
  11. 阿里云崩“出圈”了!保护业务还得加一道同云跨可用区容灾!
  12. ubuntu安装显卡驱动的三种方法
  13. SpringAop篇 (1) AOP 基础之动态代理的实现
  14. 知识图谱构建:py2neo的实体关系以及节点显示图片
  15. NetworkX系列教程(2)-graph生成器
  16. php网站如何添加ico图标,如何添加favicon.ico图标?
  17. CSDN博客的积分规则
  18. 178页7万字智慧乡村大数据平台建设项目解决方案2022
  19. 台式计算机如何取消屏幕密码,台式电脑怎么设置锁屏
  20. 计算机的应用系统安装,处理电脑系统安装软件有哪些

热门文章

  1. 启动ipython_iPython pylab模式启动方式
  2. 一篇帮助前端小白理解 PNG 图片压缩原理
  3. 思维导图教程Xmind中文版怎么用
  4. 双十二哪款蓝牙耳机性价比最高?四款高性价比蓝牙耳机推荐
  5. 关于pdf.js在IE浏览器二次刷新的报错,我有话说
  6. 超级服务器系统,曙光2000-II超级服务器
  7. Notepad++强大的代码补全和代码提示功能的方法
  8. Hadoop之SSH无密登录配置
  9. android app 启动第一个页面
  10. 【源码解析】压测工具vegeta