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

Android桌面Widget点击无响应:PendingIntent未触发,无法唤起链接弹窗

Android桌面Widget点击无响应问题修复方案

核心问题分析

  • PendingIntent类型错误:onUpdate中使用PendingIntent.getActivity()指向广播接收器AppWidgetProvider,类型不匹配导致点击事件无法触发广播回调。
  • 核心逻辑缺失:onReceive处理OPENBROWSER动作时仅修改文字颜色,未执行打开链接的关键逻辑。
  • 变量初始化时序问题:添加Widget前发送的广播可能未完成处理,导致text变量未初始化,后续逻辑出错。
  • 空值未处理:text为lateinit变量,未做空值判断,未赋值时会引发Uri.parse()异常。

修复后的完整代码

MyAppWidgetProvider.kt

import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.net.Uri
import android.os.Build
import android.util.Log
import java.util.Random

class MyAppWidgetProvider : AppWidgetProvider() {
    companion object {
        var text: String? = null // 改为可空类型,避免未初始化崩溃
        const val ACTION_OPEN_BROWSER = "OPENBROWSER"
        const val ACTION_GET_EDIT_TEXT = "GETEDITTEXT"
    }

    override fun onReceive(context: Context, intent: Intent) {
        Log.d("onReceive", intent.action.toString())
        
        // 优先处理自定义动作,再调用父类方法
        when (intent.action) {
            ACTION_GET_EDIT_TEXT -> {
                val editTextContent = intent.getStringExtra("EditText text")
                text = editTextContent?.takeIf { it.isNotEmpty() } ?: "https://example.com" // 默认值兜底
            }
            ACTION_OPEN_BROWSER -> {
                // 执行打开链接逻辑,弹出选择对话框
                text?.let { url ->
                    val browseIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply {
                        addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                    }
                    val chooserIntent = Intent.createChooser(browseIntent, "选择打开方式")
                    chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                    context.startActivity(chooserIntent)
                }
                // 点击反馈:修改文字颜色
                val appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1)
                if (appWidgetId != -1) {
                    val random = Random()
                    val color = Color.rgb(random.nextInt(256), random.nextInt(256), random.nextInt(256))
                    val remoteViews = RemoteViews(context.packageName, R.layout.widget_layout)
                    remoteViews.setTextColor(R.id.widget_text, color)
                    AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId, remoteViews)
                }
            }
            AppWidgetManager.ACTION_APPWIDGET_UPDATE -> {
                val appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS)
                appWidgetIds?.takeIf { it.isNotEmpty() }?.let {
                    updateWidget(context, it[0])
                }
            }
        }
        super.onReceive(context, intent)
    }

    private fun updateWidget(context: Context, appWidgetId: Int) {
        val views = RemoteViews(context.packageName, R.layout.widget_layout)
        views.setTextViewText(R.id.widget_text, text ?: "未设置链接") // 空值兜底显示
        AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId, views)
    }

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

        for (appWidgetId in appWidgetIds) {
            val views = RemoteViews(context.packageName, R.layout.widget_layout)

            // 创建广播类型的PendingIntent
            val intent = Intent(context, MyAppWidgetProvider::class.java).apply {
                action = ACTION_OPEN_BROWSER
                putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
            }
            // 适配Android版本的PendingIntent Flag
            val pendingIntentFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
            } else {
                PendingIntent.FLAG_UPDATE_CURRENT
            }
            val pendingIntent = PendingIntent.getBroadcast(context, appWidgetId, intent, pendingIntentFlags)

            views.setOnClickPendingIntent(R.id.widget_text, pendingIntent)
            views.setTextViewText(R.id.widget_text, text ?: "未设置链接")
            appWidgetManager.updateAppWidget(appWidgetId, views)
        }
    }
}

MainActivity.kt

import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_main)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }
        val button: Button = findViewById(R.id.button)
        button.setOnClickListener {
            val editTextContent = findViewById<EditText>(R.id.editTextText).text.toString()
            if (editTextContent.isEmpty()) {
                Toast.makeText(this, "请输入有效链接", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }
            // 直接赋值变量,避免广播时序问题
            MyAppWidgetProvider.text = editTextContent
            addWidgetToHomeScreen()
        }
    }

    private fun addWidgetToHomeScreen() {
        val appWidgetManager = AppWidgetManager.getInstance(this)
        val myProvider = ComponentName(this, MyAppWidgetProvider::class.java)
        if (appWidgetManager.isRequestPinAppWidgetSupported) {
            // 传入配置数据确保Widget初始化时能获取链接
            val extras = Bundle().apply {
                putString("EditText text", MyAppWidgetProvider.text)
            }
            appWidgetManager.requestPinAppWidget(myProvider, extras, null)
        } else {
            Toast.makeText(this, "当前设备不支持添加Widget", Toast.LENGTH_SHORT).show()
        }
    }
}

额外注意事项

  • 确保widget_layout.xml中的R.id.widget_text为普通TextView,无需手动设置clickable属性,RemoteViews会自动处理点击事件。
  • 输入的链接需为完整格式(如https://example.com),否则Intent.ACTION_VIEW无法识别并触发打开方式选择。
  • Android 12及以上版本必须指定PendingIntent.FLAG_IMMUTABLE或FLAG_MUTABLE,此处使用FLAG_IMMUTABLE因为广播Intent无需动态修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 11:17:33