Widget 工作原理浅析

Android Widget 也称桌面小部件,是系统应用开发层面的一部分,可以把一个控件嵌入到另一个进程的串口里面。

一、自定义AppWidget

1 AppWidgetProvider 

继承广播,用于更新widget信息,实际是一个广播接受者,核心方法

  • onUpdate:更新时触发,直接参与到了widget界面的显示更新
  • onReceiver:收到特定广播触发

主要功能接收AppWidgetService发出的相应广播,做出相应的处理

public class ThirdAppWidget extends AppWidgetProvider {

@Override
public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); ComponentName componentName = new ComponentName(context, ThirdAppWidget.class); if ("btn_test".equals(intent.getAction())) { Toast.makeText(context, TAG, Toast.LENGTH_SHORT).show(); Log.i(TAG, "btntest i" + i); i++; RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.third_app_widget); views.setTextViewText(R.id.appwidget_text, "test" + i); appWidgetManager.updateAppWidget(componentName, views); } } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // There may be multiple widgets active, so update all of them this.appWidgetIds = appWidgetIds; Log.i(TAG, "onUpdate"); for (int appWidgetId : appWidgetIds) { updateAppWidget(context, appWidgetManager, appWidgetId); } }

 

updateAppWidget 可替换为 parttillyUpdateWidget()方法部分更新UI,提高效率

 

onUpdate遵循的基本流程

1、创建RemoteView

2、调用AppWidgetManager.updateAppWidget方法更新view

    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                int appWidgetId) {
        Log.i(TAG, "updateAppWidget");
        CharSequence widgetText = context.getString(R.string.appwidget_text);
        // 1 Construct the RemoteViews object
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.third_app_widget);
        views.setTextViewText(R.id.appwidget_text, widgetText);

        Intent intent = new Intent(context, ThirdAppWidget.class);
        intent.setAction("btn_test");
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
        views.setOnClickPendingIntent(R.id.btn, pendingIntent);

        // 2 Instruct the widget manager to update the widget
        appWidgetManager.updateAppWidget(appWidgetId, views);
    }

2 编写配置文件

主要是widget默认布局和一些参数。对应类AppWidgetProviderInfo 

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:initialKeyguardLayout="@layout/third_app_widget"
    android:initialLayout="@layout/third_app_widget"
    android:minWidth="140dp"
    android:minHeight="40dp"
    android:previewImage="@drawable/example_appwidget_preview"
    android:resizeMode="horizontal|vertical"
    android:updatePeriodMillis="20000"/>

3 清单文件中进行注册和配置

        <receiver android:name=".ThirdAppWidget">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                <action android:name="android.appwidget.action.MODE_UPDATE" />
                <action android:name="btn_test" />
            </intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/third_app_widget_info" />
        </receiver>

二、AppWidget加载显示

具有系统应用权限的app才可绑定显示widget,system\app目录下

1 创建APPWidgetHost实列。其主要功能

(1)开启Widget更新监听

    private fun init() {
       //1024 host_id 会被WidgetService记录,依据此id更新widget
        mAppWidgetHost = AppWidgetHost(applicationContext, 1024);
        mAppWidgetManager = AppWidgetManager.getInstance(applicationContext)
        mPackageManager = application.packageManager
        mUserManager = applicationContext.getSystemService(Context.USER_SERVICE) as UserManager
        mAllWidgetProviders = getAllProviders();
        loadAllBindWidgetProviders()
        mAppWidgetHost!!.startListening()
    }

(2)申请appwidgetId,并通过AppWidgetService进行绑定

val appWidgetId = mAppWidgetHost!!.allocateAppWidgetId()
val success: Boolean = mAppWidgetManager!!.bindAppWidgetIdIfAllowed(
appWidgetId,
info.profile,
info.provider,
Bundle()
)

(3)创建AppWidgetHostView实例

AppWidgetHostView是真正加载视图的地方,通过AppWidgetService查询appWidgetId对应的RemoteViews,传递给AppWidgetHostView

  private fun createWidgetView(provider: ComponentName): AppWidgetHostView? {
        val info: AppWidgetProviderInfo? = getAppWidgetProviderInfo(provider)
        if (info == null) {
            Log.i("aaaaaa", "getAppWidgetProviderInfo is null ")
            return null
        }

        val appWidgetId = mAppWidgetHost!!.allocateAppWidgetId()
        val success: Boolean = mAppWidgetManager!!.bindAppWidgetIdIfAllowed(
                appWidgetId,
                info.profile,
                info.provider,
                Bundle()
        )
        Log.i("aaaaa", "appWidgetID:" + appWidgetId + "bindSuccess:" + success + "mWidgetProvider:" + info)
        if (!success) {
            mAppWidgetHost?.deleteAppWidgetId(appWidgetId);
        }
        val view = mAppWidgetHost!!.createView(applicationContext, appWidgetId, info)
        appWidgetHostViews!!.add(view)
        return view
    }

添加权限

<uses-permission android:name="android.permission.BIND_APPWIDGET" />
<uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>

 2 获取AppWidgetProvideinfo

主要保存widget相关信息,如布局,大小,更新频率等,在widget所在工程,xml文件路径下配置:

third_app_widget_info.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:initialKeyguardLayout="@layout/third_app_widget"
    android:initialLayout="@layout/third_app_widget"
    android:minWidth="140dp"
    android:minHeight="40dp"
    android:previewImage="@drawable/example_appwidget_preview"
    android:resizeMode="horizontal|vertical"
    android:updatePeriodMillis="20000"/>

 参考:(15条消息) Android AppWidget系统框架_iteye_6233的博客-CSDN博客

(15条消息) android中AppWidgetManager_写Android的媛运气不会太差的博客-CSDN博客

实时更新widget_Android技巧_积木网(gimoo.net)

‌​⁢‍‍⁢‌‬⁤‌⁢⁡⁢‬‌​⁤‬⁡⁡⁢​‬⁢‌‍​‍​⁤‬‬‬⁢‍​​⁤​​⁣‬Android Widget工作原理浅析 - Hi ECARX云文档 (feishu.cn)

posted @ 2022-10-20 16:56  随易来了  阅读(359)  评论(0编辑  收藏  举报