How to properly reload liveData manually in Android?
Asked Answered
A

2

5

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

Abominable answered 25/11, 2018 at 13:13 Comment(0)
M
5

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 viewModel: MyViewModel by viewModel()

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

        viewModel.goals.observe(this) { result ->
            // update UI
        }

        // refresh
        viewModel.refresh()
    }
}

class MyViewModel(useCase: MyUseCase): ViewModel() {

    private val _goals = RefreshableLiveData {
        useCase.getGoals()
    }

    val goals: LiveData<Result<List<GoalItem>>>
        get() = _goals.map(GoalItem::fromEntity)

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

class MyUseCase {...}
...
Ms answered 15/4, 2020 at 9:35 Comment(1)
Do you have this in javaSolvency
B
2

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;
}
Blocker answered 2/1, 2019 at 10:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.