一、例子

1.1、步骤

  1. 创建一个新的 Android 项目,并打开主要的 Kotlin 类文件(通常是 MainActivity.kt)。

  2. MainActivity.kt 中,创建一个新的类来定义微件。例如,你可以创建一个名为 MyWidget 的类。

class MyWidget : AppWidgetProvider() {
    override fun onUpdate(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetIds: IntArray
    ) {
        // 在此处更新微件的视图和内容
    }
}
  1. AndroidManifest.xml 文件中注册微件类。在 <application> 标签内添加以下内容:
<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/my_widget_info" />
</receiver>
  1. 创建一个名为 my_widget_info.xml 的 XML 文件来定义微件的外观和行为。将以下内容添加到 res/xml/my_widget_info.xml 文件中:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="40dp"
    android:minHeight="40dp"
    android:updatePeriodMillis="0"
    android:initialLayout="@layout/my_widget_layout" />

注意:上述示例中的 @layout/my_widget_layout 是指定微件布局的资源文件,你需要创建一个名为 my_widget_layout.xml 的布局文件。

  1. 创建一个名为 my_widget_layout.xml 的布局文件来定义微件的用户界面。将以下内容添加到 res/layout/my_widget_layout.xml 文件中:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <!-- 添加微件的视图元素 -->

</LinearLayout>
  1. MyWidget 类的 onUpdate 方法中,使用 RemoteViews 对象来更新微件的视图和内容。将以下代码添加到 onUpdate 方法中:
override fun onUpdate(
    context: Context,
    appWidgetManager: AppWidgetManager,
    appWidgetIds: IntArray
) {
    for (appWidgetId in appWidgetIds) {
        val views = RemoteViews(context.packageName, R.layout.my_widget_layout)
        
        // 在此处配置微件的视图和内容
        
        appWidgetManager.updateAppWidget(appWidgetId, views)
    }
}
  1. 通过设置 views 对象的方法来配置微件的视图和内容,例如:
views.setTextViewText(R.id.widget_text, "Hello, Widget!") // 设置 TextView 的文本
  1. 保存并构建你的 Android 项目。

1.2、完整代码

class MyWidget : AppWidgetProvider() {

    override fun onUpdate(
        context: Context?,
        appWidgetManager: AppWidgetManager?,
        appWidgetIds: IntArray?
    ) {

        if (appWidgetIds != null) {
            for (appWidgetId in appWidgetIds) {
                val views = RemoteViews(context?.packageName ?: "", R.layout.my_widget_layout)

                // 在此处配置微件的视图和内容
                views.setTextViewText(R.id.widget_text, "Hello, Widget!"); // 设置 TextView 的文本

                appWidgetManager?.updateAppWidget(appWidgetId, views)
            }
        }
        super.onUpdate(context, appWidgetManager, appWidgetIds)
    }

}

二、请求网络

    override fun onUpdate(
        context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray
    ) {
        val scope = CoroutineScope(Dispatchers.Default)
        scope.launch {
            // 在后台线程中执行网络请求
            val result = makeNetworkRequest()
            // 更新微件的视图和内容
            withContext(Dispatchers.Main) {
                updateWidgetViews(context, appWidgetManager, appWidgetIds, result)
            }
        }
    }

    private suspend fun makeNetworkRequest(): String {
        // 执行网络请求并返回结果
        val url = "https://example.com/api/data"
        val response = OkHttpClient().newCall(Request.Builder().url(url).build()).execute()
        return response.body()?.string() ?: ""
    }

    private fun updateWidgetViews(
        context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, data: String
    ) {
        for (appWidgetId in appWidgetIds) {
            val views = RemoteViews(context.packageName, R.layout.my_widget_layout)

            // 更新微件视图中显示的数据
            views.setTextViewText(R.id.widget_text, data)

            appWidgetManager.updateAppWidget(appWidgetId, views)
        }
    }

在上述示例中,makeNetworkRequest() 函数使用 OkHttp 发起网络请求,并返回请求结果。在 updateWidgetViews() 函数中,通过 RemoteViews 对象更新微件的视图,将网络请求结果显示在微件中。

