I'm new in Android development. Just wanted to test following code where clicking the button do some tasks. Toasts are popping out after the log shows the loop is ended as Toast is asynchronous. But
why does it behave like this? And so far as I know, this all happened in UI thread. If there is one thread, then how toast works asynchronously?
Thank you
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int i=0;
int j=0;
Log.d("tag", "sec "+i);
while(i++<15){
Log.d("tag", "sec "+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
Toast.makeText(getApplicationContext(),"num"+(j),Toast.LENGTH_SHORT).show();
j++;
}
}
});
Toast is asynchronous
To begin with, Toast's are not asynchronous by default.
why does it behave like this?
The lifetime of a toast created with Toast.LENGTH_SHORT
is 2 seconds. Now, if your UI thread is locked up (because of the Thread.sleep
), then the toast won't appear on the screen. It would 'die' before it is shown.
Run the whole block inside a newly created Thread
and only create & display the Toast
in the main thread,
You'll need to do something along the following lines,
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
int j = 0;
Log.d("tag", "sec " + i);
while (i++ < 15) {
Log.d("tag", "sec " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
final int finalJ = j;
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "num" + (finalJ), Toast.LENGTH_SHORT).show();
}
});
j++;
}
}
}).start();
}
});
You could also achieve similar results without using a different thread by using Handler.postDelayed
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
final int[] i = {0};
final int[] j = {0};
final int delayTime = 1000;
Log.d("tag", "sec "+ i[0]);
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
@Override
public void run() {
if(i[0]++<15) {
Log.d("tag", "sec " + i[0]);
Toast.makeText(getApplicationContext(), "num" + (j[0]), Toast.LENGTH_SHORT).show();
j[0]++;
handler.postDelayed(this, delayTime);
}
}
};
handler.postDelayed(runnable, delayTime);
}
});
P.S - Never use Thread.sleep
in main thread, it blocks the UI and results in poor UX.