【发布时间】:2019-04-18 03:38:34
【问题描述】:
请耐心等待,我对 android 还是有点陌生。
所以我正在制作一个复杂的按钮监听器。此侦听器应能识别短按、以某种方式闪烁(如正常的 onClick 功能)以及长按。
短按时,它将通过增加/减少值来更新(整数)textView。如果用户按住textView的按钮,它会不断增加/减少,直到按钮被释放。
到目前为止,我发现了 2 个关于此类问题的热门话题:
我对这些线程中的答案的问题是我觉得它们可以进一步分解。我不想创建一个单独的类来保存有关按钮侦听器的所有内容,而是想将在处理程序线程上运行的物理“任务”分离到它自己的类中。事实上,我相信这是 android 文档建议做的事情
https://developer.android.com/training/multiple-threads/communicate-ui#java
现在我有一个工作实现,用于在处理程序上的任务和 UI 线程之间正常传递数据以进行单个更改。但是,一旦我开始添加循环,它就会停止正常工作。如果我做一个 for 循环(即从 0 到 9),它似乎开始忽略帖子的“延迟”部分,并执行所有增量,并在全部完成后更新 UI。如果我尝试使用 while 循环,它永远不会更新 textView,原因与 for 循环可能失败的原因类似。
这是我实现的类,下面我会解释:
public class AutoUpdatingListener implements View.OnTouchListener, View.OnClickListener, View.OnLongClickListener {
private TextView textView;
private int textNumber;
private String decision;
private AutoUpdateTask updateTask;
private static final String MSG_KEY = "textData";
private final Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
Bundle bundle = msg.getData();
int data = bundle.getInt(MSG_KEY);
textView.setText(String.format(Locale.getDefault(), "%d", data));
}
};
public AutoUpdatingListener(TextView textView, String decision) {
this.decision = decision;
this.textView = textView;
this.textNumber = Integer.parseInt(textView.getText().toString());
updateTask = new AutoUpdateTask(handler, textNumber, decision, MSG_KEY);
}
public void onClick(View v) {
textNumber = (decision.equals("increase")) ? ++textNumber : (decision.equals("decrease")) ? --textNumber : textNumber;
textView.setText(String.format(Locale.getDefault(),"%d", textNumber));
}
public boolean onLongClick(View v) {
autoUpdate = true;
handler.postDelayed(updateTask, 500);
return true;
}
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
autoUpdate = false;
handler.removeCallbacks(updateTask);
}
return false;
}
}
这里是任务对象:
public class AutoUpdateTask implements Runnable {
private Handler handler;
private int textNumber;
private final String decision;
private final String MSG_KEY;
public AutoUpdateTask(Handler handler, int tempo, String decision, final String MSG_KEY) {
this.handler = handler;
this.tempo = tempo;
this.decision = decision;
this.MSG_KEY = MSG_KEY;
}
@Override
public void run() {
// 2nd variation would be to place the loop here
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
for (int i = 0; i < 10; i++) {
textNumber = decision.equals("increase") ? ++tempo : decision.equals("decrease") ? --tempo : tempo;
Message msg = handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putInt(MSG_KEY, tempo);
msg.setData(bundle);
handler.sendMessage(msg);
SystemClock.sleep(500);
}
}
}
这一切都在onCreate 方法中的以下上下文中使用:
AutoIncrementingListener customListener = new AutoIncrementingListener(textView, "increase");
upArrow.setOnClickListener(customListener);
upArrow.setOnLongClickListener(customListener);
upArrow.setOnTouchListener(customListener);
所以本质上,如果用户进行短按,它会更新字段并完成操作。如果用户按住按钮,它将首先转到 longClick 侦听器,并创建一个任务,该任务由对处理程序的引用、要增加的文本、“增加”确定和唯一的消息键组成。
然后任务会延迟发布到处理程序线程上,并执行(数字递增),然后创建一条消息发送回 UI 线程并更新 textView。这个过程一直持续到用户释放按钮。
这都是理论上的,正如我在上面解释的那样,它目前并没有按照定义的那样工作。
更新
我已经将循环放入任务的run() 方法中。在这个循环中,我添加了一个 sleep(500) 调用来阻止增量同时触发。
但是,UI 不更新的问题仍然存在(尽管发送了消息并实现了handleMessage() 功能)。 IE:大约 5 秒后,当它完成循环后,它最终更新了 textView。
结论
我正在放弃这个实现,对于那些遇到这个问题寻求答案的人,我深表歉意。我希望这个线程对您自己的实现有所了解。
通过上述更新,我通过调试意识到,无论执行时间如何,消息都是在循环完成后一起发送的。对于那些寻求这种实现的人,他们将不得不找出如何走捷径。
【问题讨论】:
标签: android multithreading handler