我们常常会看到类似于360、金山手机卫士一类的软件会带一个widget小控件,显示在桌面上,上面会显示现有内存大小,然后会带一个按键功能来一键清理内存,杀死后台进程的功能,那么这个功能是怎样实现的呢,我们今天也来尝试做一个类似的功能的小控件。
效果图:
參照Google的文档,首先在建立一个类继承AppWidgetProvider
然后在清单文件里申明它。我们必须注意到,AppWidgetProvider实际上是BroadcastReceiver,所以要注冊成一个receiver,然后另一些其它的东西须要注意:
android.appwidget.action.APPWIDGET_UPDATE 表明这个receiver可以接受一个APPWIDGET_UPDATE的广播,并且在这里,仅仅能增加这一个action。
android.appwidget.provider 表明数据类型时widget提供者提供的数据,example_appwidget_info表明这个widget的參数配置文件名称和位置
那么接下来就须要在res文件夹下建立一个xml文件夹。而且在当中建立一个example_appwidget_info.xml的配置文件,Google的文档中给出了演示样例有非常多參数。实际上关键的參数仅仅有以下的4个:
当中,minWidth和minHeight代表这个widget控件所占领的最小空间,这个空间一般来讲不须要太大,由于太大的话,一个屏幕可能都没办法放下。Google的官方文档的说法是大于4x4的就可能无法显示。
updatePeriodMillis代表数据更新的时间。这里86400000毫秒实际上是24小时,可能最開始看到这个參数会想我是否能将其设的非常小,每一秒刷新非常多次?,实际上对于updatePeriodMillis这个參数而言,即算你设的再小也没用,Google设定widget控件这个參数控制的最短update时间为30分钟,就算将其设置在30分钟以内也会以30分钟的频率来更新数据。
initialLayout參数代表的是本widget空间的布局文件。
那么下一步就是定义出一个相应的布局文件。
我们能够简单的在layout文件夹下建立一个布局文件example_appwidget.xml
在Google的文档中有指出,并不是全部的布局组件都能够在上面的这个布局中生效,有效的组件或布局为:
至此。一个简单的widget控件就写好了,我们能够在模拟器上将其拖到桌面上看一看效果:
大部分的Widget小控件都会须要在特定情况下更新上面显示的数据。那么这个是怎样实现的呢,我们经过上面的代码不难发现实际上这个widget控件并没有一个Activity,所以说这个控件的显示实际上不是本应用来实现的。它实际上是桌面这个应用来显示的,所以我们也不可能直接去更新它上面的数据。
回过头去看看上面我们写的那个receiver。实际上没有实现不论什么方法。实际上AppWidgetProvider里面有几个比較重要的方法:onReceive、onUpdate、onDisabled、onEnabled
当中onReceive方法跟大多数广播接收者的onReceive方法一样,可是在这里。onReceive方法的调用并非我们能够决定的,它依赖于显示该widget控件的Host组件。在这里也就是Android桌面应用。所以我们会发如今不同的手机上。将widget控件拖到桌面上显示的时候onReceive可能调用的次数和先后顺序可能全然不一样。这依赖于Host组件是怎样实现的。
所以在这里onReceive方法对于我们刷新widget数据基本没有什么帮助。
而onUpdate方法则是由上面所说的updatePeriodMillis參数来控制的,经过上面的分析。我们都知道了,它的最小周期为30分钟。所以我们一般将这个參数设为0就可以。那么在这种方法里,我们往往会在当中放置一些启动更新数据服务的功能。由于假设后台的更新数据的Service被意外停止了,那么每30分钟还会被又一次启用。不至于一直启动不了了:
以下是比較重要的两个方法了:onDisabled和onEnabled
我们知道。widget小控件是可以拖动多个到桌面上的,而onEnabled方法会在第一个widget控件拖到桌面上的时候调用一次,onDisabled会在最后一个widget控件从桌面被删除时调用一次,那么我们须要做的就是在onEnabled这种方法中启用一个刷新widget数据的服务,在onDisabled方法中使用stopService方法来停止这个服务。
那么以下的任务就仅仅剩下UpdateWidgetService这个刷新数据的服务(Service)怎样实现的问题了。
我们在这里的想法非常easy。比方说每隔三秒钟来刷新一下widget中的数据。Android中定时运行任务的方法有非常多。我们这里使用Timer和TimerTask来实现,之后我们须要关心的就是详细怎样实现刷新widget中的数据。毕竟这些数据是在桌面应用中显示的。
1、定义一个RemoteViews的实例:
当中viewId是在我们前面定义的widget布局文件里的子组件的id,也就是我们要刷新内容的对象,这里就是R.id.tv_test。第二个參数是我们要更新的内容
要实现这个功能,我们须要再上面定时刷新数据服务中将定时刷新的内容改为当前内存所剩余的量,我们这里写一个工具类方法来实现返回内存剩余量;
另外我们还须要在widget控件的布局文件里加入一个button,并在更新widget数据的服务中,设置这个button的点击事件,可是这里也不像曾经的点击事件,相同要应用到RemoteView对象,在这个点击事件中须要发送一个广播,Action为自己定义的。我们这里设为:"com.alexchen.mobilesafeexercise.killall",之后,我们须要再写一个广播接收者,来接收这个广播,在onReceive方法中运行杀死后台进程的操作。这里也不能直接使用Intent,因为我们这个意图的Action不是由我们自己运行而是由其它应用程序(桌面应用)运行的,所以须要用到PendingIntent。
刷新widget数据的服务代码:
按键清理内存的广播接收者:
获取可用内存的工具类方法:
本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5129287.html,如需转载请自行联系原作者