什么';处理可取消超时的典型Java技术是什么?
在运行安卓2.2的设备上,我想检测用户何时按下屏幕一段时间。想象一下,用短按(点)和长按(破折号)发送摩尔斯电码信息。我想在用户抬起手指时立即对短按做出反应,并在(比如)500毫秒后对长按做出反应,即使她继续按住手指 我已经研究了这两种方法,但是对于这个实现来说,这些方法看起来有些过头了。或者,我可能只是对直接处理线程并查看处理线程所需的所有代码感到冷淡 下面是我如何用其他语言完成这类工作的简化伪代码:什么';处理可取消超时的典型Java技术是什么?,java,android,timeout,Java,Android,Timeout,在运行安卓2.2的设备上,我想检测用户何时按下屏幕一段时间。想象一下,用短按(点)和长按(破折号)发送摩尔斯电码信息。我想在用户抬起手指时立即对短按做出反应,并在(比如)500毫秒后对长按做出反应,即使她继续按住手指 我已经研究了这两种方法,但是对于这个实现来说,这些方法看起来有些过头了。或者,我可能只是对直接处理线程并查看处理线程所需的所有代码感到冷淡 下面是我如何用其他语言完成这类工作的简化伪代码: public boolean onTouch(MotionEvent event) {
public boolean onTouch(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
timer = createObjectToCallback(callbackMethod, 500); // milliseconds
} else if (event.getAction() == MotionEvent.ACTION_UP) {
if (timer still exists) {
timer.kill();
// Do the short press thing
} else {
// Do nothing. It already happened when callbackMethod was triggered
}
}
}
public void callbackMethod() {
// Do the long press thing. The timer has already auto-destructed.
}
在Java中有哪些简单的方法可以做到这一点
==根据@zapl的答案进行编辑==
编写有效的代码是一回事。了解它的工作原理是另一回事
如果我理解正确,更新UI的线程已经在循环中运行。让我们想象一个非常简单的例子
主活动创建一个黑色画布,并包含一个onTouch
方法。当它启动时,它调用setOnTouchListener
。主线程现在不断地监听来自屏幕的输入。如果用户触摸屏幕的方式发生了更改,它将调用onTouch
方法,并提供有关更改的信息
假设onTouch
方法在接触点周围绘制了一个绿色圆圈。此圆是使用属于主线程的循环绘制的。绘制完成后,主线程开始检查屏幕上的新更改。如果没有更改,则不会再次调用onTouch
,绿点也不会移动
当用户抬起手指时,屏幕会向主线程提供更改的信息,并且onTouch
方法中的代码会擦除该点
Create interface
Has the screen detected a change? No: loop
Has the screen detected a change? No: loop
...
Has the screen detected a change? Yes: draw a green dot; loop
Has the screen detected a change? No: loop.
...
Has the screen detected a change? Yes: new position => redraw the green dot; loop
...
Has the screen detected a change? Yes: not touching => remove dot; loop
Has the screen detected a change? ...
假设如果用户的手指在至少500毫秒内没有移动,我希望圆点变为红色。不移动意味着没有回调到onTouch
。因此,我可以设置一个处理程序
,它将自己添加到主线程中的循环中。主线程现在在其循环中有两个操作
Create interface
Has the screen detected a change? No: loop
Has the screen detected a change? No: loop
...
Has the screen detected a change? Yes: a touch; draw a green dot; add Handler; loop
Has the screen detected a change? No;
Is it time for Handler to trigger? No: loop.
...
Has the screen detected a change? No;
Is it time for Handler to trigger? Yes: change dot color to red; remove Handler; loop.
Has the screen detected a change? No: loop.
...
Has the screen detected a change? Yes: not touching => remove dot; loop
Has the screen detected a change? ...
处理程序执行的任何代码都将阻塞主线程,直到它完成。
这是对处理程序功能的准确描述吗?在实际上不需要并行性的情况下使用线程确实是过火了,因为它增加了自己的问题集。您需要的是安排将来在同一线程上运行的代码。Android可以做到这一点。您可以安排Runnable
或消息到达。此外,还导出了简化周期事件调度的方法
但在这种情况下可能不需要它,因为存在
它配有安卓系统,可以区分几种类型的单点、长点和双击。它的行为也与系统的其余部分一致。你可能会想用它
更多信息
如果您真的想实现自己的,或者只是想看看如何使用处理程序的示例,请查看。它充满了与您发布的类似的代码(mHandler.hasMessages
,mHandler.removeMessages
,mHandler.sendEmptyMessageDelayed
)
注意:Handler
不是标准的Java类,因为在同一线程中调度事件需要一个基于消息队列的线程,并且没有标准的解决方案。它还取决于UI框架的线程安全性。如果您试图从后台线程修改ui,Android会尝试抛出异常。但是,同样的aproach应该可以用于Swing的事件分派线程(SwingUtilities.invokeLater
)
编辑:尝试解释Ui线程和处理程序:
处理程序执行的任何代码都将阻塞主线程,直到它完成为止
对。Android的主线程非常简单,如下所示:
public BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
public void loop() {
while (true) {
Runnable currentTask = queue.take(); // blocks until something happens
currentTask.run();
// repeat.
}
}
public void enqueue(Runnable runnable) {
queue.put(runnable);
}
public static void main(String[] args) {
startThreadsThatReceiveSystemEvents();
enqueue(new Runnable() {
@Override
public void run() {
Activity activity = createStartActivity();
activity.onCreate();
activity.onResume();
}
});
loop(); // fun fact: an android app will never return from here
// it's process is simply killed by the system
}
Android在启动/停止活动、绘制屏幕等方面所做的一切。。是某个对象排队的结果,以便运行循环在某个点对其进行计算。处理程序
使用相同的队列。你排队的每一件事都会被执行,并穿插在循环中已经发生的所有其他事情中。一个线程不能做与自身并行的事情,所以它都是顺序的。这就是处理程序任务阻止其他任务的原因
您的触摸事件示例基本上是正确的,只是没有积极地查看触摸屏。它通过与系统的连接得到通知。本质上还有另一个线程(如果您看过线程列表,那么就是绑定线程)在侦听来自系统的消息,一旦消息到达,这个线程所需要做的就是将它们排队等待主循环。如果循环正在等待,这会自动唤醒循环
主线程队列实际上不是一个简单的阻塞队列
,因为它还需要支持计划事件。它是一个特定于android的实现,名为,并且部分是用本机代码实现的。loop
方法也在它自己的类中(Looper
)。队列并不是直接使用Runnable
,它实际上是一个s队列,它可以包含Runnable
(在一个隐藏字段中),当它在消息中找到Runnable时,run循环将像上面的示例代码一样执行它
每个处理程序
都绑定到一个循环器
/消息队列
组合(因此绑定到一个线程)<代码>处理程序。post
/sendMessage
完成了构建正确消息并将其排队的肮脏工作。该消息有一个指向处理程序的链接,因此循环知道要调用哪个处理程序的方法
除了使用
E/AndroidRuntime(20941): at android.os.Looper.loop(Looper.java:130)
E/AndroidRuntime(20941): at android.app.ActivityThread.main(ActivityThread.jav a:3691)