Android线程/处理程序错误IllegalStateException:尚未发布指定的消息队列同步障碍标记

我想做什么

使用处理程序和后台线程每3秒更新一次UI线程上的TextView x 10次。 UI上的输出应该是“重复:1”开始,每3秒开始,它应该是++的数字。 例如,“重复:1”在3秒后更新为“重复:2”,然后在3秒后更新为“重复:3”。

我是如何尝试这样做的

我测试的第一个方法是使用带有Thread.sleep()的for循环来为每个循环引起第二个延迟。 在每个循环中,我调用sendMessage(message)方法,我的理论是每次都会调用UI Thread上的handleMessage()方法。 这是代码:

public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private TextView repeat; private Handler mHandler; private Thread backgroundThread; private String uiString; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(TAG, "onCreate(Bundle) called by Gil "); repeat = (TextView)findViewById(R.id.view_repeat); runInBackground(); backgroundThread.start(); mHandler = new Handler() { @Override public void handleMessage(Message message) { Bundle bundle = message.getData(); uiString = bundle.getString("count"); repeat.setText("Repeat: " + uiString); } }; } public void runInBackground() { Log.d(TAG, "runInBackGround() called by Gil"); backgroundThread = new Thread(new Runnable() { @Override public void run() { Log.d(TAG, "Background Thread started by Gil"); Bundle bundle = new Bundle(); Message message = new Message(); for (int i = 1; i < 11; i++) { bundle.putString("count", ""+i); message.setData(bundle); mHandler.sendMessage(message); try { // delay for 3 seconds Thread.sleep(3000); } catch (Throwable t) { Log.d(TAG, "Throwable Error caused by Thread.Sleep() & Gil"); } } } }); } } 

我跑的结果

它更新一次:“重复:1” – >“重复:2”,然后应用程序自动停止/退出。 错误堆栈跟踪如下:

 E/AndroidRuntime: FATAL EXCEPTION: main Process: personal.development.gilho.timerstuff, PID: 29226 java.lang.IllegalStateException: The specified message queue synchronization barrier token has not been posted or has already been removed. at android.os.MessageQueue.removeSyncBarrier(MessageQueue.java:289) at android.os.Looper.removeSyncBarrier(Looper.java:316) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1251) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6521) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:813) at android.view.Choreographer.doCallbacks(Choreographer.java:613) at android.view.Choreographer.doFrame(Choreographer.java:583) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:799) at android.os.Handler.handleCallback(Handler.java:733) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:146) at android.app.ActivityThread.main(ActivityThread.java:5679) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107) at dalvik.system.NativeStart.main(Native Method) Application terminated. 

到目前为止我做了什么

  1. 这个SO问题 :建议使用dispatchMessage()而不是sendMessage() 。 试了一下,发生了同样的错误。
  2. 这个SO问题 :与我的问题非常相似,但没有答案,建议试用一本关于游戏开发的书。
  3. 这个问题 :似乎是一个不同的问题,因为这里的问题与回收信息有关,而这里没有回收。
  4. 这个SO问题 :结果类似,但没有重复尝试不断更新处理程序。 答案也不适用于我的场景。

我怀疑在每个循环中使用Thread.sleep()方法的for循环是我想要做的愚蠢的实现。 我的下一个选择是尝试使用CountDownTimer,Handler现有的延迟函数,如sendMessageDelayed()postDelayed() 。 最后,我将尝试使用Timer

但就目前而言,我想帮助理解为什么在我尝试其他解决方案之前这是不可行的。 我无法使用stacktrace中提供的信息来成功识别出错的地方,也没有在调试模式中查看每一行帮助我。

问题是使用Message对象。 它是一个临时对象,所以一旦它被发送到Handler ,后台线程就不应再使用它了。 接收线程在那时“拥有”它。 更改后台线程以执行以下操作:

 for (int i = 0; i < 11; i++) { Message msg = mHandler.obtainMessage(MY_MESSAGE_ID, i, 0); msg.sendToTarget(); // Delay or otherwise wait } 

在UI线程的处理程序中,您可以获取消息并处理它:

 @Override public void handleMessage(Message message) { switch (message.what) { case MY_MESSAGE_ID: repeat.setText("Repeat: " + message.arg1); break; default: Log.w(TAG, "Invalid message received: " + message.what); break; } }