Widget是安卓的一个桌面小工具组件—窗口小部件,是微型应用程序视图,可以嵌入到其他应用程序(如主屏幕)和接收定期更新。

使用步骤:

1、创建一个类继承 AppWidgetProvider  并重写相应方法 默认实现了onReceive 方法。

2、在清单文件进行注册。

3、在res目录下新建xml文件夹 配置widget相关信息。

4、创建widget展示布局。

5、创建widget的配置文件(可选)。

6、更新数据。

大概就是上述的一些步骤。如果在添加的widget之前需要进行一些配置 则需要实现第5步。

第一步:创建类继承AppWidgetProvider

public class MyWidget extends AppWidgetProvider {@Overridepublic void onReceive(Context context, Intent intent) {super.onReceive(context, intent);}/*** 第一个widget被添加调用* @param context*/@Overridepublic void onEnabled(Context context) {super.onEnabled(context);context.startService(new Intent(context, WidgetService.class));}/*** widget被添加 || 更新时调用* @param context*/@Overridepublic void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {super.onUpdate(context, appWidgetManager, appWidgetIds);context.startService(new Intent(context, WidgetService.class));}/*** 最后一个widget被删除时调用* @param context*/@Overridepublic void onDisabled(Context context) {super.onDisabled(context);context.stopService(new Intent(context, WidgetService.class));}/*** widget被删除时调用* @param context* @param appWidgetIds*/@Overridepublic void onDeleted(Context context, int[] appWidgetIds) {super.onDeleted(context, appWidgetIds);}}

2、清单文件注册

        <receiver android:name=".MyWidget"><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" /> //widget的配置信息文件</receiver>

3、创建配置信息 目录 res/xml/xxx.xml

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"android:minWidth="40dp" //widget的最小宽度android:minHeight="40dp"//widget的最小高度android:updatePeriodMillis="86400000"//更新的频率  google规定最小时间为30分钟android:previewImage="@drawable/preview" //widget的预览图 即在添加是看到的图片 一般为logoandroid:initialLayout="@layout/example_appwidget" // widget的布局文件android:configure="com.example.android.ExampleAppWidgetConfigure" //widget配置activityandroid:resizeMode="horizontal|vertical" //widget是否可以水平 竖直缩放 android:widgetCategory="home_screen|keyguard"> //widget可以被添加主屏幕或者锁屏
</appwidget-provider>

以上这些信息并不是必须  是可以选择的。updatePeriodMillis的时间最小限定在了30分钟,对于有些app来说可能时间太久了,那么我们可以将updatePeriodMillis的时间设置为0,然后通过自定义service去更新widget。

Demo中的配置信息如下:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"android:initialLayout="@layout/example_appwidget"android:minHeight="80dp"android:minWidth="250dp"android:previewImage="@mipmap/ic_launcher"android:updatePeriodMillis="0"android:widgetCategory="home_screen|keyguard"></appwidget-provider>

4、创建widget的展示布局,这个就根据设计,自己去码布局了。

Demo中布局文件内容如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@mipmap/bg_icon"android:gravity="center_vertical"android:orientation="horizontal"android:paddingLeft="30dp"android:paddingRight="30dp"><LinearLayoutandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:orientation="vertical"><TextViewandroid:id="@+id/tv_date"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#000"android:textSize="16sp" /><TextViewandroid:id="@+id/tv_money"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#000"android:textSize="16sp" /></LinearLayout><Buttonandroid:id="@+id/btn_refound"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@null"android:gravity="right|center"android:text="点击" android:textColor="#000"android:textSize="16sp" /></LinearLayout></LinearLayout>

就是简单的来个TextView来显示文案。

Demo中不需要对在添加widget进行配置所以不需要第5步。

这样简单的widget使用就完成了。

最后就是更新widget数据了,为了满足自定义时间可以对widget进行更新,我们采取使用service的方式进行。同样,创建类继承Service。

Demo中的service代码如下:

