Как правильно перезагрузить liveData вручную в Android?

Мое приложение - это основное новостное приложение, которое извлекает данные из JSON, предоставляемые Guardian API. Я проанализировал значения из JSON, используя сырой код Java (без использования модификации).

Затем я получаю LiveData в классе NewsFeedViewModel, который расширяется как AndroidViewModel.

А затем во фрагменте я отправляю список адаптеру.

Вот проблемы, с которыми я сталкиваюсь: 1) сначала, если для выставляемых статей установлено значение 10, затем, если я перехожу к настройкам и меняю его на 2, то последние 8 статей исчезают, но пробел / пробел не собирается. Я все еще могу прокрутить пустой пробел. 2) если я постоянно изменяю количество статей, приложение перестает прокручиваться.

И у меня есть еще несколько сомнений, как обновить данные вручную, когда происходит swipeToRefresh?

Это ссылка на мой проект github: https://github.com/sdzshn3/News24-7-RV

Пример видео о проблеме, возникающей в приложении: https://drive.google.com/file/d/1gr_fabS2rqREuyecvGSG3IQ_jXOowlW7/view?usp=drivesdk

0 ответов

В стиле котлин:

class RefreshableLiveData<T>(
    private val source: () -> LiveData<T>
) : MediatorLiveData<T>() {

    private var liveData = source()

    init {
        this.addSource(liveData, ::observer)
    }

    private fun observer(data: T) {
        value = data
    }

    fun refresh() {
        this.removeSource(liveData)
        liveData = source()
        this.addSource(liveData, ::observer)
    }
}

Пример:

class MainActivity : AppCompatActivity() {
    private val useCase = TestUseCase(DataSource())

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        useCase.goals.observe(this) {
            // update UI
        }

        // refresh
        useCase.refresh()
    }
}

class TestUseCase(dataSource: DataSource) : CommonUseCase() {

    private val _goals = RefreshableLiveData {
        callService { dataSource.loadData() }
    }
    val goals: LiveData<Resource<Boolean>> = _goals

    fun refresh() {
        _goals.refresh()
    }
}

class DataSource {
    fun loadData() = Resource.Success(true)
}


Вы должны сделать именно то, что я сделал в этом посте Reddit:

public class RefreshLiveData<T> extends MutableLiveData<T> {
    public interface RefreshAction<T> {
        private interface Callback<T> {
             void onDataLoaded(T t);
        }

        void loadData(Callback<T> callback);
    }

    private final RefreshAction<T> refreshAction;
    private final Callback<T> callback = new RefreshAction.Callback<T>() {
          @Override
          public void onDataLoaded(T t) {
               postValue(t);
          }
    };

    public RefreshLiveData(RefreshAction<T> refreshAction) {
        this.refreshAction = refreshAction;
    }

    public final void refresh() {
        refreshAction.loadData(callback);
    }
}

Тогда вы можете сделать

public class YourViewModel extends ViewModel {
    private RefreshLiveData<List<Project>> refreshLiveData; // TODO: make `final`

    private final GithubRepository githubRepository;

    public YourViewModel(GithubRepository githubRepository) {
         this.githubRepository = githubRepository;
    }

    public void start(String userId) {
         refreshLiveData = githubRepository.getProjectList(userId); // TODO: use Transformations.switchMap
    }

    public void refreshData() {
        refreshLiveData.refresh();
    }

    public LiveData<List<Project>> getProjects() {
        return refreshLiveData;
    }
}

И тогда репозиторий может сделать:

public RefreshLiveData<List<Project>> getProjectList(String userId) {
    final RefreshLiveData<List<Project>> liveData = new RefreshLiveData<>((callback) -> {
         githubService.getProjectList(userId).enqueue(new Callback<List<Project>>() {
            @Override
            public void onResponse(Call<List<Project>> call, Response<List<Project>> response) {
                callback.onDataLoaded(response.body());
            }

            @Override
            public void onFailure(Call<List<Project>> call, Throwable t) {

            }
         });
    });

    return liveData;
}

Вы можете сделать это так
в своемViewModel

public class NewsViewModel extends AndroidViewModel {
    private NewsRepository newsRepository;
    private MutableLiveData<List<News>> news;

    public NewsViewModel() {
        super(application);
        newsRepository = new NewsRepository(application);
        news = newsRepository.getMutableLiveData();
      }

    public MutableLiveData<List<News>> getAllNews() {
        return news;
      }

    public void Refresh() {
        newsRepository = new NewsRepository(application);
        news = newsRepository.getMutableLiveData();
      }   
  }

Тогда в вашем Activity

   swipeRefreshLayout.setOnRefreshListener(() -> {
      viewModel.Refresh();
      viewModel.getNewsData().observe(this, news -> mAdapter.setNews(news));
      swipeRefreshLayout.setRefreshing(false);
   });
Другие вопросы по тегам