为什么未来的线程不会在应用程序的后台运行? [英] Why Future thread doesn't work in background of application?
问题描述
今天,我发现一个奇怪的问题。我要的是检查服务器的可用性(特别是SSL检查)一次应用程序启动,如果服务器关闭显示正确的消息。这个过程应该在后台工作,用户可以浏览应用程序,如果服务器有问题(应用程序可以脱机工作)。
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;
}
}
这是 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运行(第一code),然后 - 因为我的服务器关闭(用于测试目的) - 我有15秒的黑屏(因为我设置MAX_ATTEMPT为3,在5秒线程睡眠)和之后我能够看到mainActivity的UI和我的错误信息。
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.
我预计可赎回&LT;>应在后台工作,我看到mainActivity闪屏后没有问题(黑屏)
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.
推荐答案
好吧,我只是固定我的问题。 njzk2'是正确的。问题是的Future.get()
这是上运行或阻塞主线程。我做了一些改变固定的问题。
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()
方法。因此,处理的整个会在另一个线程来完成。 - 我为了运行增加了新的
的start()
方法。 - 添加监听器在
BackendCheck
类,并在我的活动付诸实施。 - 因为我想,如果服务器停机显示一个对话框,我在另一个线程则
runOnUiThread(可运行)
用来显示主线程对话框。
- First, I call my
execute()
method from a new thread. Therefore the whole of processing will be done in another thread. - I added new
start()
method in order to run it. - Add a listener in
BackendCheck
class and implemented it in my activity. - Since I want to display a dialog if server is down and I'm in another thread then
runOnUiThread(runnable)
uses to show the dialog in main thread.
这是我的完整code,供大家参考。
在我的活动:
This is my complete code for your reference. In my activity:
@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);
}
}
这篇关于为什么未来的线程不会在应用程序的后台运行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!