为什么未来的线程不会在应用程序的后台运行?(Why Future thread doesn'

2019-09-26 14:39发布

今天,我发现了一个奇怪的问题。 我要的是检查服务器的可用性(特别是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秒线程睡眠)和我后”米就能看到mainActivity的UI和我的错误消息。

我预计可赎回<>应在背景和我的作品看mainActivity闪屏后没有问题(黑屏)。

你认为呢? 有什么问题可能是什么? 谢谢。

Answer 1:

这样看来,您正在执行的BackendCheck在主线程中调用。

延伸类Callable通常经由一个执行ExecutorService它是一个单独的线程本身,因而它在后台执行。 你可能想看看在Runnable接口或Thread ,如果你想运行一个单独的线程在返回值后台执行。 调用start方法将导致在一个单独的线程来执行由类的文档所示:

当一个对象实现接口可运行用于创建一个线程,启动线程将导致在独立执行的线程被称为对象的run方法。

如果您需要在执行结束返回一些数据我强烈推荐的ExecutorService ,但你很可能也逃脱使用FutureTask虽然我与该类经验较少。 希望帮助。



Answer 2:

好吧,我只是固定我的问题。 “njzk2”是正确的。 该问题future.get()其上运行或阻塞主线程。 我做了一些更改固定的问题。

  1. 首先,我把我execute()从一个新的线程方法。 因此,处理的整体将在另一个线程来完成。
  2. 我添加了新的start()来运行它的方法。
  3. 添加监听器在BackendCheck类和我的活动付诸实施。
  4. 因为我想显示一个对话框,如果服务器宕机,我在另一个线程然后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);
    }
}


文章来源: Why Future thread doesn't work in background of application?