请注意,执行网络请求可能需要在 AndroidManifest.xml 文件中声明网络权限()。

确保在微件中进行网络请求时,处理好网络请求的异步逻辑,以免阻塞主线程和影响用户体验。

三、和 App 共用数据么

是的,Widget 可以和 app 共用数据。Android 提供了多种方式来实现 Widget 和 app 之间的数据共享。

以下是一些常用的数据共享方法:

  1. ContentProvider:通过 ContentProvider,你可以在 app 中暴露数据,并在 Widget 中使用 ContentResolver 来读取和更新这些数据。ContentProvider 提供了一种标准的数据访问接口,可以用于实现跨进程的数据共享。

  2. SharedPreferences:SharedPreferences 是一种轻量级的存储机制,可以用于在 app 和 Widget 之间共享简单的键值对数据。app 和 Widget 都可以使用同一个 SharedPreferences 文件进行读写操作。

  3. 文件共享:app 和 Widget 可以通过在共享的文件中读写数据来实现数据共享。例如,app 可以将数据写入一个文件,而 Widget 可以读取相同的文件来获取数据。

  4. 广播(Broadcast):app 可以通过发送广播来通知 Widget 更新数据。Widget 可以注册相应的广播接收器,接收来自 app 发送的广播,并根据接收到的广播内容更新数据。

  5. Intent:app 可以使用 Intent 发送包含数据的广播或启动带有额外数据的服务或活动。Widget 可以使用相同的 Intent 获取这些数据。

这些方法可以根据你的需求和具体情况选择适合的方式来实现 Widget 和 app 之间的数据共享。具体实现方式取决于你的应用架构和数据传输的复杂性。

四、API

在 Android 中,Widget(小部件)是通过继承自 AppWidgetProvider 类的类来创建的。这个类中定义了一些重要的方法,用于处理 Widget 的生命周期和事件。以下是一些常用的重要方法:

  1. onUpdate(): 当 Widget 需要更新时调用该方法。在该方法中,你可以更新 Widget 的视图和内容。这个方法在创建 Widget 实例、当 Widget 被添加到屏幕上或者当 Widget 的更新周期到达时都会被调用。

  2. onEnabled(): 当第一个 Widget 实例被添加到屏幕上时调用该方法。你可以在这里执行一些初始化操作,如启动后台服务或设置定期更新。

  3. onDisabled(): 当最后一个 Widget 实例从屏幕上移除时调用该方法。你可以在这里进行一些清理操作,如停止后台服务或清除定期更新。

  4. onDeleted(): 当 Widget 实例被从屏幕上移除时调用该方法。你可以在这里执行一些特定 Widget 实例的清理操作。

  5. onReceive(): 当接收到来自 Widget 的广播事件时调用该方法。你可以在这里处理 Widget 的点击事件或其他自定义的广播事件。

  6. onAppWidgetOptionsChanged(): 当 Widget 的尺寸或其他选项发生变化时调用该方法。你可以在这里根据新的尺寸或选项重新布局和更新 Widget。

  7. onRestored(): 当 Widget 从备份或恢复中重新创建时调用该方法。你可以在这里进行特定的恢复操作,例如重新加载之前保存的数据。

  8. onAppWidgetRemoved(): 当 Widget 实例从屏幕上被移除并且被系统彻底删除时调用该方法。你可以在这里执行一些最终的清理操作。

  9. onAppWidgetOptionsChanged(): 当 Widget 实例的选项发生变化时调用该方法。选项是由 AppWidgetManager 中的 updateAppWidgetOptions() 方法传递的。你可以在这里根据新的选项重新布局和更新 Widget。

这些方法都是在 AppWidgetProvider 类中进行重写的,你可以根据需要实现这些方法,并在其中编写自定义的逻辑来处理 Widget 的生命周期和事件。

请注意,在这些方法中不应该进行耗时的操作或阻塞主线程,因为 Widget 的更新和事件处理是在主线程中进行的。如需进行网络请求或其他耗时操作,建议使用后台线程或异步任务来执行。

06-13 18:35