Today I found a wierd problem. What I want is to check server availability (Particularly SSL checking) once application started and display proper message if server is down. This process should work in background and user is able to navigate the app if server has problem (app can works offline).
What I did is simple. In main activity I have
@Override
protected void onStart()
{
super.onStart();
// Check Internet connection
// Check Location sensor
// Check server accessibility
BackendCheck backendCheck = new BackendCheck(this);
if (!backendCheck.execute())
{
displayErrorDialog();
return;
}
}
This is BackendCheck
class:
public class BackendCheck implements Callable<Boolean>
{
private static final String TAG = BackendCheck.class.getSimpleName();
// Thread sleep time
private static final int THREAD_SLEEP = 5000;
// Number of attempts to call an API in order to get response
private static final int MAX_ATTEMPT = 3;
// Current attempt
private int counter = 0;
// The url that should be used in order to get server response
private String mTestUrl;
// App mContext
private Context mContext;
// Server status
private boolean mServerStatus = false;
public BackendCheck(Context context)
{
this(context, "");
}
public BackendCheck(Context context, String url)
{
this.mTestUrl = url;
this.mContext = context;
}
public boolean execute()
{
// Check #mTestUrl and use Feature API if this variable is empty
if (TextUtils.isEmpty(mTestUrl))
{
mTestUrl = PassengerConstants.URL_BASE + mContext.getResources()
.getString(R.string.uri_feature_payments);
}
// Get ExecutorService from Executors utility class, thread pool size is 10
ExecutorService executor = Executors.newFixedThreadPool(10);
do
{
// Increment counter
counter++;
// Submit Callable tasks to be executed by thread pool
Future<Boolean> future = executor.submit(this);
try
{
// Break Do-While loop if server responded to request (there is no error)
if (!future.get())
{
mServerStatus = true;
break;
}
}
catch (InterruptedException e)
{
Logger.error(TAG, e.getMessage());
}
catch (ExecutionException e)
{
Logger.error(TAG, e.getMessage());
}
} while (counter < MAX_ATTEMPT);
// Shut down the executor service now
executor.shutdown();
// Return server status
return mServerStatus;
}
@Override
public Boolean call() throws Exception
{
// Sleep thread for a few seconds
Thread.sleep(THREAD_SLEEP);
try
{
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(mTestUrl);
Logger.debug(TAG, "Attempt (" + counter + "), try to check => " + mTestUrl);
HttpResponse httpResponse = client.execute(get);
int connectionStatusCode = httpResponse.getStatusLine().getStatusCode();
Logger.debug(TAG,
"Connection code: " + connectionStatusCode + " for Attempt (" + counter
+ ") of request: " + mTestUrl);
if (isServerError(connectionStatusCode))
{
return true;
}
}
catch (IllegalArgumentException e)
{
Logger.error(TAG, e.getMessage());
}
catch (Exception e)
{
Logger.error(TAG, e.getMessage());
}
return false;
}
/**
* Server status checker.
*
* @param statusCode status code of HTTP request
* @return True if connection code is 5xx, False otherwise.
*/
private static boolean isServerError(int statusCode)
{
return (statusCode >= HttpURLConnection.HTTP_INTERNAL_ERROR);
}
}
What happens is, When I launch the application splash screen displays. Then after a few seconds mainActivity runs (first code) then - since my server is down (for testing purposes) - I have black screen for 15 seconds (since I set MAX_ATTEMPT to 3 and have 5 seconds thread sleep) and after that I'm able to see UI of mainActivity and my error message.
I expect Callable<> should works in background and I see mainActivity after splashScreen without problem (black screen).
What you think? What problem might be? Thanks.
It would appear that you are executing the
BackendCheck
callable in the main thread.Classes that extend
Callable
are usually executed via anExecutorService
which is a separate thread itself, thus it executes in the background. You may want to take a look at theRunnable
interface orThread
if you'd like to run a separate thread to execute in the background that does not return a value. Calling thestart
method will cause the class to execute in a separate thread as indicated by the documentation:If you need to return some data at the end of execution I highly recommend an
ExecutorService
but you could probably also get away with using aFutureTask
though I have less experience with that class. Hopefully that helps.Okay, I just fixed my problem. 'njzk2' is right. The problem is
future.get()
which is running on or blocking main thread. I fixed the issue by doing a few changes.execute()
method from a new thread. Therefore the whole of processing will be done in another thread.start()
method in order to run it.BackendCheck
class and implemented it in my activity.runOnUiThread(runnable)
uses to show the dialog in main thread.This is my complete code for your reference. In my activity:
And my
BackendCheck
class: