Может ли вызов дооснащения 2 в ViewModel вызвать утечку памяти? - PullRequest
0 голосов
/ 05 сентября 2018

Вопрос короткий: вызов асинхронного модифицированного 2 с использованием ViewModel может вызвать утечки памяти?

Как в следующем примере.

ShowsAsynViewModel.java

открытый класс ShowsAsyncViewModel extends ViewModel {

private static final String TAG = "ShowsAsyncViewModel";

private MutableLiveData<List<Show>> shows;

public LiveData<List<Show>> getShows() {
    if (shows == null) {
        shows = new MutableLiveData<>();
        loadShows();
    }
    return shows;
}

private void loadShows() {
    // Do an asynchronous operation to fetch users.
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(TvMazeService.BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    TvMazeService service = retrofit.create(TvMazeService.class);
    service.getShows().enqueue(new Callback<List<Show>>() {
        @Override
        public void onResponse(Call<List<Show>> call, Response<List<Show>> response) {
            if (response.isSuccessful()) {
                List<Show> showList = response.body();
                if (showList != null) {
                    shows.setValue(showList);
                }
            } else {
                Log.i(TAG, "onResponse: Error code: " + response.code() + " - error message: " + response.message());
            }
        }

        @Override
        public void onFailure(Call<List<Show>> call, Throwable t) {
            t.printStackTrace();
            Log.i(TAG, "onFailure: Failed to connect: " + t.getMessage());
        }
    });
}
}

RetrofitActivity.java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_retrofit);

    ShowsAsyncViewModel model = ViewModelProviders.of(this).get(ShowsAsyncViewModel.class);
    model.getShows().observe(this, new Observer<List<Show>>() {
        @Override
        public void onChanged(@Nullable List<Show> shows) {
            // Do something with the result
        }
    });
}

Вот что я заметил.

  1. Если я вызываю дооснащение 2 тем же методом, но в методе RetrofitActivity.java onCreate. Я получаю огромную утечку памяти, потому что модификация будет вызываться каждый раз, когда действие воссоздается.
  2. Если я вызываю модификацию 2, используя частный статический внутренний класс, содержащий WeakReference, то у меня не возникает утечек памяти из-за WeakReference, а также потому, что этот метод не вызывается несколько раз, если пользователь поворачивает экран несколько раз.
  3. Используя эту ShowsAsyncViewModel, я не получил утечку памяти, вероятно, потому что этот метод вызывается только один раз, даже если пользователь поворачивает экран несколько раз. Я хотел бы быть уверен, что это не приведет к утечке памяти.

1 Ответ

0 голосов
/ 16 января 2019

Да, это может привести к утечке памяти. Представьте себе сценарий, в котором вы делаете сетевой вызов с ViewModel, подключенного к вашему Activity. Перед завершением вызова действие уничтожается не для изменения конфигурации, а путем вызова finish(). Даже если Activity и ViewModel уничтожены, вызов продолжит выполняться.

Чтобы предотвратить это, вы можете изменить ShowsAsynViewModel.java следующим образом (код Котлина)

// Glogal variable
private lateinit var getShowsNetworkCall: Call<List<Show>>

void loadShows() {
    // You can add parameters to the call here
    getShowsNetworkCall = service.getShows()
    getShowsNetworkCall.enqueue(object: Callback<List<Show>>) {
        override fun onResponse(call: Call<List<Trip>>, response: Response<List<Trip>>) {...}
        override fun onFailure(call: Call<List<Show>>, t: Throwable) {...}
    }
}

override fun onCleared() {
    super.onCleared()

    getShowsNetworkCall?.cancel()
}

...