Retrofit 2.0如何取消Call对象?

16

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

什么时候最适合触发它?我尝试在 FragmentonStop() 中调用它,但遇到了一些问题,当屏幕显示关闭时,调用被取消。我还尝试在 FragmentonDestroy() 中调用它,但这个方法不能取消在 ViewPager(例如在选项卡之间切换)中触发的调用。

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

我尝试在我的 Loop 存储库中实现了这个功能: https://github.com/lawloretienne/Loop

2个回答

11

“正确的位置”将在很大程度上取决于您具体的用例。正如您已经发现的那样,不太可能有一种通用解决方案。根据您所述的需求,以下是需要考虑的几个方面:


当屏幕关闭时取消网络请求是否是您的应用程序的一个大问题?用户在期望应用程序继续运行时是否有可能关闭屏幕?

  • 如果不是,您可以使用onStop,就像您已经描述的那样。
  • 如果是,则可以将您的网络请求移动到类中,该类存在于ActivityFragment 生命周期之外(例如,使用单例网络请求管理器或更多地依赖于Service子类)。然后,您将能够基于每种情况处理取消操作。例如,你仍然可以随时想要取消生命周期回调中的请求(通过向管理器发出信号),但你不需要这么做。

关于取消由ViewPager中的Fragments触发的网络请求,您可能希望实现自己的伪生命周期方法。这里有一个很棒的模式,我已经使用过几次。其要点如下:

  • 所有由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的新取消功能的想法!请告诉我们您的想法。


1
我已经在onDestroyView()中将其工作。但我的问题是有时会抛出NetworkOnMainThreadException,因此Call对象永远不会被取消。这当然会破坏取消机制的目的,如果不能每次都发生。显然,在OKHttp中存在某种Strictmode问题。此处已记录一个问题https://github.com/square/okhttp/issues/1592。 - Etienne Lawlor
是的,不幸的是,在OkHttp中修复之前,我看不到避免这种情况的好方法。你需要退回到一种机制来手动忽略那些本应该被取消的调用结果,但这与没有使用Call.cancel()时的解决方案是相同的。 - stkent
2
与此同时,我正在将 Call.cancel() 封装在一个 AsyncTask 中。 - Etienne Lawlor

1
你尝试过使用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
        }
    }

即便如此,由于OKHttp中的错误,Call.cancel()仍可能会抛出异常。 - Etienne Lawlor
你能记录异常吗? - Kishan Vaghela
@KishanVaghela,我认为toobsco42所说的错误是这个:https://github.com/square/okhttp/issues/1592 - wangqi060934
@toobsco42 这个异常现在已经修复了! - Philip Giuliani

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接