简体   繁体   中英

runOnUiThread() no executing when using Thread.sleep()

I'm using code that looks like this :

_thread = new Thread(){
            @Override
            public void run() {
                try {
                    while (true) {
                        operate();
                        Thread.sleep(DELAY);
                    }
                } catch (InterruptedException e) {
                    // Doesn't matters...
                }
            }
  };

operate function looks like this :

    // does things....
    activity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            // adds an ImageView to the screen
        }
    });
    // does other things...

At the bottom line, what i wanted to achieve is an operation that happens once in a while, without interrupting the main thread and the UI, something like a game-loop.

In the first 2 times that operate() runs, it adds the ImageView and everything is alright, but after 2 or 3 times it stops adding the ImageViews, but the UI is still running as usual. When i debugged the problem, i found out that after 3 times the run() method of the Runnable isn't called anymore, even thought the operate function was called.

The wired thing (for me) was that when i removed the Thread.sleep, everything worked fine (much faster of course...). I tried to replace it with a very long for loop (just for checking) and it worked, but of course it is not an appropriate solution to the problem.

I read about the problem, most of the people that asked this question did a thread.sleep or an infinite loop on the main thread, but, as i see it, i didn't do such thing. Many people wrote that you should replace the Thread.sleep with Handler.postDelayed. I tried to do it but it didn't work, maybe I did it wrong. I even tried replacing the runOnUiThread with other options I found on the internet, but all of them gave me the same exact results. I tried to replace the method that I'm adding the view to the activity, but all of them, again, gave the same result.

The waiting is crucial for this application . I got to find a way to wait sometime and then execute a function on the UI thread, cause this pattern returns at least a couple of times in my application.

It sounds like you want a post delay so that you can do the code on the UI thread after some delay. Handler Post Delay .

private static final int DELAY = 500;
private Handler mHandler;
private Runnable mRunnable;

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

    start();
}

private void start()
{
    mHandler = new Handler();
    mRunnable = new MyRunnable(this);
    mHandler.postDelayed(mRunnable, DELAY);
}

private void stop()
{
    mHandler.removeCallbacks(mRunnable);
}

private void doSomething()
{
    // Do your stuff here.

    // Reschedule.
    mHandler.postDelayed(mRunnable, DELAY);
}

Recommended way of creating a Runnable.

private static class MyRunnable implements Runnable
{
    private WeakReference<MainActivity> mRef;

    // In here you can pass any object that you need.
    MyRunnable(MainActivity activity)
    {
        mRef = new WeakReference<MainActivity>(activity);
    }

    @Override
    public void run()
    {
        // Safety check to avoid leaking.
        MainActivity activity = mRef.get();
        if(activity == null)
        {
            return;
        }

        // Do something here.
        activity.doSomething();
    }
}

There could be several reasons why the UI Runnable isn't being executed. Probably the activity variable has something messed up with it or it's referencing the context incorrectly, or as you said the Thread.sleep() could be causing an issue. At this point more parts of the code needs to viewed to better solve the problem.

A better way of implementing your logic is to use a scheduled Timer instead of using an infinite loop with a Thread.sleep() in it. It will execute the code within a background thread. And then use a Handler to update the UI instead of activity.runOnUiThread() . Here's an example:

// Global variable within the activity
private Handler handler;

// Activity's onCreate()
@Override
protected void onCreate(Bundle savedInstanceState) {
    handler = new Handler(getMainLooper());
    Timer timer = new Timer("ScheduledTask");
    // Timer must be started on the Main UI thread as such.
    timer.scheduleAtFixedRate(new TimerTask() {

        @Override
        public void run() {
            operate();
        }
    }, 0L, DELAY);
}

private void operate() {
    // does things in background....
    handler.post(new Runnable() {
        @Override
        public void run() {
            // adds an ImageView to the screen from within the Main UI thread
        }
    });
    // does other things in the background...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM