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

快速切换时Launcher Activity旧实例onStop致Widget停止更新问题处理

问题分析与解决方案

问题原因

快速切换应用时,系统可能会创建新的LauncherActivity实例(比如启动模式配置、系统内存调度或快速切换触发的实例重建),旧实例的onStop方法会延迟到新实例完成onStart/onResume后才执行。由于每个Activity实例都独立调用appWidgetHost.stopListening(),旧实例的该操作会终止系统层面的Widget监听,直接导致前台新实例的Widget监听被意外关闭,最终无法接收更新。

推荐解决方案:全局管理AppWidgetHost生命周期

将AppWidgetHost的监听逻辑从Activity实例迁移到全局单例类,结合应用整体的前台/后台状态来控制监听的启动与停止,彻底避免多实例冲突。

1. 实现全局AppWidgetHost管理单例

创建一个单例类统一管理AppWidgetHost,通过统计前台Activity数量判断应用是否处于前台:

public class AppWidgetHostManager {
    private static AppWidgetHostManager sInstance;
    private AppWidgetHost mAppWidgetHost;
    private int mForegroundActivityCount = 0;
    private final Context mAppContext;

    private AppWidgetHostManager(Context context) {
        mAppContext = context.getApplicationContext();
        // 初始化WidgetHost,替换为你的Host ID
        mAppWidgetHost = new AppWidgetHost(mAppContext, R.id.app_widget_host_id);
    }

    public static synchronized AppWidgetHostManager getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new AppWidgetHostManager(context);
        }
        return sInstance;
    }

    public AppWidgetHost getAppWidgetHost() {
        return mAppWidgetHost;
    }

    public void onActivityStarted() {
        mForegroundActivityCount++;
        // 应用从后台切换到前台时启动监听
        if (mForegroundActivityCount == 1 && mAppWidgetHost != null) {
            mAppWidgetHost.startListening();
        }
    }

    public void onActivityStopped() {
        mForegroundActivityCount--;
        // 应用完全退到后台时停止监听
        if (mForegroundActivityCount == 0 && mAppWidgetHost != null) {
            mAppWidgetHost.stopListening();
        }
    }
}

2. 在Application中注册Activity生命周期回调

通过Application的生命周期回调,将所有Activity的启动/停止事件通知给全局管理器:

public class HomeScreenApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {}

            @Override
            public void onActivityStarted(@NonNull Activity activity) {
                AppWidgetHostManager.getInstance(activity).onActivityStarted();
            }

            @Override
            public void onActivityResumed(@NonNull Activity activity) {}

            @Override
            public void onActivityPaused(@NonNull Activity activity) {}

            @Override
            public void onActivityStopped(@NonNull Activity activity) {
                AppWidgetHostManager.getInstance(activity).onActivityStopped();
            }

            @Override
            public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {}

            @Override
            public void onActivityDestroyed(@NonNull Activity activity) {}
        });
    }
}

3. 修改LauncherActivity代码

移除Activity自身的startListening/stopListening调用,直接从全局单例获取AppWidgetHost:

// 移除原有onStart/onStop中的监听代码
@Override
protected void onStart() {
    currentState = ActivityState.STARTED;
    super.onStart();
    Log.d(TAG, "onStart currentState:"+currentState+" object:"+this);
    // 不再自行调用startListening,由全局管理器处理
}

@Override
protected void onStop() {
    super.onStop();
    Log.d(TAG, "onStop() currentState:" + currentState+" object:"+this);
    currentState = ActivityState.STOPPED;
    // 不再自行调用stopListening,由全局管理器处理
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 从全局单例获取Host实例
    appWidgetHost = AppWidgetHostManager.getInstance(this).getAppWidgetHost();
    // 原有Widget初始化逻辑保持不变
}

替代方案:实例级状态校验

如果不想修改全局逻辑,也可以在Activity的onStop中添加校验,仅当当前实例确实是最后一个活跃实例时才停止监听:

private static WeakReference<LauncherActivity> sCurrentActiveInstance;

@Override
protected void onStart() {
    super.onStart();
    currentState = ActivityState.STARTED;
    Log.d(TAG, "onStart currentState:"+currentState+" object:"+this);
    // 更新当前活跃实例引用
    sCurrentActiveInstance = new WeakReference<>(this);
    if (appWidgetHost != null) {
        appWidgetHost.startListening();
    }
}

@Override
protected void onStop() {
    super.onStop();
    Log.d(TAG, "onStop() currentState:" + currentState+" object:"+this);
    currentState = ActivityState.STOPPED;

    if (appWidgetHost != null) {
        LauncherActivity activeInstance = sCurrentActiveInstance != null ? sCurrentActiveInstance.get() : null;
        // 仅当当前实例不是活跃实例,或Activity正在被销毁时才停止监听
        if (activeInstance != this || isFinishing()) {
            appWidgetHost.stopListening();
        }
    }
}

此方案依赖弱引用跟踪活跃实例,可靠性略低于全局管理方案,适合场景简单的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 06:12:06