public class WidgetService extends Service {private Timer mTimer;private SimpleDateFormat mFormat;@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();mFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");mTimer = new Timer();mTimer.schedule(new TimerTask() {@Overridepublic void run() {updateWidget(WidgetService.this);}}, 0, 5000); }private void updateWidget(Context context) {RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.example_appwidget);long millis = System.currentTimeMillis();String format = mFormat.format(new Date(millis));remoteViews.setTextViewText(R.id.tv_date, "日  期:" + format);remoteViews.setTextViewText(R.id.tv_money, "毫秒值:" + millis);PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, new Intent(this, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);remoteViews.setOnClickPendingIntent(R.id.btn_refound, pendingIntent);ComponentName componentName = new ComponentName(this, MyWidget.class);AppWidgetManager.getInstance(this).updateAppWidget(componentName, remoteViews);}@Overridepublic void onDestroy() {super.onDestroy();mTimer.cancel();mTimer = null;stopForeground(true);}}   stopForeground(true);}}

在service的oncreate方法中创建一个Timer定时器,这个定时器每个5秒钟就会执行updateWidget方法,在updateWidget方法里面实现了具体的更新widget的逻辑。通过RemoteViews去加载布局文件 在通过setTextViewText等方法实现对控件的控制。

这个地方使用了PendingIntent  ,PendingIntent 其实和Intent效果是一样的,都是充当信使的作用,但是区别就是 PendingIntent 定义的事件是提前预知的,就是不知道事件什么时候发生,但是只要发生了,就要执行PendingIntent 定义的逻辑。

最后通过AppWidgetManager.getInstance(this).updateAppWidget(componentName, remoteViews);去更新widget组件的信息。

这样看,大概一个widget的功能就已经完成了,创建了,数据也可以更新了,但是有一个问题就是,我们使用的是service去更新widget,那么我们创建的service是一个后台进程,后台进程的优先级比较低,当手机内存不足的时候 就会优先kill掉这些进程。这个时候,widget在桌面上就不会得到更新了。那么怎么解决呢?

这里的思路是提升service进程的优先级,将其提升为前台进程,这样就可以最大程度的保证service不会被系统kill掉了。

在service的oncreate方法中创建一个通知,这样就将此service由后台进程变为前台进程了。代码如下:

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)private void improvePriority() {PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, WidgetService.class), 0);Notification notification = new Notification.Builder(this).setContentTitle("Foreground Service").setContentText("Foreground Service Started.").setSmallIcon(R.mipmap.ic_launcher).build();notification.contentIntent = contentIntent;startForeground(1, notification); }

在oncreate方法中调用此方法即可。 Demo源码中startForeground(1, notification);  第一个参数写的是0  这个是不行的  谷歌文档提示 must not be 0 , 写0之后就not working了。但是这样,当SDK<18时,通知栏不会显示该通知,当SDK>=18时,通知栏就会显示该通知 了。关于这个问题请移步到消除前台进程通知 本人未做实践,不过的确是一种思路。

这样基本就完成了widget的创建了。这个时候可能又会问了,万一此时service还是被kill了怎么办呢?

一种方式是我们重写service的onStartCommand方法 并返回START_STICKY,这样如果是系统自动将service kill了,在一段时间后 在内存比较充裕的心情下 系统会自动启动这个service的。

    @Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return START_STICKY;}

另外一种方式就是通过广播来监听此service,安卓系统提供了一个时间改变的广播接受者— ACTION_TIME_TICK 每隔一分钟 就会发送一个广播。由于此广播是系统级别的广播,所以不可以通过清单文件配置监听,只能通过代码动态的创建监听。

创建一个类继承BroadcastReceiver 并且重写onReceive 方法 ,这样每隔一分钟 onReceive方法就会执行一次,在onReceive方法中判断service是否已经在运行,如果没有在运行就去开启service,否则就上面操作都不需要做。

public class WidgetBroadcastReceiver extends BroadcastReceiver {public static final String SERVICE_NAME = "com.ppdai.widgetdemo.WidgetService";@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (action.equals(Intent.ACTION_TIME_TICK)) {if (!isServiceWork(context, SERVICE_NAME)) {context.startService(new Intent(context, WidgetService.class));}}}/*** 判断service是否在运行* @param mContext* @param serviceName* @return*/public boolean isServiceWork(Context mContext, String serviceName) {boolean isWork = false;ActivityManager myAM = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);List<ActivityManager.RunningServiceInfo> myList = myAM.getRunningServices(100);if (myList.size() <= 0) {return false;}for (int i = 0; i < myList.size(); i++) {String mName = myList.get(i).service.getClassName().toString();if (mName.equals(serviceName)) {isWork = true;break;}}return isWork;}
}

然后在需要的地方 动态的注册此广播:

        WidgetBroadcastReceiver mReceiver = new WidgetBroadcastReceiver();IntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_TIME_TICK);registerReceiver(mReceiver, filter);

这样 整个widget的功能就基本完善了。如有不足 请指正! 谢谢

我是源码

扫描下方二维码关注公众号,及时获取文章推送

