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

求助:多次触发android.view.WindowManager$BadTokenException崩溃

我来拆解这个你遇到的高频Android崩溃问题,先看一下你提供的崩溃日志:

Fatal Exception: android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@42383ff8 is not valid; is your activity running?
at android.view.ViewRootImpl.setView(ViewRootImpl.java:536)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:259)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
at android.app.ActivityThread.handleResumeActivity(Act...

崩溃原因分析

这个BadTokenException本质上是你尝试在已经失效的Activity上下文上添加窗口类组件(比如Dialog、PopupWindow)。这里的BinderProxy是Activity窗口的唯一令牌,当Activity被销毁(比如用户返回、系统回收、配置重建)后,这个令牌就会失效,系统会拒绝任何基于这个失效令牌的窗口添加请求,直接抛出异常。

常见的触发场景有这几种:

  • 异步任务(网络请求、子线程耗时操作)完成后,在回调里弹出窗口,但此时用户已经退出了当前Activity
  • 错误地使用ApplicationContext创建Dialog/PopupWindow(ApplicationContext没有关联的窗口令牌,无法承载这类组件)
  • 屏幕旋转、语言切换等配置变化导致Activity重建,旧Activity实例的回调触发,尝试弹窗口
具体解决方法

针对这些场景,你可以逐个排查并应用对应的解决方案:

  • 弹出窗口前先检查Activity状态
    在调用弹出窗口的代码前,先判断Activity是否还处于活跃状态,用isFinishing()(兼容所有API)和isDestroyed()(API 17+)双重校验:

    if (!this.isFinishing() && !this.isDestroyed()) {
        // 这里写弹出Dialog/PopupWindow的逻辑
        AlertDialog dialog = new AlertDialog.Builder(this)
            .setTitle("提示")
            .setMessage("内容")
            .create();
        dialog.show();
    }
    
  • 用弱引用持有Activity(针对异步场景)
    如果是在异步任务(比如AsyncTask、OkHttp回调)中触发窗口弹出,不要直接持有Activity的强引用,改用WeakReference避免内存泄漏同时,在回调里先检查引用是否有效:

    // 异步任务示例
    private static class MyNetworkTask extends AsyncTask<Void, Void, String> {
        private final WeakReference<YourActivity> mActivityRef;
    
        public MyNetworkTask(YourActivity activity) {
            mActivityRef = new WeakReference<>(activity);
        }
    
        @Override
        protected String doInBackground(Void... params) {
            // 模拟网络请求
            return "请求结果";
        }
    
        @Override
        protected void onPostExecute(String result) {
            YourActivity activity = mActivityRef.get();
            if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
                // 弹出窗口
            }
        }
    }
    
  • 禁止用ApplicationContext创建窗口组件
    Dialog、PopupWindow必须依附于Activity上下文,所以创建时一定要传入当前Activity的this,而不是getApplicationContext()或者getApplication(),后者没有窗口令牌,必然会触发这个异常。

  • 在Activity生命周期内取消异步任务
    在Activity的onDestroy()或者onPause()方法中,取消所有未完成的异步任务、RxJava订阅、Coroutine Job等,从源头避免无效回调触发窗口弹出:

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 取消AsyncTask
        if (mMyNetworkTask != null && mMyNetworkTask.getStatus() != AsyncTask.Status.FINISHED) {
            mMyNetworkTask.cancel(true);
        }
        // 取消RxJava订阅
        if (mDisposable != null && !mDisposable.isDisposed()) {
            mDisposable.dispose();
        }
        // 取消Coroutine Job
        if (mJob != null && mJob.isActive()) {
            mJob.cancel();
        }
    }
    
  • 处理配置变化场景
    如果是屏幕旋转等配置变化导致的崩溃,可以在Manifest的Activity标签中添加android:configChanges="orientation|screenSize"(不推荐滥用,仅当你不需要系统重建Activity时使用),或者在onSaveInstanceState中保存任务状态,重建后恢复并判断是否需要弹出窗口。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:17:54