Search code examples
javaandroidasynchronousrealmrefresh

How to restart async method when It's called again?


I have a problem with an async method. Every time when its invoked It should be restarted. How to achieve that?

In my Android application, I want to show movies on the dashboard grouped by month. The movies are stored in a realm database and some users have a lot of movies locally, so it could be a bunch of time when the process finishes. That's why I want to refresh the UI every time when a new group is ready. The problem is when the realm database is changed (for example when new movies arrived from another service ) I have to start the refresh process again. Before the new refresh process, the previous one has to be stopped and the UI has to clear.

UI:

public class DashboardFragment extends BaseFragment {
//...
private DashboardViewModel viewModel;

private Observer<RealmResults<Movie>> movieObserver = movies -> {
    if (movies != null && movies.isLoaded())
        viewModel.refresh();
};

//...

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    //...
    viewModel.movies.observe(this, movieObserver);
    //...
}
//...
}

ViewModel:

public class DashboardViewModel extends AndroidViewModel {

    //..
    public RealmLiveDataResult<Movie> movies;

    //...
    public DashboardViewModel(@NonNull Application application) {
        super(application);

        //This provides a RealmLiveDataResult to have an observable to catch all the changes
        movies = new MoviesRepository().getMovies();
    }

    //...
    void refresh() {
        try (Realm realmDefault = Realm.getDefaultInstance()) {

            realmDefault.executeTransactionAsync(realmAsync -> {

                //If there are already rendered movies they should be cleared from the UI
                clearUI();

                //Find months contains movies
                RealmResults<Movie> moviesByMonth = realmDefault
                        .where(Movie.class)
                        .distinct("dateMonth")
                        .sort("date", Sort.DESCENDING);
                        .findAll();

                //Find movies by month
                for (Movie movieByMonth : moviesByMonth) {

                    //When this loop is still running but the refresh is called again it causes problems on the UI:
                    //It shows groups from the both processes
                    RealmQuery<Movie> allMoviesByMonthQuery = realmAsync
                            .where(Movie.class)
                            .equalTo("dateMonth", movieByMonth.getDateMonth())
                            .sort("date", Sort.DESCENDING);

                    List<Movie> moviesInTheMonth = realmAsync.copyFromRealm(allMoviesByMonthQuery.findAll());

                    //The new group is ready
                    showNewGroupOnUI(movieByMonth.getDate(), moviesInTheMonth);
                }
            });
        }
    }
}

Solution

  • In Async task, you can override onPreExcute() and onPostExecute(). first, create boolean like isCurrentlyLoading and initialize it as false. Then check is this isCurrentlyLoading are false before call loading

          @Override
        protected void onPreExecute() {
           isCurrentlyLoading = true;
        }
    
        @Override
        protected void onPostExecute(String result) {
           isCurrentlyLoading = false; 
        }