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

为何启动Thread后View.OnTouchListener停止响应?附代码示例

问题分析与解决方案

我来帮你拆解下这个问题的根源,以及对应的解决办法~

首先,核心问题出在线程执行完成后调用的fillLayout()方法上。我推测这个方法是重新填充了整个布局(比如调用了setContentView或者替换了LinearLayout l1的父容器内容),导致原来绑定了OnTouchListener的LinearLayout实例被新的视图实例替换掉了——新的视图并没有设置触摸监听器,所以之后的点击事件自然就无法响应了。

另外还有个小细节需要注意:bisruning变量没有用volatile修饰,多线程环境下可能会出现可见性问题,导致线程的判断逻辑出错。

具体解决步骤:

  • 修复线程可见性问题:给bisruning加上volatile关键字,确保主线程和子线程能实时看到变量的最新值:

    private volatile boolean bisruning = false;
    
  • 重新绑定触摸监听器:如果fillLayout()必须重新创建布局,那在填充完成后,重新获取LinearLayout实例并再次设置OnTouchListener。你可以把触摸监听器的定义提出来,方便重复调用:

    修改后的关键代码片段:

    // 把触摸监听器定义为成员变量,方便重复使用
    private View.OnTouchListener touchListener;
    private GestureDetector detector;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.your_layout); // 补充你原来缺失的布局加载代码
        c = getBaseContext();
        handler = new myHandler();
    
        // 初始化GestureDetector
        detector = new GestureDetector(c, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                return true;
            }
            @Override
            public boolean onDown(MotionEvent e) {
                Log.i("multiView", "Touch id=" + viewid);
                return true;
            }
            public boolean onSingleTapConfirmed(MotionEvent e) {
                return true;
            }
            @Override
            public void onLongPress(MotionEvent e) {
                super.onLongPress(e);
            }
        });
    
        // 初始化触摸监听器
        touchListener = new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                viewid = v.getId();
                return detector.onTouchEvent(event);
            }
        };
    
        // 第一次绑定监听器
        setupTouchListener();
    
        // 定时器逻辑保持不变
        Runnable timerrunnable = new Runnable() {
            @Override
            public void run() {
                if (!bisruning) {
                    thread = new Thread(MultiviewActivity.this);
                    thread.start();
                }
                timerhandler.postDelayed(this, 1000);
            }
        };
        timerhandler.postDelayed(timerrunnable, 5000);
    }
    
    // 新增方法:统一处理触摸监听器的绑定
    private void setupTouchListener() {
        LinearLayout lay = findViewById(R.id.l1);
        if (lay != null) {
            lay.setOnTouchListener(touchListener);
        }
    }
    
    class myHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.arg1) {
                case 0:
                    if (msg.arg2 == 1) {
                        fillLayout();
                        // 填充布局后,重新绑定监听器
                        setupTouchListener();
                    }
                    bisruning = false;
                    break;
            }
        }
    }
    
  • 优化方案(推荐):如果fillLayout()只是更新布局内容,而不是替换整个视图,那可以直接操作现有LinearLayout的子视图,不需要重新创建布局,这样原来的监听器会一直生效,也就不用重复绑定了。

比如把fillLayout()改成:

private void fillLayout() {
    LinearLayout lay = findViewById(R.id.l1);
    lay.removeAllViews();
    // 直接给现有布局添加新内容,而非重新加载整个布局
    TextView tv = new TextView(this);
    tv.setText("Updated content");
    lay.addView(tv);
}

这样就不会破坏原来绑定的触摸监听器了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:31:37