In my previous post, I've presented a Toast
solution via a Handler
and a Runnable
. While that solution was a nice one and serves pretty well, I still got an exception. Therefore, I've decided to implement a builder-type wrapper to cover all situations:
- Direct: just display a
Toast
, - Runnable: Build a custom
Runnable
to display a toast, apparently ideal forService
s - AsyncTask: Use the
onPostExecute()
of anAsyncTask
to display theToast
The result can be used like:
new ToastBuilder()
.onHandler(mHandler) // use a Handler (hence a Runnable)
.message("Show a Toast from an AsyncTask")
.withContext(this)
.build();
The Full Code
At the time of writing, the code looks like this:
package com.laurivan.android.common.ui.runnables;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
/**
* A class capable of building a toast using different methods:
* - a {@link java.lang.Runnable} + {@link android.os.Handler}
* - an {@link android.os.AsyncTask}
* - direct {@link android.widget.Toast}
* <p/>
* Created by ivanlla on 30/03/2015.
*/
public class ToastBuilder {
private static final String TAG = ToastBuilder.class.getSimpleName();
private Handler mHandler;
private Context mContext;
private String mMessage;
private ToastType mToastType = ToastType.TOAST_INVALID;
private int mToastDuration = Toast.LENGTH_SHORT;
private int mDelay = 0;
public ToastBuilder onHandler(Handler handler) {
if (mToastType != ToastType.TOAST_INVALID)
throw new IllegalStateException(
String.format("Cannot set a new Toast type from %s",
mToastType));
mToastType = ToastType.TOAST_RUNNABLE;
mHandler = handler;
return this;
}
public ToastBuilder withContext(Context context) {
mContext = context.getApplicationContext();
return this;
}
public ToastBuilder as(ToastType toastType) {
this.mToastType = toastType;
return this;
}
public ToastBuilder withDuration(int toastDuration) {
this.mToastDuration = toastDuration;
return this;
}
public ToastBuilder withDelay(int toastDelay) {
if (mToastType != ToastType.TOAST_RUNNABLE)
throw new IllegalStateException(
String.format("Delay is invalid for %s. Only a runnable toast can be used.",
mToastType));
this.mDelay = toastDelay;
return this;
}
public ToastBuilder message(String message) {
this.mMessage = message;
return this;
}
public void build() {
if (mMessage == null)
throw new IllegalStateException("Message is null. Please set message for a Toast");
if (mToastType == ToastType.TOAST_INVALID)
throw new IllegalStateException("Unset toast type.");
switch (mToastType) {
case TOAST_RUNNABLE:
if (mDelay > 0)
mHandler.postDelayed(new ToastRunnable(), mDelay);
else
mHandler.post(new ToastRunnable());
break;
case TOAST_ASYNC_TASK:
new ToastAsyncTask().execute();
break;
case TOAST_DIRECT:
Toast.makeText(mContext, mMessage, mToastDuration).show();
break;
default:
throw new IllegalStateException(
String.format("Unknown toast type: %s", mToastType));
}
}
public enum ToastType {
TOAST_INVALID,
TOAST_RUNNABLE,
TOAST_ASYNC_TASK,
TOAST_DIRECT,
}
private class ToastRunnable implements Runnable {
/**
* Starts executing the active part of the class' code. This method is
* called when a thread is started that has been created with a class which
* implements {@code Runnable}.
*/
@Override
public void run() {
Toast.makeText(mContext, mMessage, mToastDuration).show();
}
}
private class ToastAsyncTask extends AsyncTask<Void, Void, Void> {
/**
* Override this method to perform a computation on a background thread. The
* specified parameters are the parameters passed to {@link #execute}
* by the caller of this task.
* <p/>
* This method can call {@link #publishProgress} to publish updates
* on the UI thread.
*
* @param params The parameters of the task.
* @return A result, defined by the subclass of this task.
* @see #onPreExecute()
* @see #onPostExecute
* @see #publishProgress
*/
@Override
protected Void doInBackground(Void... params) {
try {
if (mDelay > 0)
Thread.sleep(mDelay);
} catch (InterruptedException e) {
Log.i(TAG, "Thread was interrupted. No big deal.");
}
return null;
}
/**
* <p>Runs on the UI thread after {@link #doInBackground}. The
* specified result is the value returned by {@link #doInBackground}.</p>
* <p/>
* <p>This method won't be invoked if the task was cancelled.</p>
*
* @param aVoid The result of the operation computed by {@link #doInBackground}.
* @see #onPreExecute
* @see #doInBackground
* @see #onCancelled(Object)
*/
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Toast.makeText(mContext, mMessage, mToastDuration).show();
}
}
}
If it's useful, I'll publish it on Github.
HTH,
Member discussion: