How to properly reload liveData manually in Android?

大城市里の小女人 提交于 2021-02-07 04:01:46

问题


My app is a basic news app which fetches data from JSON provided by Guardian API. I parsed the values from JSON using raw java code (not using retrofit).

Then I get the LiveData in NewsFeedViewModel class which extends as AndroidViewModel.

And then in the fragment, I submit list to adapter.

These are the issues I'm facing: 1) at first, if the articles to show is set to 10, then if i go to settings and change it to 2, then the last 8 articles are disappearing but the white space /gap is not going. I can still scroll through the empty gap. 2) if i change the number of articles value constantly, then app is becoming un-scrollable.

And i have a few more doubts, how to refresh the data manually when swipeToRefresh is happened?

This is my project github link: https://github.com/sdzshn3/News24-7-RV

Video sample of the issue happening in app: https://drive.google.com/file/d/1gr_fabS2rqREuyecvGSG3IQ_jXOowlW7/view?usp=drivesdk


回答1:


You need to do exactly what I did in this Reddit post:

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);
    }
}

Then you can do

public class YourViewModel extends ViewModel {
    private final GithubRepository githubRepository;

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

    private final LiveData<String> userId = savedStateHandle.getLiveData("userId"); // from args

    private final RefreshLiveData<List<Project>> refreshLiveData = Transformations.switchMap(userId, (uId) -> {
        return githubRepository.getProjectList(uId);
    });

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

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

And then repository can do:

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;
}



回答2:


In kotlin style:

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)
    }
}

Example:

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)
}





回答3:


You can do it like this
In your 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();
      }   
  }

Then in your Activity

   swipeRefreshLayout.setOnRefreshListener(() -> {
      viewModel.Refresh();
      viewModel.getNewsData().observe(this, news -> mAdapter.setNews(news));
      swipeRefreshLayout.setRefreshing(false);
   });


来源:https://stackoverflow.com/questions/53467820/how-to-properly-reload-livedata-manually-in-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!