天天看点

android person类_把你的程序放到桌面——Android桌面部件Widget

android person类_把你的程序放到桌面——Android桌面部件Widget

Android 桌面小部件是我们经常看到的,比如时钟、天气、音乐播放器等等。

它可以让 App 的某些功能直接展示在桌面上,极大的增加了用户的关注度。

首先纠正一个误区:

当 App 的小部件被放到了桌面之后,并不代表你的 App 就可以一直在手机后台运行了。该被杀,它还是会被杀掉的。

所以如果你做小部件的目的是为了让程序常驻后台,那么你可以死心了。

但是!!!

虽然它还是能被杀掉,但是用户能看的见它了啊,用户可以点击就打开我们的 APP,所以还是很不错的。

Android 桌面小部件可以做什么?

小部件可以做什么呢?也就是我们需要实现什么功能。

  • 展示。每隔 N 秒/分钟,刷新一次数据;
  • 交互。点击操作 App 的数据;
  • 打开App。打开主页或指定页面。

这三个功能,大概就能满足我们绝大部分需求了吧。

实现桌面小部件需要什么?

如果你从来没有做过桌面部件,那肯定总是感觉有点慌,无从下手,毫无逻辑。

所以,实现它到底需要什么呢?

  • 先声明 Widget 的一些属性。在 res 新建 xml 文件夹,创建 appwidget-provider 标签的 xml 文件。
  • 创建桌面要显示的布局。 在 layout 创建 app_widget.xml。
  • 然后来管理 Widget 状态。实现一个继承 AppWidgetProvider 的类。
  • 最后在 AndroidManifest.xml 里,将 AppWidgetProvider类 和 xml属性 注册到一块。
  • 通常我们会加一个 Service 来控制 Widget 的更新时间,后面再讲为什么。

做完这些,如果不出错,就完成了桌面部件。

其实挺简单的,下面就让我们来看看具体的实现吧。

实现一个桌面计数器

先上效果图:

android person类_把你的程序放到桌面——Android桌面部件Widget

1. 声明 Widget 的属性

在 res 新建 xml 文件夹,创建一个 app_widget.xml 的文件。

如果 res 下没有 xml 文件,则先创建。

app_widget.xml 内容如下:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"android:initialLayout="@layout/app_widget"android:minHeight="110dp"android:minWidth="110dp"android:previewImage="@mipmap/ic_launcher"android:resizeMode="horizontal|vertical"android:widgetCategory="home_screen|keyguard">
           

属性的注释在上面写的很清楚了,这里需要说两点。

  • 关于宽度和高度的数值定义是很有讲究的,在桌面其实是按照“格子”排列的。

    看 Google 给的图。上面我们代码定义 110dp 也就是说,它占了2*2的空间。

android person类_把你的程序放到桌面——Android桌面部件Widget
  • 第二点很重要。有个 updatePeriodMillis 属性,更新widget的时间间隔(ms)。

    官方给提供了小部件的自动更新时间,但是却给了限制,你更新的时间必须大于30分钟,如果小于30分钟,那默认就是30分钟。

    可以我们就是要5分钟更新啊,怎么办呢?

    所以就不能使用这个默认更新,我们要自己来通过发送广播控制更新时间,也就是一开始总步骤里面第4步,加一个 Service 来控制 Widget 的更新时间,这个在最后一步添加。

2. 创建布局文件

在 layout 创建 app_widget.xml 文件。

<?xml  version="1.0" encoding="utf-8"?>
           

这里要注意的就是 桌面部件并不支持 Android 所有的控件。

支持的控件如下:

App Widget支持的布局:
           

3. 管理 Widget 状态

这里代码看起来可能有点多,先听我讲几个逻辑,再来看代码。

  • Android 的各种东西都有自己的生命周期,Widget 也不例外,它有几个方法来管理自己的生命周期。
android person类_把你的程序放到桌面——Android桌面部件Widget
  • 同一个小部件是可以添加多次的,所以更新控件的时候,要把所有的都更新。
  • onReceive() 用来接收广播,它并不在生命周期里。但是,其实 onReceive() 是掌控生命周期的。

    如下是 onReceive() 父类的源码,右边是每个广播对应的方法。

    上面我画的生命周期的图,也比较清楚。

android person类_把你的程序放到桌面——Android桌面部件Widget

然后我们再来看代码。

新建一个 WidgetProvider 类,继承 AppWidgetProvider。

主要逻辑在 onReceive() 里,其他的都是生命周期切换时,所处理的事情。

我们在下面分析 onReceive()。

public 
           

onReceive(Context context, Intent intent)

它传了两个值回来,Context 是跳转、发广播用的。

我们用来判断的是 Intent ,这里用到了 Intent 的两种方式。

Intent 作为信息传递者。

它要把信息传给谁,可以有三个匹配依据:一个是action,一个是category,一个是data。

String ACTION_UPDATE_ALL = "com.lyl.widget.UPDATE_ALL";

这个最后会在 AndroidManifest.xml 里面注册时写进去。

当每隔 N 秒/分钟,就发送一次这个广播,更新所有UI。

intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)

是广播事件里携带的 Intent 里设置的,用来匹配。

点击“恢复”按钮,计数器清零。

然后是 updateAllAppWidgets() 这个方法,更新 UI。

更新 UI 用到了一个新东西——RemoteViews。

怎么来理解 RemoteViews 呢?

因为,桌面部件并不像平常布局直接展示,它需要通过某种服务去更新UI。但是我们的App怎么能去控制桌面上的布局呢?

所以就需要有一个中间人,类似传递者。

我告诉传递者,你让他把我的 R.id.widget_txt ,更新成 “hello world”。

你让他把我的 R.id.widget_btn_open 按钮点击之后去响应 PendingIntent 这件事。

RemoteViews 就是承担着一个这样的角色。

然后再去理解代码,是不是稍微好一点了?

4. 最后就是 Service 控制 Widget 的更新时间

说好的 当每隔 N 秒/分钟,就发送一次这个广播。

那到底在哪发呢?也就是我们刚开始说的,用 Service 来控制时间。

新建一个 WidgetService 类,继承 Service。代码如下:

/**
 * 控制 桌面小部件 更新
 */
           

在 onCreate 开启一个计时线程,每1秒发送一个广播,广播就是我们自己定义的类型。

5. 在 AndroidManifest.xml 注册 桌面部件 和 服务

然后就只剩最后一步了,注册相关信息

相应的注释都在上面,如果我们的App进程被杀掉,服务也被关掉,那就没办法更新UI了。

也可以再创建一个 BroadcastReceiver 监听系统的各种动态,来唤醒我们的通知服务,这就属于进程保活了。

至此,以上代码写完,如果不出问题,运行之后直接去桌面看小工具,我们的App就在里面了,可以添加到桌面。

对于需要定时更新的桌面部件,保证自己的服务在后台运行也是一件比较重要的事情。

这个我们还是可以好好做一下,毕竟用户都已经愿意把我们的程序放到桌面上,所以只要友好的引导用户给你一定的权限,存活概率还是很大。

再不济,让用户主动点开App,也不失为一种办法。

好的创意才能造就好的App,代码只是实现。

最后放上项目地址:

https://github.com/Wing-Li/Widget

大家都在看

GitHub 上优质项目整理,不只 Android

Retrofit结合Lifecycle, 将Http生命周期管理到极致

关于 Java 的静态工厂方法,看这一篇就够了!

打开Flutter动画的另一种姿势——Flare

欢迎前往安卓巴士博客区投稿,技术成长于分享

期待巴友留言,共同探讨学习

android person类_把你的程序放到桌面——Android桌面部件Widget