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

用户无活动检测与PIN码屏问题:onUserInteraction重复触发及上下文丢失

解决Android无活动超时PIN码屏的两个问题

针对你遇到的两个问题——onUserInteraction()重复触发导致PIN码屏异常弹出,以及静态Runnable丢失上下文无法启动Activity,我整理了以下实用解决方案:

问题1:onUserInteraction()被重复调用的解决方法

onUserInteraction()会在所有用户交互(包括按键、触摸、甚至Activity跳转时的系统级交互)时触发,这就是你遇到重复调用的核心原因。更精准的方式是通过监听用户的触摸事件来判断真实交互行为,避免系统触发的额外调用。

修改方案:重写dispatchTouchEvent方法替代onUserInteraction(),仅在用户按下屏幕时重置超时计时器:

public abstract class BaseActivity extends AppCompatActivity {
    private static final String TAG = BaseActivity.class.getSimpleName();
    private static Handler disconnectHandler = new Handler(Looper.getMainLooper());
    // 用弱引用持有Activity上下文,避免内存泄漏
    private WeakReference<BaseActivity> activityRef;
    private Runnable disconnectCallback = new Runnable() {
        @Override
        public void run() {
            BaseActivity activity = activityRef.get();
            if (activity != null && !activity.isFinishing()) {
                Intent intent = new Intent(activity, CustomPinActivity.class);
                // 添加标志确保启动逻辑正确
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
                activity.startActivity(intent);
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        activityRef = new WeakReference<>(this);
    }

    public void resetDisconnectTimer() {
        disconnectHandler.removeCallbacks(disconnectCallback);
        disconnectHandler.postDelayed(disconnectCallback, getResources().getInteger(R.integer.disconnect_timeout));
    }

    public void stopDisconnectTimer() {
        disconnectHandler.removeCallbacks(disconnectCallback);
    }

    // 仅在用户真实触摸屏幕时重置计时器
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            resetDisconnectTimer();
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    protected void onResume() {
        super.onResume();
        resetDisconnectTimer();
    }

    @Override
    protected void onStop() {
        super.onStop();
        stopDisconnectTimer();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        activityRef.clear();
        stopDisconnectTimer();
    }
}

问题2:静态Runnable丢失上下文的解决方法

如果必须将Runnable设为静态(进一步降低内存泄漏风险),可以通过**弱引用(WeakReference)**绑定Activity上下文,同时在启动Activity前检查上下文有效性:

public abstract class BaseActivity extends AppCompatActivity {
    private static final String TAG = BaseActivity.class.getSimpleName();
    private static Handler disconnectHandler = new Handler(Looper.getMainLooper());
    // 静态弱引用持有当前活跃的Activity实例
    private static WeakReference<BaseActivity> sCurrentActivityRef;
    // 静态Runnable
    private static Runnable disconnectCallback = new Runnable() {
        @Override
        public void run() {
            BaseActivity activity = sCurrentActivityRef.get();
            if (activity != null && !activity.isFinishing()) {
                Intent intent = new Intent(activity, CustomPinActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
                activity.startActivity(intent);
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sCurrentActivityRef = new WeakReference<>(this);
    }

    // 其余方法(resetDisconnectTimer、stopDisconnectTimer、生命周期方法)与上方一致
}

不过更推荐第一种非静态Runnable+弱引用的实现,因为静态Runnable持有全局Activity引用可能会导致多Activity实例冲突,非静态版本更贴合单个Activity的生命周期。

额外优化建议

  • 给启动CustomPinActivity的Intent添加FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_NEW_TASK,避免重复创建实例并保证返回栈逻辑正确。
  • 在onDestroy中清空弱引用并停止计时器,彻底规避内存泄漏风险。
  • 保持CustomPinActivity的launchMode="singleTop"配置,防止多次弹出PIN码屏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:52:58