为什么未来的线程不会在应用程序的后台运行? [英] Why Future thread doesn't work in background of application?

查看:230
本文介绍了为什么未来的线程不会在应用程序的后台运行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天,我发现一个奇怪的问题。我要的是检查服务器的可用性(特别是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.


  1. 首先,我称之为从一个新的线程我的的execute()方法。因此,处理的整个会在另一个线程来完成。

  2. 我为了运行增加了新的的start()方法。

  3. 添加监听器在 BackendCheck 类,并在我的活动付诸实施。

  4. 因为我想,如果服务器停机显示一个对话框,我在另一个线程则 runOnUiThread(可运行)用来显示主线程对话框。

  1. First, I call my execute() method from a new thread. Therefore the whole of processing will be done in another thread.
  2. I added new start() method in order to run it.
  3. Add a listener in BackendCheck class and implemented it in my activity.
  4. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