Android Thread/Handler Error IllegalStateException: The specified message queue synchronization barrier token has not been posted

a 夏天 提交于 2019-12-07 16:29:07

问题


What I am trying to do

Update TextView on the UI Thread every 3 seconds x 10 times using a Handler and a background thread. The output on the UI should be "Repeat: 1" to begin with and after every 3 seconds, it should ++ the number. Eg "Repeat: 1" updates to "Repeat: 2" after 3 seconds and then to "Repeat: 3" after further 3 seconds.

How I am trying to do that

The first method that I am testing is to use a for loop with a Thread.sleep() to cause a n second delay for each loop. In each loop, I call the sendMessage(message) method and my theory is that the handleMessage() method on the UI Thread will be called every time. Here is the code:

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");
                    }

                }

            }
        });

    }

}

The result when I run

It updates once: "Repeat: 1" --> "Repeat: 2" and then the application stops/quits by itself. The error stack trace is as follows:

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.

What I have done so far

  1. This SO Question: recommends using dispatchMessage() instead of sendMessage(). Tried it and the same error happens.
  2. This SO Question: very similar problem as mine but there was no answer and the comments recommended to try a book on game development.
  3. This SO Question: appears to be a different problem as the problem here related to recycling the message whereas there is no recycling happening here.
  4. This SO Question: the outcome is similar but not there is no repeated attempt to continuously update the handler. The answer also not applicable to my scenario.

I suspect that a for loop with a Thread.sleep() method in each loop is a stupid implementation of what I am trying to do. My next choices are to try to use a CountDownTimer, Handler's existing delay functions like sendMessageDelayed() or postDelayed(). Finally, I will try to use a Timer.

But for now, I would like help to understand why this isn't working to learn before I try other solutions. I havent been able to use the information provided in the stacktrace to successfully identify what is going wrong nor has looking at each line in debug mode helped me.


回答1:


The problem is the use of Message object. It is a transient object, so once it has been sent to the Handler, the background thread should no longer use it. The receiving thread "owns" it at that point. Change you background thread to do something like this:

for (int i = 0; i < 11; i++) {
    Message msg = mHandler.obtainMessage(MY_MESSAGE_ID, i, 0);
    msg.sendToTarget();

    //  Delay or otherwise wait
}

On your UI thread's handler, you can then get the message and process it:

@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;
    }
}


来源:https://stackoverflow.com/questions/42554809/android-thread-handler-error-illegalstateexception-the-specified-message-queue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!