线程如何与 Android 中的 Handler 一起工作?
Posted
技术标签:
【中文标题】线程如何与 Android 中的 Handler 一起工作?【英文标题】:How does a thread work with Handler in Android? 【发布时间】: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();
);
);
【问题讨论】:
【参考方案1】:android 主线程建立在Looper 和Handler 两个核心概念之上。它转换为与线程和消息交互器相关的消息循环。所有 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
。这不是一个好的做法,因为这样会阻止用户与应用程序的交互。我建议研究另一种方法来满足您的要求。以上是关于线程如何与 Android 中的 Handler 一起工作?的主要内容,如果未能解决你的问题,请参考以下文章