【问题标题】:Retrofit 2.0 cancel a Call objectRetrofit 2.0 取消一个 Call 对象
【发布时间】:2015-12-13 06:49:57
【问题描述】:

有人玩过Retrofit 2.0,特别是Call.cancel() 方法吗?

什么时候触发它的最佳时机?我曾尝试在 onStop()Fragment 中调用它,但遇到了一些问题,即屏幕显示关闭时调用被取消。我也尝试在FragmentonDestroy() 中调用它,但此方法不会取消在ViewPager 中触发的调用(例如在选项卡之间切换)

有人有这方面的工作示例吗?

我试图实现这个我的循环回购: https://github.com/lawloretienne/Loop

【问题讨论】:

    标签: android api retrofit2 request-cancelling


    【解决方案1】:

    “正确”的位置很大程度上取决于您的具体用例。正如您所发现的,不可能有一个万能的解决方案。根据您的需求,需要考虑以下几点:


    屏幕关闭时取消网络请求对您的应用来说是一个大问题吗?用户是否可能会在期望应用继续运行时关闭屏幕?

    • 如果没有,您可以安全地使用 onStop,正如您已经描述的那样。
    • 如果是这样,您可以将您的网络请求移至位于 ActivityFragment 生命周期之外的类(例如,使用单例网络请求管理器,或者更多地依赖于 Service 子类)。然后,您将能够根据具体情况处理取消。例如,您仍然可以随时取消生命周期回调中的请求(通过向经理发出信号),但您不会要求这样做。

    关于取消FragmentsViewPager 中触发的网络请求,您可能希望实现自己的虚假生命周期方法。这是a great pattern I've used a couple of times。要点如下:

    • ViewPager 使用的所有Fragments 实现一个接口,其中包含您关心的生命周期方法的“假”版本。

    例子:

    public interface FragmentLifecycle {
        public void onStartFragment();
        public void onStopFragment();
    }
    
    • ViewPager 上设置OnPageChangeListener,并在其中跟踪当前页面。每当页面发生变化时,调用传入/传出片段的适当方法。

    例子:

    private OnPageChangeListener pageChangeListener = new OnPageChangeListener() {
    
        int currentPosition = 0;
    
        @Override
        public void onPageSelected(int newPosition) {
            final FragmentLifecycle fragmentToShow = (FragmentLifecycle) pageAdapter.getItem(newPosition);
            fragmentToShow.onStartFragment();
    
            final FragmentLifecycle fragmentToHide = (FragmentLifecycle)pageAdapter.getItem(currentPosition);
            // Cancel network requests inside this callback. It
            // corresponds to the current page moving off-screen.
            fragmentToHide.onStopFragment(); 
    
            currentPosition = newPosition;
        }
    
        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
            // no-op
        }
    
        public void onPageScrollStateChanged(int arg0) {
            // no-op
        }
    };
    

    (我更新了链接示例以使用 onStart/onStop,因为您已经在问题中提到了该生命周期对。)

    希望这能让您了解如何最好地使用 Retrofit 2 中的新取消功能!让我们知道您的想法。

    【讨论】:

    • 我让它在 onDestroyView() 中工作。 gist.github.com/lawloretienne/5b8529f536bd0c5f72f7 但我的问题是在某些情况下会抛出 NetworkOnMainThreadException 以便 Call 对象永远不会被取消。如果不能每次都发生,这当然会破坏取消机制的目的。显然,OKHttp 中存在某种 Strictmode 问题。这里有一个问题github.com/square/okhttp/issues/1592
    • 是的,不幸的是,直到在 OkHttp 中修补它之前,我看不到避免这种情况的好方法。您需要依靠一种机制来手动忽略本应取消的调用结果,但这与您在没有 Call.cancel() 的情况下使用的解决方案相同。
    • 与此同时,我将Call.cancel() 包装在AsyncTask 中。 github.com/square/okhttp/issues/1592#issuecomment-143309765
    【解决方案2】:

    您尝试过UserVisibleHint吗?

       @Override
        public void setUserVisibleHint(boolean isVisibleToUser) {
            super.setUserVisibleHint(isVisibleToUser);
            if (isVisibleToUser) {
                    // fragment visible to user
            }else{
               // fragment invisible 
               // you can call Call.cancel() here
            }
        }
    

    【讨论】:

    • 即便如此,Call.cancel() 仍然可能因为 OKHttp 的 bug 而抛出异常。
    • 你能记录异常吗?
    • @KishanVaghela,我认为 toobsco42 说的错误是这样的:github.com/square/okhttp/issues/1592
    • @toobsco42 这个异常现在已经修复了!
    猜你喜欢
    • 2017-02-03
    • 1970-01-01
    • 1970-01-01
    • 2016-01-01
    • 1970-01-01
    • 2017-04-08
    • 2017-09-01
    • 1970-01-01
    相关资源
    最近更新 更多