繁体   English   中英

在连续循环中与UI线程实现Handler交互

implementing Handler interaction with the UI thread on a continuous loop

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

忍受我,我还是android新手。

因此,我正在制作一个复杂的按钮侦听器。 该侦听器应识别短按,以某种方式闪烁(例如正常的onClick功能)以及长按。

短按一下,它将通过增加/减小值来更新(整数)textView。 如果用户在textView上按住按钮,它将持续增加/减少,直到释放按钮为止。

到目前为止,我已经找到了两个有关此类问题的流行线程:

这些线程中的答案存在的问题是,我认为它们可以进一步细分。 我不想创建一个单独的类来保存与按钮侦听器有关的所有内容,我想将在处理程序线程上运行的物理“任务”分离到它自己的类中。 实际上,我相信这是android文档建议的做法

https://developer.android.com/training/multiple-threads/communicate-ui#java

现在,我有一个有效的实现,用于在处理程序上的任务和UI线程之间进行单个更改的正常数据传递。 但是,一旦我开始添加循环,它就会停止正常工作。 如果我执行for循环(即从0到9),它似乎开始忽略帖子的“延迟”部分,并执行所有增量操作,并在完成时更新UI。 如果我尝试一个while循环,它绝不会由于for循环可能失败的类似原因而更新textView。

这是我实现的类,下面将解释:

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。

结论

我正在放弃此实现,对于那些遇到此问题寻求答案的人深感抱歉。 我希望该线程对您自己的实现有所了解。

通过上面的更新,我通过调试意识到无论执行时间如何,循环完成后消息都将一起发送。 对于那些寻求实现的人,他们将不得不找出如何简化这种现象的方法。

1 个回复

您无法以这种方式做您正在做的事情。 原因是在onLongClick期间,您运行了一个循环,该循环一次运行,而没有给UI时间刷新。

这是什么意思?

好吧,您实际上正在执行的是发送10条消息,一个又一个都延迟了500毫秒。 这意味着它们将一次全部到达,一个接一个地到达(彼此之间没有延迟),只是在第一个到达之前您将有500ms的间隔。

您需要做的是增加延迟,因此每条消息都会有自己的延迟,并且比前一条消息长500ms。

handler.postDelayed(updateTask, 500*(i+1));

那是第一件事。

第二个问题是,您在AutoUpdatingListener的C'Tor中创建了updateTask,因此每个更新任务都会为更新事件发送相同的编号(如果只是递增)。

问题在于,即使将其更改为以下代码:

for (int i = 0; i < 10; i++) {  // example usage of a long press (looping update)
        this.textNumber = Integer.parseInt(textView.getText().toString());
        updateTask = new AutoUpdateTask(handler, textNumber, decision, MSG_KEY);
        handler.postDelayed(updateTask, 500*(i+1));
    }

由于循环期间任务尚未运行,因此该号码没有机会更新,因此无法正常工作。

如此您可以在循环中作弊并增加数量,但这违反了所有逻辑。

for (int i = 0; i < 10; i++) {  // example usage of a long press (looping update)
            this.textNumber = Integer.parseInt(textView.getText().toString());
            updateTask = new AutoUpdateTask(handler, textNumber+i, decision, MSG_KEY);
            handler.postDelayed(updateTask, 500*(i+1));

        }

结论 您不能在同一线程中具有发送增量的循环和进行增量的处理程序。

2 在循环中实现多线程

我编写了一个使用不同线程数运行摩纳哥算法的应用程序,它们是 2,4,6 和 8 来计算 PI 的值。 目标是在使用更多线程时也能看到速度的提高。 问题是,我的代码并没有分工,而是简单地做了 2 次工作! 这是我的代码: 我得到的输出是: 我怎样才能让它分工而不是做 2 次? ...

3 在tkinter循环中连续访问线程

我正在尝试制作一个可连续绘制从微处理器接收到的信号的GUI。 我试图仅通过使用类来实现此目的,但由于仅GUI类处于对接状态,因此失败了。 现在我已经实现了线程化(或者至少我想我有!!),但是每个线程只运行一次。 这使我相信我不了解tkinter中的mainloop如何工作,所以我可以在线程 ...

5 后台线程与UI交互

我正在使用Eclipse和android编程。 AsyncThread可以与UI交互吗,我的后台线程中包含以下代码,并且会引发异常: ...

6 android AsyncTask和UI线程交互

我正在使用AsyncTask打开URL,访问服务器,获取内容并将其显示在主活动的列表视图中。 所提取的内容包括报纸的标题和网站的URL,如果单击“阅读”按钮,则将在第二个活动中将其显示在WebView上。 我立即对程序进行了编码,并且可以正常工作,但是当我回头看时,发现似乎有些道理,所以我主 ...

7 使用Timer和Handler处理UI线程

我在处理程序和timertask上遇到问题当我完成处理程序以检查连接并在两个单独的线程上更新UI时,它可以工作。 但是我想定期更新网络连接。 也许每5秒执行一次。 我使用Timer.schedule执行此操作。 但是申请失败了。 我不知道计时器是否不能进入UI线程。 另外,我不知 ...

8 我如何让 UI 线程连续运行

据我了解,因为 JavaScript 是单线程的,所以像 不会阻塞 UI 线程,会等到 UI 线程中断,以便它可以“跳入”并运行。 这是古老的 JavaScript 说法 “当无事可做时,检查[回调]队列。但只有在无事可做时才检查队列。” 我要说的是,有人可以向我展示一个示例,其中浏览 ...

9 从后台线程更新UI,该线程在线程完成时在主UI中的循环中调用

我有一个WinForms应用程序,它调用一个业务类方法,执行一些重要操作,每次调用大约需要5秒。 主窗体在循环中调用此方法。 这个循环可以运行10次,也可以运行10万次。 WinForms应用程序向业务类发送一个参数,并有一个区域显示每个方法调用所花费的时间以及该方法返回的值。 如何 ...

10 如何停止for循环中的handler.postDelayed?

对于使用“ handler.posDelayed”的这种类型,我没有看到真正的答案。 因此,我使用for循环多次执行“ handler.posDelayed”。 问题是,当我离开活动并重新启动活动时,处理程序中的新对象和旧对象也会被执行。 我不知道如何从处理程序中停止旧对象。 ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2021 STACKOOM.COM