ViewModel делает сетевой вызов при изменении ориентации экрана Android

Я новичок в компонентах архитектуры Android, и меня немного смущает viewmodel. Я создаю приложение, которое получает список элементов с сервера и отображает его в виде списка в макете. Я реализовал сетевой вызов в классе Repository.

Репозиторий.java:

//Get list of top rated movies
    public LiveData<NetworkResponse> getTopRatedMovies() {
        final MutableLiveData<NetworkResponse> result = new MutableLiveData<>();
        ApiService api = retrofit.create(ApiService.class);
        Call<MovieData> call = api.getTopRateMovies("api_key");
        call.enqueue(new Callback<MovieData>() {
            @Override
            public void onResponse(Call<MovieData> call, Response<MovieData> response) {
                result.postValue(new NetworkResponse(response.body()));
            }

            @Override
            public void onFailure(Call<MovieData> call, Throwable t) {
                Log.e(TAG, t.getLocalizedMessage());
                result.postValue(new NetworkResponse(t));
            }
        });
        return result;
    }

Теперь в классе ViewModel я делаю это:

public class MovieListViewModel extends ViewModel {


    public LiveData<NetworkResponse> result, topRatedMovies;
    public LiveData<List<MovieEntity>> favoriteMovies;

    private Repository repository;

    public MovieListViewModel() {
        repository = new Repository(MyApplication.getInstance());
    }

    public void getTopRatedMovieList() {
        topRatedMovies = repository.getTopRatedMovies();
    }

}

Теперь в MainActivity.java:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        ((MyApplication) getApplication()).getComponent().inject(this);
        movieListViewModel = ViewModelProviders.of(this).get(MovieListViewModel.class);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
        adapter = new MovieListAdapter(this);
        movieListViewModel.getTopRatedMovieList();
        observeTopRatedMovies();

    }
private void observeTopRatedMovies() {
        movieListViewModel.topRatedMovies.observe(this, new Observer<NetworkResponse>() {
            @Override
            public void onChanged(@Nullable NetworkResponse networkResponse) {
                if (networkResponse.getPostData() != null) {
                    Log.e(TAG, "Successful");
                    topRatedData = networkResponse.getPostData();
                    adapter.addData(networkResponse.getPostData().getResults());
                    recyclerView.setAdapter(adapter);
                } else {
                    Log.e(TAG, "failure");
                }
            }
        });
    }

Теперь все работает нормально, и я могу видеть список. Но если я поверну телефон, модель просмотра снова сделает сетевой вызов. Как я могу избежать повторного сетевого вызова при изменении ориентации экрана?


comment
Возможный дубликат компонентов Android Arch ViewModel и LiveData запускается после экрана ротация   -  person ivan8m8    schedule 24.01.2019


Ответы (2)


Вы можете инициализировать оперативные данные только один раз. Этого должно быть достаточно:

public class MovieListViewModel extends ViewModel {


    public LiveData<NetworkResponse> result, topRatedMovies;
    public LiveData<List<MovieEntity>> favoriteMovies;

    private Repository repository;

    public MovieListViewModel() {
        repository = new Repository(MyApplication.getInstance());
        topRatedMovies = repository.getTopRatedMovies();
    }

}
person egoldx    schedule 21.08.2018
comment
Большой! Теперь он не делает сетевой вызов снова при ориентации экрана. - person sagar suri; 21.08.2018
comment
что, если мы хотим передать переменную в getTopRatedMovies(id); есть ли способ передать идентификатор без использования View Model Factory? - person Mi_Dhah; 25.07.2020

Я предлагаю вам использовать шаблон проектирования безголовых фрагментов. Фрагмент без заголовка — это фрагмент, который сохраняет свою конфигурацию и не увеличивает размер xml. Если вы поворачиваете свое приложение, фрагмент продолжает свою логику и конфигурацию и очень полезен, когда вам нужно выполнять асинхронную задачу или асинхронный вызов (например, при модернизации)

определите свой фрагмент:

public class YourFragment extends Fragment {

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true); // <--------- the fragment retain his configuration
    }

    public void yourLogic(){
        // do your logic
    }

}

в вашем классе MainActivity создайте фрагмент или получите фрагмент istance, если он уже существует:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {

     super.onCreate(savedInstanceState);

     _yourHeadLessFragment= (YourFragment) getSupportFragmentManager().findFragmentByTag(HEADLESS_FRAGMENT);

     if (_yourHeadLessFragment== null) {
         _yourHeadLessFragment= new YourFragment();
         _yourHeadLessFragment.setListener(this); // if you want a callback
                getSupportFragmentManager().beginTransaction().add(_yourHeadLessFragment, HEADLESS_FRAGMENT).commit();

     }
     else{
         _yourHeadLessFragment.setListener(this); // refresh the callbacks if a rotation happened
     }
   }
}
person Alessandro Verona    schedule 21.08.2018
comment
Даже это хороший подход. Но в настоящее время я изучаю эту модель представления и живые данные. Спасибо и за такой подход. :) - person sagar suri; 21.08.2018