Android的后台网络错误恢复 [英] Android background network error recovery

查看:262
本文介绍了Android的后台网络错误恢复的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定一个Android的意图服务的工作就是做后台网络通信(例如做一个REST调用来同步数据),当意图服务捕获了一个 IOException异常,什么是从错误中恢复好的做法呢?

Given an Android intent service whose job is do background network communication (e.g. make a REST call to synchronize data), when the intent service catches an IOException, what is a good practice for recovering from the error?

让我们假设传输数据的量足够小,我们是内容重试从头开始网络操作。如果设备丢失网络连接,我们希望当连接恢复,并再次尝试得到通知。如果我们没有失去联系,我们假设服务器或它的网络链路中断,并要延迟一段时间后再次尝试。

Let's assume the amount of data transferred is small enough that we're content retry the network operation from scratch. If the device lost network connection, we want to be notified when connectivity is restored and try again. If we didn't lose connection, we assume the server or its network link is down, and want to try again after a delay.

这不是关键,以尽快完成通信操作,但快并不意味着更好的用户体验,但它必须对带宽的占用和电池寿命进行权衡。

It is not critical to complete the communication operation as soon as possible, but quicker does mean a better user experience, although it must be traded off against bandwidth usage and battery life.

我们希望,这是一个共同的要求和功能烤成的Andr​​oid。如果是这样,它在哪里,如果没有,会是什么code智能重启意图服务样子?

Hopefully, this is a common requirement and the functionality is baked into Android. If so, where is it, or if not, what would the code to intelligently restart the intent service look like?

推荐答案

我创建的检查网络状态,并等待网络变得可用,或辅助类(如果可用),使用指数退避延迟。

I created a helper class that examines the network state and waits for the network to become available, or if it is available, delays using an exponential backoff.

/**
 * Handles error recovery for background network operations.
 * 
 * Recovers from inability to perform background network operations by applying a capped exponential backoff, or if connectivity is lost, retrying after it is
 * restored. The goal is to balance app responsiveness with battery, network, and server resource use.
 * 
 * Methods on this class are expected to be called from the UI thread.
 * */
public final class ConnectivityRetryManager {
    private static final int INITIAL_DELAY_MILLISECONDS = 5 * 1000;
    private static final int MAX_DELAY_MILLISECONDS = 5 * 60 * 1000;

    private int delay;

    public ConnectivityRetryManager() {
        reset();
    }

    /**
     * Called after a network operation succeeds. Resets the delay to the minimum time and unregisters the listener for restoration of network connectivity.
     */
    public void reset() {
        delay = INITIAL_DELAY_MILLISECONDS;
    }

    /**
     * Retries after a delay or when connectivity is restored. Typically called after a network operation fails.
     * 
     * The delay increases (up to a max delay) each time this method is called. The delay resets when {@link reset} is called.
     */
    public void retryLater(final Runnable retryRunnable) {
        // Registers to retry after a delay. If there is no Internet connection, always uses the maximum delay.
        boolean isInternetAvailable = isInternetAvailable();
        delay = isInternetAvailable ? Math.min(delay * 2, MAX_DELAY_MILLISECONDS) : MAX_DELAY_MILLISECONDS;
        new RetryReciever(retryRunnable, isInternetAvailable);
    }

    /**
     * Indicates whether network connectivity exists.
     */
    public boolean isInternetAvailable() {
        NetworkInfo network = ((ConnectivityManager) App.getContext().getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
        return network != null && network.isConnected();
    }

    /**
     * Calls a retry runnable after a timeout or when the network is restored, whichever comes first.
     */
    private class RetryReciever extends BroadcastReceiver implements Runnable {
        private final Handler handler = new Handler();
        private final Runnable retryRunnable;
        private boolean isInternetAvailable;

        public RetryReciever(Runnable retryRunnable, boolean isInternetAvailable) {
            this.retryRunnable = retryRunnable;
            this.isInternetAvailable = isInternetAvailable;
            handler.postDelayed(this, delay);
            App.getContext().registerReceiver(this, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            boolean wasInternetAvailable = isInternetAvailable;
            isInternetAvailable = isInternetAvailable();
            if (isInternetAvailable && !wasInternetAvailable) {
                reset();
                handler.post(this);
            }
        }

        @Override
        public void run() {
            handler.removeCallbacks(this);
            App.getContext().unregisterReceiver(this);
            retryRunnable.run();
        }
    }
}

这篇关于Android的后台网络错误恢复的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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