为何启动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
相关产品推荐
相关产品推荐

