I am writing a method for my android app where I make a RecyclerView invisible, and a ProgressBar visible. I then perform some logic, before resetting the two views to their original visibility state.
With just the setVisibility()
call, it works as intended. However, I am also required to call Thread.sleep()
to force a wait directly after performing the logic.
Initially, I have had trouble trying to call setVisibility()
to begin with. It simply did nothing. I have found many questions with similar problems, but not similar enough; I was unable to find a solution specific to my problem.
Creating a new method to simply call setVisibility()
, I found that this worked as intended. I started to move my logic over, line by line, until it stopped working.
As it stands, it still technically sets the visibility correctly. However, despite being several lines down from the setVisibility()
calls, my Thread.sleep()
seems to be forcing itself to run before setVisibility()
. I believe this was my original problem; Logically, the commands after Thread.sleep()
would run directly after, and effectivley undo my setVisibility()
on the very next frame.
This is my method:
public void SetMainInvisible(){
mRecyclerView.setVisibility(View.INVISIBLE);
mMainProgressBar.setVisibility(View.VISIBLE);
mTrainAdapter.RefreshAll();
Log.d("TEST", "FINISHED VIS");
try {
Thread.sleep(sSleepTime);
} catch (InterruptedException exception) {
// In the nature of a simple "Thread.sleep", there is no real reason to respond
// directly to interruption. If the sleep request is interrupted, the best course
// of action to preserve user experience is to simply move on. That said, we will
// still "re-enable" the flag that tells us the thread was interrupted, in case we
// should need to clarify if there was an interruption, later on. As is, this flag
// will be reset to false as soon as the exception is thrown.
Thread.currentThread().interrupt();
}
}
From my direct observation, when it calls, my log prints "FINISHED VIS". My application then enters the Thread.sleep()
stage, and waits for 3 seconds. My views then change their visibility, as directed by the very first lines. I do not have setVisibility()
anywhere else in my code.
I have tried reading further on Thread.sleep, but all references suggest exactly what I have been taught; when it executes, it forces the process to "sleep" for a set period of time. It should not force the method to postpone all other logic until it returns. On the contrary, the examples at Tutorial Point provide logic and output that suggests normal operation.
I know that I should never really be calling Thread.sleep()
, but it is a direct requirement of the exercise I am completing for University. Why is Thread.sleep()
forcing itself to run before any other command, despite being at the end of the method?
Changing visibility (or any other layout/drawing operation) does not have any immediate, synchronous effect on your user interface. Instead, essentially just a message is posted on the UI thread's message queue to take care of the change later.
Calling sleep()
on the UI thread is a no-no. You're blocking the UI thread and execution does not return to the message handler that would take care of the relayout/redraw messages waiting in the queue. Only after the sleep()
does the execution return to the message handler.
If you need to add delays to your code, use e.g. Handler#postDelayed()
to post a Runnable
of your own to the UI thread's message queue to be executed after a delay.