• 开发 AppWidget


    参考 https://www.cnblogs.com/joy99/p/6346829.html

    AppWidgetProvider

    AppWidgetProvider,其本质 BroadcastReceiver。用户用这个类去创建自己的 widget AppWidgetProvider 除构造方法外,总共只有下面这些方法:

    AppWidgetProvider::onEnable

    当小部件第一次被添加到桌面时回调该方法,可添加多次,但只在第一次调用。对用广播的 Action 为 ACTION_APPWIDGET_ENABLE。

    AppWidgetProvider::onUpdate

    当小部件被添加时或者每次小部件更新时都会调用一次该方法,配置文件中配置小部件的更新周期 updatePeriodMillis,每次更新都会调用。对应广播 Action 为:ACTION_APPWIDGET_UPDATE 和 ACTION_APPWIDGET_RESTORED 。

    AppWidgetProvider::onDisabled

    当最后一个该类型的小部件从桌面移除时调用,对应的广播的 Action 为 ACTION_APPWIDGET_DISABLED。

    AppWidgetProvider::onDeleted

    每删除一个小部件就调用一次。对应的广播的 Action 为: ACTION_APPWIDGET_DELETED 。
    AppWidgetProvider::onRestored : 当小部件从备份中还原,或者恢复设置的时候,会调用,实际用的比较少。对应广播的 Action 为 ACTION_APPWIDGET_RESTORED。
    AppWidgetProvider::onAppWidgetOptionsChanged
    当小部件布局发生更改的时候调用。对应广播的 Action 为 ACTION_APPWIDGET_OPTIONS_CHANGED。
    在 onReceive() 方法中,对上述事件进行分发

    public void onReceive(Context context, Intent intent) {
        // Protect against rogue update broadcasts (not really a security issue,
        // just filter bad broacasts out so subclasses are less likely to crash).
        String action = intent.getAction();
        if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
            Bundle extras = intent.getExtras();
            if (extras != null) {
                int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
                if (appWidgetIds != null && appWidgetIds.length > 0) {
                    this.onUpdate(context, AppWidgetManager.getInstance(context), appWidgetIds);
                }
            }
        } else if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
            Bundle extras = intent.getExtras();
            if (extras != null && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID)) {
                final int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
                this.onDeleted(context, new int[] { appWidgetId });
            }
        } else if (AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED.equals(action)) {
            Bundle extras = intent.getExtras();
            if (extras != null && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID)
                    && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS)) {
                int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
                Bundle widgetExtras = extras.getBundle(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS);
                this.onAppWidgetOptionsChanged(context, AppWidgetManager.getInstance(context),
                        appWidgetId, widgetExtras);
            }
        } else if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) {
            this.onEnabled(context);
        } else if (AppWidgetManager.ACTION_APPWIDGET_DISABLED.equals(action)) {
            this.onDisabled(context);
        } else if (AppWidgetManager.ACTION_APPWIDGET_RESTORED.equals(action)) {
            Bundle extras = intent.getExtras();
            if (extras != null) {
                int[] oldIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS);
                int[] newIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
                if (oldIds != null && oldIds.length > 0) {
                    this.onRestored(context, oldIds, newIds);
                    this.onUpdate(context, AppWidgetManager.getInstance(context), newIds);
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    继承 AppWidgetProvider 对 AppWidget 进行定制

    用户可以通过继承 AppwidgetProvider 的一个或者几个方法来定义自己的 widget 以及控制 widget 的更新

    package com.example.joy.remoteviewstest;
    
    import android.appwidget.AppWidgetManager;
    import android.appwidget.AppWidgetProvider;
    import android.content.Context;
    import android.widget.RemoteViews;
    
    /**
     * Implementation of App Widget functionality.
     */
    public class MyAppWidgetProvider extends AppWidgetProvider {
    
        static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                    int appWidgetId) {
    
            CharSequence widgetText = context.getString(R.string.appwidget_text);  
            // Construct the RemoteViews object
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.my_app_widget_provider);
            views.setTextViewText(R.id.appwidget_text, widgetText);
    
            // Instruct the widget manager to update the widget
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }
    
        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
            // There may be multiple widgets active, so update all of them
            for (int appWidgetId : appWidgetIds) {
                updateAppWidget(context, appWidgetManager, appWidgetId);
            }
        }
    
        @Override
        public void onEnabled(Context context) {
            // Enter relevant functionality for when the first widget is created
        }
    
        @Override
        public void onDisabled(Context context) {
            // Enter relevant functionality for when the last widget is disabled
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    重写 AppWidgetProvider::onUpdate 方法的逻辑,对 AppWidget 的样式进行定义,具体实现思路如下:

    1. 新建一个 RemoteViews 对象,为其绑定对应布局文件
    2. 通过 AppWidgetProvider::updateAppWidget 方法将一个 RemoteViews 对象传递给 AppWidgetProvider,由 AppWidgetProvider 实现后续的逻辑
      在 AndroidManifest 中注册 AppWidgetProvider

    AppWidgetProvider,其本质 BroadcastReceiver,需要在 AndroidManifest 中注册

    <receiver android:name=".MyAppWidgetProvider">
        <intent-filter>
           <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        intent-filter>
    
        <meta-data
            android:name="android.appwidget.provider"
            android:resource="@xml/my_app_widget_provider_info" />
    receiver>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    名为 android.appwidget.action.APPWIDGET_UPDATE 的 action 将作为系统识别的表示,系统将通过 PackageManager 扫描该 action,并根据 meta-data 中 android.appwidget.provider 指定的 xml 文件里的配置去生成 AppWidget
    该配置形如

    
    <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
        android:initialKeyguardLayout="@layout/my_app_widget_provider"
        android:initialLayout="@layout/my_app_widget_provider"
        android:minHeight="40dp"
        android:minWidth="40dp"
        android:previewImage="@drawable/example_appwidget_preview"
        android:resizeMode="horizontal|vertical"
        android:updatePeriodMillis="86400000"
        android:widgetCategory="home_screen">
    appwidget-provider>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    这里配置了一些小部件的基本信息,常用的属性有 initialLayout 就是小部件的初始化布局, minHeight 定义了小部件的最小高度,previewImage 指定了小部件在小部件列表里的预览图,updatePeriodMillis 指定了小部件更新周期,单位为毫秒。更多属性,可以查看API文档

    RemoteViews

    下面简单说说 RemoteViews 相关的几个类。

    RemoteViews

    RemoteViews,从字面意思理解为它是一个远程视图。是一种远程的 View,它在其它进程中显示,却可以在另一个进程中更新。RemoteViews 在 Android 中的使用场景主要有:自定义通知栏和桌面小部件。
    在RemoteViews 的构造函数中,第二个参数接收一个 layout 文件来确定 RemoteViews 的视图;然后,我们调用RemoteViews 中的 set 方法对 layout 中的各个组件进行设置,例如,可以调用 setTextViewText() 来设置 TextView 组件的文本。
    前面提到,小部件布局文件可以添加的组件是有限制的,它可以支持的 View 类型包括四种布局:FrameLayout、LinearLayout、RelativeLayout、GridLayout 和 13 种View: AnalogClock、Button、Chronometer、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView、AdapterViewFlipper、ViewSub。注意:RemoteViews 也并不支持上述 View 的子类。
    RemoteViews 提供了一系列 setXXX() 方法来为小部件的子视图设置属性。具体可以参考 API 文档。

    RemoteViewsService

    RemoteViewsService,是管理 RemoteViews 的服务。一般,当 AppWidget 中包含 GridView、ListView、StackView 等集合视图时,才需要使用 RemoteViewsService 来进行更新、管理。RemoteViewsService 更新集合视图的一般步骤是:

    1. 通过 setRemoteAdapter() 方法来设置 RemoteViews 对应 RemoteViewsService 。
    2. 之后在 RemoteViewsService 中,实现 RemoteViewsFactory 接口。然后,在 RemoteViewsFactory 接口中对集合视图的各个子项进行设置,例如 ListView 中的每一Item。

    RemoteViewsFactory

    通过RemoteViewsService中的介绍,我们知道 RemoteViewsService 是通过 RemoteViewsFactory 来具体管理 layout 中集合视图的,RemoteViewsFactory 是 RemoteViewsService 中的一个内部接口。RemoteViewsFactory 提供了一系列的方法管理集合视图中的每一项。例如:
    RemoteViews getViewAt(int position)
    通过getViewAt()来获取“集合视图”中的第position项的视图,视图是以RemoteViews的对象返回的。
    int getCount()
    通过getCount()来获取“集合视图”中所有子项的总数。

  • 相关阅读:
    QT5.15使用VISA接口连接GPIB设备和USB设备
    Haproxy实现七层负载均衡
    Qt QMultiMap
    LeetCode刷题(python版)——Topic65.有效数字
    Android毕业设计开题报告基于Uniapp+SSM实现的公园植物介绍APP
    阿里云验证SSL证书
    Win11 22000.918(KB5016691)正式版发布,解决一系列问题!
    网络安全(黑客)自学
    云原生底座之上,顺丰智慧供应链领跑的秘密
    学习笔记-IPC$(Internet Process Connection)
  • 原文地址:https://blog.csdn.net/lzs781/article/details/127972469