14

我在Retrofit v2 API Spec中读到,在从自定义改造接口返回的 Call 类上调用 cancel() 方法应该将传入的 Callback 设置为 null。

cancel() 在收到响应后是无操作的。在所有其他情况下,该方法会将任何回调设置为 null(因此如果匿名声明,则释放对封闭类的强引用)

通过代码我看不到调用取消时回调被显式设置为空。我可以看到OkHttpCall类中引用了回调(尽管没有显式存储)。调用 cancel 将依次调用 RealCall 类上的 cancel,该类负责取消的 Http 端,但不关心 AsyncCall 类中存储的回调(它放在 Dispatcher 类中的 readyAsyncCalls 和 runningAsyncCalls 队列中。它对我来说是不熟悉的代码,所以我可能会遗漏一些东西。

有人可以自信地确认在我的调用对象上调用 cancel() 将删除对我传入的回调的引用,这样我就不会泄漏内存吗?

简化代码示例:

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    final Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    api = retrofit.create(Api.class);
}

@Override
public void onStart() {
    super.onStart();
    call = api.getPokedex();
    call.enqueue(new Callback<Pokedex>() {
        @Override
        public void onResponse(Call<Pokedex> call, Response<Pokedex> response) {
            populate(response.body());
        }

        @Override
        public void onFailure(Call<Pokedex> call, Throwable t) {
            error(t.getMessage());
        }
    });
}

@Override
public void onStop() {
    call.cancel();
    super.onStop();
}
4

1 回答 1

1

未删除对 CallBack 的引用,如果您根据文档Call#Cancel 取消呼叫

  /**
   * Cancel this call. An attempt will be made to cancel in-flight calls, and if the call has not
   * yet been executed it never will be.
   */
  void cancel();

反正Call被取消后,CallBack被调用,即onFailure方法。

public interface Callback<T> {
  /**
   * Invoked when a network exception occurred talking to the server or when an unexpected
   * exception occurred creating the request or processing the response.
   */
  void onFailure(Call<T> call, Throwable t);
}

如果 Call#isCanceled() 是您在代码中测试的最简单方法。

 @Override
        public void onFailure(Call<Pokedex> call, Throwable t) {
            Log.w(TAG, "Call is canceled: " + call.isCancelled());
            error(t.getMessage());
        }
于 2019-11-14T09:36:58.607 回答