If you've ever had the need to display a Toast notification and customize it the way you thinks its right, say for example a custom duration other than Toast.LENGTH_SHORT and Toast.LENGTH_LONG, or to display styled text (italics/bold), you would know that the functionality provided byt the default Android Toast notification is rather limited.
I faced this recently in the design of my 'Tic Tac Toe Classic' game. For this game I wanted to display Tips and Interesting information about the game to users when the game was started (as shown in this pic below),
BTW, I encourage you to give this game a try and see how this actually looks like on your phone.
I first tried using the default Android Toast but soon discovered that the LENGTH_LONG duration was not long enough for users to actually read what was on the screen. So I had a look at the documentation and found a Toast.setDuration() method which seemed to be what I needed. I used this to set a custom duration of 10 seconds (10000 ms) to this function. However I was surprised to see that the Toast still disappeared quite soon. On digging deeper I found that the LENGTH_SHORT and LENGTH_LONG are treated as flags that are passed to the setDuration() and work out to a durations of 2.5 and 3 seconds respectively. i.e. there is no actual option to set a desired duration.
This was quite disappointing, but I soon came across a workaround (read "ugly hack") which was to invoke Toast.show() repeatedly which would keep it on screen longer. I tried this in a loop with a count of 3 (to get near to 10 seconds as possible) and everything seemed fine.
for (int i=0; i < 3; ++i) {
Toast.makeText(this, "My Text", Toast.LENGTH_LONG).show();
}
My joy was short lived though. When I tried a case where a user would quit the app just as the game was launched (say for e.g. another Activity/phone call interrupts it at this time), the toast was still displayed on screen for almost 10 seconds even after the app was quit (that is after all the behavior of Toast's in Android though) which seemed a little annoying. So I then started investigating alternatives to help me solve this small but annoying problem.I soon came across an Article on Android ViewStubs and this seemed just perfect for what I had in mind. In short an Android ViewStub is a lightweight view which does not participate in the layout, hence is very cheap to inflate and keep in memory. In my opinion this is exactly what I needed for my Window to be like.
So to achieve this I added a tip.xml within my res/layout directory for the layout of my custom toast I needed (which is cool as I was also able to add a header element and a a horizontal rule below it),
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:padding="10dip" android:background="@drawable/rounded_rectangle"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textStyle="bold" android:textColor="#FFF" android:text="My Tip Title" /> <View android:layout_gravity="center" android:layout_width="fill_parent" android:layout_height="2dip" android:background="#FFFFFFFF" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FFF" android:maxEms="15" android:id="@+id/tip_trivia_text" android:text="Test. Alpha Beta Charlie Bravo..." /> </LinearLayout>and in the XML layout where I wanted this Toast like Window to appear, I added a ViewStub which referenced the above tip.xml layout,
<ViewStub android:id="@+id/stub_import" android:inflatedId="@+id/toast_panel_import" android:layout="@layout/tip" android:layout_width="wrap_content" android:layout_height="wrap_content" />Finally within my Activity I added a simple AsyncTask that did nothing more than to inflate() the ViewStub, sleep for the required time and then disappear with setVisibility(View.GONE); as shown below,
private class MyCustomToastTask extends AsyncTask<Void, Void, Void> {
private long mToastDisplayTimeMs = 0;
private View mTipTriviaPanel;
// This runs on the UI thread itself
@Override
protected void onPreExecute() {
if (mTipTriviaPanel == null) {
// Get the display time and String to be populated
mToastDisplayTimeMs = getResources().getInteger(R.integer.toast_display_time_ms);
tipTriviaMsg = getResources().getStringArray(R.array.tip_trivia_list);
mTipTriviaPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
TextView text = (TextView) mTipTriviaPanel.findViewById(R.id.tip_trivia_text);
text.setText(tipTriviaMsg);
}
}
@Override
protected Void doInBackground(Void... arg0) {
try {
Thread.sleep(mToastDisplayTimeMs);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
// This is on the UI thread itself
@Override
protected void onPostExecute(Void v) {
mTipTriviaPanel.setVisibility(View.GONE);
}
}
Thats it!. This worked excellently for me and resolved all the above problems I was facing. The only additional change I think could be added is that a fade animation to fade out the window (for better effect).
Also do check out my game on the Android Market. to see how this works firsthand (QR code below).
I hope you find this useful. If you have any alternatives or would like to add to this I would love to hear from you. Please leave a message if so.