Widget的简单使用详解相关推荐

  1. mysql单表查询实例_MySQL简单查询详解-单表查询

    MySQL简单查询详解-单表查询 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.查询的执行路径 一条SQL查询语句的执行过程大致如下图所示: 1>.客户端和服务端通过my ...

  2. python中paste函数的作用_PIL图像处理模块paste方法简单使用详解

    python2中提供了PIL基础的图像数据出来模块,在python3中更名为了pillow模块,名字虽然发生了改变,但是提供的方法和功能都是一样的,对于日常基础的图像数据处理分析来说是足够用了的,现在 ...

  3. u盘制作大师 linux系统教程,制作用U盘启动的Linux系统的简单步骤详解

    制作用U盘启动的Linux系统的简单步骤详解 最近听朋友说误删除了Linux系统里的文件,于是系统进不了,里面保存着很多重要的数据,这该怎么办?虽然可以把硬盘取出挂载其他Linux系统运行,也可跳过控 ...

  4. scrapy-splash java,scrapy-splash简单使用详解

    1.scrapy_splash是scrapy的一个组件 scrapy_splash加载js数据基于Splash来实现的 Splash是一个Javascrapy渲染服务,它是一个实现HTTP API的轻 ...

  5. Android简单计时器详解(Timer)

    Android计时器详解(Timer) 在开发中我们有时会有这样的需求,即在固定的每隔一段时间执行某一个任务.比如UI上的控件需要随着时间改变,我们可以使用Java为我们提供的计时器的工具类,即Tim ...

  6. java 天气爬虫_java网页爬虫简单实例详解——获取天气预报。

    [本文介绍] 爬取别人网页上的内容,听上似乎很有趣的样子,只要几步,就可以获取到力所不能及的东西,例如呢?例如天气预报,总不能自己拿着仪器去测吧!当然,要获取天气预报还是用webService好.这里 ...

  7. c语言substr函数的优点,C/C++中substr函数的应用(简单讲解)详解

    substr(字符串,截取开始位置,截取长度) //返回截取的字 substr('Hello World',0,1) //返回结果为 'H'  *从字符串第一个字符开始截取长度为1的字符串 subst ...

  8. 【贪玩巴斯】带你一起攻克英语语法长难句—— 第一章——简单句详解 2021年12月2日

    简单句 1.英汉句法语法的差异? 2.第一个句子--主谓宾 3.什么是英语句子? 4.英语句子的五个基本结构 1.主谓 2.主谓宾 3.主系表 4.主谓双宾 5.主谓宾宾补 5.句子的成分--词性 1 ...

  9. 【求解器】超级强大的数学规划模型求解器Cplex,导入idea+java代码简单案例详解

    文章目录 前言 一.下载cplex 二.使用步骤 1.打开idea,创建一个新项目 2.导入cplex的包 3.测试,用cplex求解一个简单的线性规划问题 总结 前言 CPLEX是一种数学优化技术. ...

  10. 简单mysql 查询_MySQL简单查询详解

    MySQL的查询操作 单表查询:简单查询 多表查询:连接查询 联合查询 布尔条件表达式操作符= 等值比较 <=>:跟空值比较不会产生额外信息的等值比较 <>:不等值 <: ...

最新文章

  1. linux下用gcc如何生成预处理、汇编等文件
  2. 第50讲:Scrapy 部署不用愁,Scrapyd 的原理和使用
  3. modbus注意几点
  4. 黑白极简设计行业企业官网模板
  5. vue中使用高德地图 amap--基础使用方法
  6. struts2随笔(一)Action、struts.xml、Interceptor细节
  7. reload端口 tomcat_CentOS 7配置tomcat https并改端口为443
  8. javaweb课程PSP(1)
  9. Factory Method (工厂方法)
  10. 下载我的CSDN资源
  11. 短视频app源码开发,Java使用ffmpeg实现音视频分离
  12. ps去水印教程_图片如何用PS去水印?ps去水印教程,让你1秒学会!
  13. MySQL权限系统(三).权限表 Grant Tables
  14. DBLINK使用的思考
  15. 数字图像处理中的Region与XLD
  16. 分享:阿里P8架构师深度概述分布式架构
  17. 中国智能行车记录仪行业发展现状及趋势分析,DMS将替代DVR
  18. 【SV 基础】queue 的一些用法
  19. 关于昨晚昨晚的银河护卫队2
  20. 无法启动Sql Server服务

热门文章

  1. 计算机设置u盘启动,如何设置U盘启动_BIOS设置U盘启动教程 - U当家官网
  2. Android发短信功能
  3. 18 亿美元!腾讯最大股东收购全球第三大程序员社区 Stack Overflow
  4. 数字滤波器的简单使用
  5. Ubuntu18.04 wifi不稳定
  6. si24r1程序_SI24R1多对一通信功能(ACK模式,ACK不带PAYLOAD)程序资料开发
  7. wifi产品调试经验
  8. win7触摸板怎么关闭_win7系统如何禁用触摸板功能 win7禁用触摸板功能方法【详解】...
  9. 如何通过API接口,获取拼多多商品详情数据
  10. Markdown表格——在CSDN上画表格