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

Android Oreo设备中AutoCompleteTextView获焦时showDropDown失效报错问题

解决Android Oreo上AutoCompleteTextView调用showDropDown报BadTokenException的问题

这个问题我在适配Oreo版本时刚好踩过坑,本质是Android 8.0(API 26)对窗口管理的token校验变得更严格,再加上你的代码里存在两个关键问题,导致了这个异常:

问题根源分析

  1. 上下文使用错误:你给googlePlaceAutocompleteAdapter传了getApplicationContext(),但AutoCompleteTextView的下拉窗口是依附于当前Activity的,Application上下文没有关联的Activity窗口token,在Oreo中会直接导致系统无法验证窗口的有效性。
  2. 焦点变化时机与窗口状态不同步:OnFocusChangeListener触发时,Activity可能还没完全进入resumed状态,或者控件的窗口token尚未准备就绪,直接调用showDropDown()就会抛出BadTokenException。

分步解决方案

1. 替换Adapter的上下文为Activity实例

这是最核心的修复步骤,先把Adapter的上下文改成当前Activity的实例,而不是Application上下文:

// 把getApplicationContext()换成你的Activity实例,比如MainActivity.this
googlePlaceAutocompleteAdapter = new googlePlaceAutocompleteAdapter(YourActivityName.this,
    android.R.layout.simple_list_item_1, this, list);
search_place.setAdapter(googlePlaceAutocompleteAdapter);

2. 优化showDropDown的调用时机

即使修复了上下文,焦点变化的时机还是可能存在窗口未就绪的问题,推荐两种更可靠的触发方式:

方式一:延迟调用,给系统留足窗口准备时间

用postDelayed延迟100-200ms执行,同时再次确认控件是否还处于焦点状态,避免后续焦点丢失导致的异常:

search_place.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if(hasFocus){
            search_place.postDelayed(new Runnable() {
                @Override
                public void run() {
                    // 再次校验焦点状态,防止中途焦点被其他控件抢走
                    if(search_place.isFocused() && !search_place.isPopupShowing()){
                        search_place.showDropDown();
                    }
                }
            }, 100);
        }
    }
});

方式二:改用OnTouchListener触发(更稳定)

用户点击控件时触发showDropDown,这个时机的窗口状态是完全就绪的,比焦点变化回调更可靠:

search_place.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_UP){
            // 确保下拉窗口没显示再调用
            if(!search_place.isPopupShowing()){
                search_place.showDropDown();
            }
        }
        // 返回false,让系统继续处理触摸事件,不影响正常输入
        return false;
    }
});

额外注意点

  • 确保你的Activity处于resumed状态时才调用showDropDown,如果是在onCreate或者onStart里触发,也可能因为窗口未完全创建而报错。
  • 可以在调用前先判断search_place.isAttachedToWindow(),确保控件已经绑定到窗口上。

内容的提问来源于stack exchange,提问作者Nirmal Kumar A

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:27:21