【问题标题】:How does a thread work with Handler in Android?线程如何与 Android 中的 Handler 一起工作?
【发布时间】:2021-11-14 08:52:43
【问题描述】:

在下面给出的代码部分中,我在单击按钮时运行了一个线程。一开始,线程会将文本设置到textView,然后它会休眠6秒。但是,实际上在单击按钮时,首先,线程休眠 6 秒,然后将文本设置为 textView。现在,为什么会出现这种语句执行流程不匹配的情况?

public class MainActivity extends AppCompatActivity {

    EditText editText;
    Button button;
    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        editText = findViewById(R.id.editText);
        button = findViewById(R.id.button);
        textView = findViewById(R.id.textView);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                button.setEnabled(false);
                runthread();
            }
        });

    }

    private void runthread() {
        final String s1 = editText.getText().toString();
        Handler handler = new Handler();
        handler.post(new Runnable() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText(s1);
                        button.setEnabled(true);
                        try {
                            Thread.sleep(6000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        });
    }
}

【问题讨论】:

    标签: java android multithreading


    【解决方案1】:

    Android 主线程建立在LooperHandler 两个核心概念之上。它转换为与线程和消息交互器相关的消息循环。所有 ui 员工都从中受益。例如,您使用的setText 只不过是向looper 发送一条新消息,一段时间后该消息被某个处理程序解析。正如您可能首先猜到的那样,每条消息都已入队。

    如果你通过上面的棱镜看你的例子,你会看到下面列出的步骤。(所有步骤都在主线程/主循环器上进行)

    Handler handler = new Handler(); <-- this handler is related to main looper
            handler.post(new Runnable() {   <-- enqueue new message to main looper
                @Override
                public void run() {
                    runOnUiThread(new Runnable() { <-- enqueue new message
                        @Override
                        public void run() {
                            textView.setText(s1); <-- enqueue new message of setting text
                            button.setEnabled(true); <-- enqueue new message of enabling button
                            try {
                                Thread.sleep(6000); <-- suspend thread for 6 seconds
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
    

    根据上述,在处理所有消息(包括设置文本和启用按钮)之前暂停线程。这样做的结果是顺序颠倒。

    #UPDATE 那么,我怎样才能让这个 sleep() 方法也入队呢?

         val handler = Handler();
            handler.post {
                runOnUiThread {
                    textView.text = "ABC";
                    button.isEnabled = true;
    
                }
            }
            handler.postDelayed({
                try {
                    Thread.sleep(6000);
                } catch (e: InterruptedException) {
                    e.printStackTrace();
                }
            }, 16) <-- 16 milliseconds is a time between frames
    

    【讨论】:

    • 你是想说 Thread.sleep() 方法没有入队直接执行?那么,我怎样才能将这个 sleep() 方法也加入队列呢?
    • 是的,这正是我所说的。活套与线相连。如果线程休眠,则不处理消息。您的第二个问题的答案在更新的答案中。顺便说一句,runOnUiThread 只不过是底层处理程序上的另一个 post 方法。
    • 如果我想在设置文本和启用按钮之间加入 Thread.sleep() 方法怎么办?
    • 这个例子很好地解释了处理程序和循环器的工作,但你不应该在主线程上使用Thread.sleep。这不是一个好的做法,因为这样会阻止用户与应用程序的交互。我建议研究另一种方法来满足您的要求。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-09
    • 1970-01-01
    • 2017-11-25
    • 2020-07-31
    • 2015-01-29
    • 2021-06-18
    相关资源
    最近更新 更多