如何取消通过AppWidgetManager.requestPinAppWidget()创建的Widget?
Android AppWidget 取消创建问题
背景
- 手动拖拽Widget到主屏幕时,若已配置配置Activity,系统会自动启动它;若该Activity返回
RESULT_CANCELED,Widget创建流程会被取消。 - 通过
AppWidgetManager.requestPinAppWidget()主动添加Widget时,配置Activity不会自动启动,需开发者手动触发。
我的实现代码
启动配置页的广播接收器
object StartWidgetConfigureReceiver : BroadcastReceiver() { const val ACTION_NEW_WIDGET = "ACTION_NEW_WIDGET" override fun onReceive(context: Context?, intent: Intent?) { Intent(context, MyWidgetConfigureActivity::class.java).apply { action = ACTION_APPWIDGET_CONFIGURE putExtras(intent) context?.startActivity(this) } } }
触发Widget添加的代码
val appWidgetManager = AppWidgetManager.getInstance(context) val myProvider = ComponentName(applicationContext, MyWidgetProvider::class.java) val successIntent = PendingIntent.getBroadcast(applicationContext, 0, Intent(StartWidgetConfigureReceiver.ACTION_NEW_WIDGET), PendingIntent.FLAG_MUTABLE) appWidgetManager.requestPinAppWidget(myProvider,null, successIntent)
问题
我需要在某些场景下取消Widget创建,但在StartWidgetConfigureReceiver的onReceive方法中设置resultCode = Activity.RESULT_CANCELED完全无效。(注:我知道需要等待配置Activity的返回结果,但这不是当前核心问题,除非启动Activity的方式会影响取消逻辑。)
解决方案
问题核心:广播接收器无法通过设置resultCode来终止requestPinAppWidget发起的Widget创建流程。因为successIntent只是系统通知你用户已同意添加Widget的回调,此时系统已经进入Widget创建的待完成阶段,广播的result无法影响这个流程。
正确的处理方式是通过系统提供的cancelPinAppWidgetRequest()方法主动取消,步骤如下:
- 启动配置Activity时,必须获取其返回结果(用
registerForActivityResult替代直接startActivity)。 - 在配置Activity中根据用户操作返回对应结果码。
- 若收到
RESULT_CANCELED,调用cancelPinAppWidgetRequest()终止创建。
修改后的代码示例
1. 改造发起Widget添加的逻辑(在原Activity中处理)
// 在发起requestPin的Activity中注册Activity结果回调 val configResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == Activity.RESULT_CANCELED) { // 从Intent中取出requestId,用于取消请求 val requestId = result.data?.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID) requestId?.let { AppWidgetManager.getInstance(this).cancelPinAppWidgetRequest(it) } } } // 发起Widget添加请求 val appWidgetManager = AppWidgetManager.getInstance(this) val myProvider = ComponentName(this, MyWidgetProvider::class.java) // 生成请求ID,传递给后续流程 val requestId = appWidgetManager.createRequestPinAppWidgetIntent(myProvider, null).getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID) // 构造启动配置页的PendingIntent,携带requestId val configIntent = Intent(this, MyWidgetConfigureActivity::class.java).apply { action = ACTION_APPWIDGET_CONFIGURE putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, requestId) } val successIntent = PendingIntent.getActivity(this, requestId, configIntent, PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT) appWidgetManager.requestPinAppWidget(myProvider, null, successIntent)
2. 配置Activity处理返回结果
class MyWidgetConfigureActivity : AppCompatActivity() { private lateinit var requestId: Int override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.widget_config_layout) // 获取传递过来的requestId requestId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID) // 取消按钮逻辑 findViewById<Button>(R.id.btn_cancel).setOnClickListener { setResult(Activity.RESULT_CANCELED) finish() } // 确认按钮逻辑 findViewById<Button>(R.id.btn_confirm).setOnClickListener { // 这里添加你的配置保存逻辑 setResult(Activity.RESULT_OK) finish() } } }
关键说明
requestPinAppWidget发起后,系统会生成唯一的请求ID,必须通过EXTRA_APPWIDGET_ID传递到配置Activity,用于后续取消操作。cancelPinAppWidgetRequest()是官方唯一认可的终止requestPinAppWidget流程的方法,广播接收器的resultCode无法影响系统的Widget创建流程。
内容的提问来源于stack exchange,提问作者Doron Ben-Ari
相关产品推荐
相关产品推荐

