【问题标题】:Android Thread/Handler Error IllegalStateException: The specified message queue synchronization barrier token has not been postedAndroid Thread/Handler Error IllegalStateException: 指定的消息队列同步屏障令牌尚未发布
【发布时间】:2017-07-22 03:25:34
【问题描述】:

我要做什么

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

我是如何做到这一点的

我正在测试的第一种方法是使用带有 Thread.sleep() 的 for 循环来为每个循环造成 n 秒的延迟。在每个循环中,我调用 sendMessage(message) 方法,我的理论是每次都会调用 UI 线程上的 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");
                    }

                }

            }
        });

    }

}

我运行时的结果

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

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

但现在,在我尝试其他解决方案之前,我想先了解一下为什么这不起作用。我无法使用堆栈跟踪中提供的信息来成功识别出问题所在,在调试模式下查看每一行也没有帮助。

【问题讨论】:

    标签: java android multithreading android-handler


    【解决方案1】:

    问题在于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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-02
      • 2017-03-22
      • 1970-01-01
      • 1970-01-01
      • 2018-08-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多