You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin:封装可复用Widget固定函数遇问题求助

问题原因

你创建的function类继承了Activity,但Activity是Android系统管理的组件,不能手动通过new实例化调用。手动创建的Activity实例没有经过系统的生命周期初始化,上下文(Context)是无效的,调用getSystemService、Toast.makeText等依赖有效上下文的方法时会出现异常或无效果。

正确解决方案

推荐两种Android中常用的代码复用方式:

方案一:静态工具类

将函数封装为静态工具方法,通过传入外部的有效Context(比如Activity实例)来获取系统服务、创建组件等。

import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Build
import android.widget.Toast

object WidgetUtils {
    // 传入有效Context,支持在任意Activity中调用
    fun pinAppWidget(context: Context, text: String?) {
        val urlCode = extractLinks(text)
        if (urlCode.isNotEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val mAppWidgetManager = context.getSystemService(AppWidgetManager::class.java)
                ?: return // 防止获取服务失败
            
            if (!mAppWidgetManager.isRequestPinAppWidgetSupported) {
                Toast.makeText(
                    context,
                    "Pin app widget is not supported",
                    Toast.LENGTH_SHORT
                ).show()
                return
            }

            val myProvider = ComponentName(context, MyWidget::class.java)
            val pinnedWidgetCallbackIntent = Intent(context, MyWidget::class.java)
            val successCallback = PendingIntent.getBroadcast(
                context, 0,
                pinnedWidgetCallbackIntent, PendingIntent.FLAG_IMMUTABLE
            )
            mAppWidgetManager.requestPinAppWidget(myProvider, null, successCallback)
        }
    }

    // 提取链接的工具方法,增加空值安全处理
    fun extractLinks(text: String?): String {
        if (text.isNullOrEmpty()) return ""
        val index = text.lastIndexOf("/")
        return if (index == -1) text else text.substring(index + 1)
    }
}

调用方式

在MainActivity或ConfigurableWidgetConfigureActivity中直接调用:

WidgetUtils.pinAppWidget(this, "your_text_here")

方案二:Context扩展函数

给Context添加扩展方法,这样所有Context子类(Activity、Service等)都可以直接调用,代码更简洁。

import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Build
import android.widget.Toast

// Context扩展方法,直接在Activity中调用
fun Context.pinAppWidget(text: String?) {
    val urlCode = extractLinks(text)
    if (urlCode.isNotEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val mAppWidgetManager = getSystemService(AppWidgetManager::class.java)
            ?: return
            
        if (!mAppWidgetManager.isRequestPinAppWidgetSupported) {
            Toast.makeText(
                this,
                "Pin app widget is not supported",
                Toast.LENGTH_SHORT
            ).show()
            return
        }

        val myProvider = ComponentName(this, MyWidget::class.java)
        val pinnedWidgetCallbackIntent = Intent(this, MyWidget::class.java)
        val successCallback = PendingIntent.getBroadcast(
            this, 0,
            pinnedWidgetCallbackIntent, PendingIntent.FLAG_IMMUTABLE
        )
        mAppWidgetManager.requestPinAppWidget(myProvider, null, successCallback)
    }
}

// 独立的工具方法,同样支持空值安全
fun extractLinks(text: String?): String {
    if (text.isNullOrEmpty()) return ""
    val index = text.lastIndexOf("/")
    return if (index == -1) text else text.substring(index + 1)
}

调用方式

在Activity中直接调用:

pinAppWidget("your_text_here")
额外优化点
  1. 原代码中的text!!会导致空指针异常,改为text.isNullOrEmpty()做安全处理
  2. 不需要额外数据时,requestPinAppWidget的Bundle参数可以传null替代空Bundle
  3. 获取AppWidgetManager后增加空判断,避免服务获取失败引发的异常

内容的提问来源于stack exchange,提问作者Paul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 15:33:13