Android widget基础指南

widget的概念最早是由一名叫Rose的苹果工程师提出,后来经过多方面机缘巧合的发展下,便有了今天Android平台上的小组件widget,一般APP开发可能应用场景较少,最常见的莫过于天气APP的widget。但对于从事IOT或车载方向的同学,定制化Launcher涉及修改的widget的相关业务则可能不少。

Android widget,即桌面插件,如下图红框所选中皆是插件:

其启动、加载运行流程全在Launcher中,其实现细节我们可以不关注(如果想了解需翻阅Launcher源码),只需要了解如何使用即可。实现步骤如下:

1、创建布局

在res/layout/目录中创建相应布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="#cca">

    <ImageView
        android:id="@+id/icon"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_centerInParent="true"
        android:src="@drawable/ic_launcher_round"/>

    <TextView
        android:id="@+id/tv_widget"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/icon"
        android:text="123"
        android:layout_centerHorizontal="true"/>

</RelativeLayout>

这里要注意的是,widget中并不支持所有布局控件,目前所支持的布局如下:

FrameLayout
LinearLayout
RelativeLayout
GridLayout

所支持的控件如下:

AnalogClock
Button
Chronometer
ImageButton
ImageView
ProgressBar
TextView
ViewFlipper
ListView
GridView
StackView
AdapterViewFlipper

不支持自定义View、这些类的子类,以及包括RecyclerView在内的其他没有声明的控件(是的,这些都不支持)。

2、创建配置文件

在res/xml/目录中创建相应文件:

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minHeight="180dp"
    android:minWidth="300dp"
    android:previewImage="@drawable/ic_launcher_background"
    android:initialLayout="@layout/layout_widget_info"
    android:updatePeriodMillis="10000"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen">

</appwidget-provider>

其各参数含义如下:

·minWidth 、 minHeight:widget的最小宽、高,在Launcher上,widget可以通过拉伸宽高来改变尺寸大小。

·previewImage:添加widget前的预览图片。

·initialLayout:widget所使用的布局。

·updatePeriodMillis:widget更新周期时间。(在 1.6 以后的版本中,Google从省电的角度规定,当 updatePeriodMillis 设置的值小于30min时,就会失效。也就是通过设置这个属性值,最短的更新间隔是30min。)

·resizeMode:widget尺寸调整规格、拉伸方向,"horizontal"代表可以水平拉伸,"vertical"代表可以竖向拉伸,"none"代表不能拉伸;默认为"none"。

·widgetCategory:widget的显示区域,"home_screen" 或 "keyguard"。

3、创建AppWidgetProvider

widget的功能都是通过AppWidgetProvider实现的,先继承此类然后复写相关方法,例如:

public class MainWidgetProvider extends AppWidgetProvider {

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
    }

    @Override
    public void onEnabled(Context context) {
        super.onEnabled(context);
    }

    @Override
    public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
        super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
    }

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        super.onDeleted(context, appWidgetIds);
    }

    @Override
    public void onDisabled(Context context) {
        super.onDisabled(context);
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
    }
}

其个参数含义如下:

·onUpdate():用户添加widget时,或者根据updatePeriodMillis定义的刷新时间到了的时候,会调用此函数刷新,可以在此函数里进行部分初始化刷新业务,也可以在这里设置点击事件等。

·onEnabled():widget第一次被添加时调用,比如用户添加widget后再删除再添加一次,只有第一次添加的时候会回调。

·onDisabled():当最后一个widget在Launcher桌面上被移除后调用,这时候适合做一些数据重置归零业务。

·onReceive():广播接收时调用。

·onAppWidgetOptionsChanged():widget 第一次添加或者拉伸等引起大小尺寸发生变化时调用该方法

·onDeleted():小插件被移除时会调用。(亲测不是所有机型都有效)

这里面最常使用的也就是onUpdate()和onReceive()了。

4、在AndroidManifest.xml中添加相关信息

我们观察下AppWidgetProvider的源码,会发现这其实就是个广播类:

因此,我们的MainWidgetProvider 在清单文件中也要以广播的形式注册:

<receiver
    android:name=".MainWidgetProvider"
    android:label="小组件">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data
        android:name="android.appwidget.provider"
        android:resource="@xml/widget_provider" />
</receiver>

这里的android.appwidget.action.APPWIDGET_UPDATE 动作的广播是所有widget都会接受到的广播,该广播根据android:updatePeriodMillis设定的间隔时间发出广播,用于定时更新桌面上的所有窗口小部件(部分机型可能无效)。resource指定xml 目录下widget对应的布局文件。

其效果(长按桌面,选择自己的小组件长按拖拽到桌面的过程)如下:

总结

widget所有流程基本上全在这里了,其余业务逻辑流程这里不再赘述。widget在部分机型上还拥有保活的功效(比如OV,没升鸿蒙之前的华为等),当然,你也有可能会发现在某些机型上部分API会失效,因为控制这部分API的Launcher是各大厂商必改的apk之一,如果想刷新widget,还是得通过广播的形式,同时注意进程的存活状态,但是考虑到很多方法不一定会生效,建议相关逻辑处理放到Service中。

相关推荐
找藉口是失败者的习惯28 分钟前
从传统到未来:Android XML布局 与 Jetpack Compose的全面对比
android·xml
Jinkey2 小时前
FlutterBasic - GetBuilder、Obx、GetX<Controller>、GetxController 有啥区别
android·flutter·ios
大白要努力!3 小时前
Android opencv使用Core.hconcat 进行图像拼接
android·opencv
天空中的野鸟4 小时前
Android音频采集
android·音视频
小白也想学C5 小时前
Android 功耗分析(底层篇)
android·功耗
曙曙学编程6 小时前
初级数据结构——树
android·java·数据结构
闲暇部落8 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX10 小时前
Android 分区相关介绍
android
大白要努力!11 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee11 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip