LiveData не обновляется при изменении данных

1

Я использую LiveData для получения данных с сервера и наблюдаю за этим. Мой onChanged() просто onChanged() в первый раз и не вызывается при обновлении данных на сервере.

UserFragment:

UserViewModel userViewModel = ViewModelProviders.of(this).get(UserViewModel.class);
userViewModel.getUser().observe(this, new Observer<User>() {
    @Override
    public void onChanged(User user) {
        //Set UI
    }
});

UserViewModel:

public class UserViewModel extends AndroidViewModel {
    private LiveData<User> user;

    public UserViewModel(Application application) {
        super(application);
        user = UserRepository.getInstance().fetchUser();
    }

    public LiveData<User> getUser() {
        return user;
    }    
}

UserRepository:

public class UserRepository {    
    private ApiService apiService;
    private static UserRepository userRepository;

    private UserRepository() {
        apiService = RestClient.getClient().create(ApiService.class);
    }

    public synchronized static UserRepository getInstance() {
        if (userRepository == null) userRepository = new UserRepository();
        return userRepository;
    }

    public LiveData<User> fetchUser() {
        final MutableLiveData<User> data = new MutableLiveData<>();
        Call<User> call = apiService.getUser();
        call.enqueue(new Callback<User>() {
            @Override
            public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
                if (response.body() != null) {
                    data.postValue(response.body());
                }
            }

            @Override
            public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
                data.postValue(null);
                t.printStackTrace();
            }
        });
        return data;
    }
}
Теги:
android-architecture-components
android-livedata
android-viewmodel

1 ответ

1
Лучший ответ

Проблема в том, что fetchUser создает новые LiveData<> каждый раз, когда вы вызываете его.

Это означает, что ваш первый никогда не получит обновления.

Пожалуйста, взгляните на эти...

вместилище

public class UserRepository {    
    private ApiService apiService;
    private static UserRepository userRepository;

    private UserRepository() {
        apiService = RestClient.getClient().create(ApiService.class);
    }

    public synchronized static UserRepository getInstance() {
        if (userRepository == null) userRepository = new UserRepository();
        return userRepository;
    }

    // Your example code
    public LiveData<User> fetchUser() {
        // Your problem lies here. Every time you fetch user data, you create a new LiveData.
        // Instead, fetch user should update the data on a pre-existing LiveData.
        final MutableLiveData<User> data = new MutableLiveData<>();
        Call<User> call = apiService.getUser();
        call.enqueue(new Callback<User>() {
            @Override
            public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
                if (response.body() != null) {
                    data.postValue(response.body());
                }
            }

            @Override
            public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
                data.postValue(null);
                t.printStackTrace();
            }
        });
        return data;
    }

    // My alterations below:
    private MutableLiveData<User> userLiveData = new MutableLiveData<>();

    public LiveData<User> getUser() {
        return userLiveData;
    }

    public LiveData<User> fetchUser2() {
        Call<User> call = apiService.getUser();
        call.enqueue(new Callback<User>() {
            @Override
            public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
                if (response.body() != null) {
                    userLiveData.postValue(response.body());
                }
                // TODO: Consider a fallback response to the LiveData here, in the case that bad data is returned. Perhaps null?
            }

            @Override
            public void onFailure(@NonNull Call<User> call, @NonNull Throwable t) {
                userLiveData.postValue(null);
                t.printStackTrace();
            }
        });
        return userLiveData;
    }
}

ViewModel

Я также изменил бы это немного. Вместо того, чтобы наблюдать выборку, я бы наблюдал LiveData напрямую.

user = UserRepository.getInstance().getUser();

Позже вы можете запросить обновленные данные с сервера в любой момент.

UserRepository.getInstance().fetchUser2();

Вы также можете вызвать fetchUser2() в первой конструкции UserRepository. Тогда только обновления будут вызывать fetchUser2() напрямую.

private UserRepository() {
    apiService = RestClient.getClient().create(ApiService.class);
    fetchUser2();
}

Фрагмент

Кроме того, в вашем фрагменте не наблюдайте за this. Вместо этого используйте getViewLifecycleOwner()

userViewModel.getUser().observe(getViewLifecycleOwner(), new Observer<User>() {
    @Override
    public void onChanged(User user) {
        //Set UI
    }
});
  • 0
    Не могли бы вы объяснить, в чем разница использования this getViewLifecycleOwner() ?
  • 1
    Это меняет то, с чем LiveData . Проблема в том, что Fragment живет намного дольше, чем вы могли ожидать. Это может привести к тому, что один и тот же LiveData несколько раз. getViewLifecycleOwner() будет фактически связываться с жизненным циклом фрагмента View . Поэтому, когда иерархия представлений будет разрушена, наблюдатели LiveData также будут не LiveData .
Показать ещё 8 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню