今天我发现了一个奇怪的问题。我想要的是在应用程序启动后检查服务器可用性(特别是SSL检查),如果服务器关闭则显示正确的消息。此过程应在后台运行,如果服务器出现问题,用户可以导航应用程序(应用程序可以脱机工作)。
我做的很简单。在主要活动中我有
@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;
}
}
这是BackendCheck
类:
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);
}
}
当我启动应用程序启动屏幕时,会发生什么。然后几秒钟之后mainActivity运行(第一个代码)然后 - 因为我的服务器停机(用于测试目的) - 我有黑屏15秒(因为我将MAX_ATTEMPT设置为3并且有5秒线程睡眠)然后我和# 39;能够看到mainActivity的UI和我的错误信息。
我希望Callable&lt;&gt;应该在后台工作,我在splashScreen之后看到mainActivity没有问题(黑屏)。
你怎么想?可能是什么问题?感谢。答案 0 :(得分:1)
您似乎正在主线程中执行BackendCheck
callable。
扩展Callable
的类通常通过ExecutorService
执行,Runnable
是一个单独的线程本身,因此它在后台执行。您可能需要查看Thread
界面或FutureTask
,如果您想要在后台执行单独的线程不返回值。调用start
方法将导致类在单独的线程中执行,如文档所示:
当使用实现接口Runnable的对象创建线程时,启动该线程会导致在该单独执行的线程中调用该对象的run方法。
如果您需要在执行结束时返回一些数据,我强烈推荐ExecutorService
,但您可能也可以使用{{3}},但我对该课程的经验较少。希望这会有所帮助。
答案 1 :(得分:1)
好的,我刚刚解决了我的问题。 &#39; njzk2&#39;是正确的。问题是future.get()
正在运行或阻塞主线程。我通过做一些修改来解决这个问题。
execute()
方法。因此整个处理将在另一个线程中完成。start()
方法以便运行它。BackendCheck
课程中添加一个听众,并在我的活动中实施。runOnUiThread(runnable)
用于在主线程中显示对话框。这是我的完整代码供您参考。 在我的活动中:
@Override
protected void onStart()
{
super.onStart();
// Check Location sensor
// Check server accessibility
BackendCheck backendCheck = new BackendCheck(this);
backendCheck.setServerListener(new BackendCheck.BackendCheckListener()
{
@Override
public void onServerIsDown()
{
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
displayErrorDialog();
}
});
}
});
backendCheck.start();
}
我的BackendCheck
课程:
public class BackendCheck implements Callable<Boolean>
{
public interface BackendCheckListener
{
public void onServerIsDown();
}
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 mIsServerWorking = false;
// Server listener
private BackendCheckListener mListener;
public BackendCheck(Context context)
{
this(context, "");
}
public BackendCheck(Context context, String url)
{
this.mTestUrl = url;
this.mContext = context;
}
public void setServerListener (BackendCheckListener listener)
{
this.mListener = listener;
}
public void start()
{
Thread thread = new Thread()
{
@Override
public void run() {
boolean isServerWorking = execute();
if(!isServerWorking)
{
mListener.onServerIsDown();
}
}
};
thread.start();
}
private 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
ExecutorService executor = Executors.newFixedThreadPool(1);
do
{
// Increment counter
counter++;
// Submit Callable tasks to be executed by thread pool
Future<Boolean> future = executor.submit(this);
try
{
// Skip sleeping in first attempt
if(counter > 1)
{
// Sleep thread for a few seconds
Thread.sleep(THREAD_SLEEP);
}
// Break Do-While loop if server responded to request (there is no error)
if (!future.get())
{
mIsServerWorking = true;
break;
}
}
catch (InterruptedException e)
{
Logger.error(TAG, e.getMessage());
}
catch (ExecutionException e)
{
Logger.error(TAG, e.getMessage());
}
} while (counter < MAX_ATTEMPT);
// Try to shut down the executor service now
try
{
executor.shutdown();
executor.awaitTermination(THREAD_SLEEP, TimeUnit.MILLISECONDS);
}
catch (InterruptedException e)
{
Logger.error(TAG, e.getMessage());
}
// Return server status
return mIsServerWorking;
}
@Override
public Boolean call() throws Exception
{
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);
}
}