简体   繁体   中英

Is it possible to chain async tasks in Android?

I have been working on a personal project of mine to make an app that allows for a simple workout tracker. I was previously doing all operations using file I/O but have since then tried to move towards databases since I figured it would be more elegant.

I am implementing the Room persistent library on an Android application with a basic repo pattern: Fragment->ViewModel->Repository->DAO.

Currently, my queries to the database are very simple. I am just trying to get a proof of concept to see how I want to interact with the database. I have a method to get the current workout a user is doing and then one to get all the exercises associated with that workout. Most of the tutorials I have seen utilize a LiveData object but I feel it is overboard for me because once I get the data, I never need any more updates from the database so live updates would just be an necessary tax on performance. I also was getting similar issues that I'm outlining here when I used a LiveData object.

I had an idea to have two asyc tasks that run in a "chain" in my fragment where the UI is actually updated. The first async task gets the current workout, and when it is done it starts the next one to get the exercises for that workout.

What I'm finding is that sometimes the current workout doesn't actually get fetched from the view model. From debugging it, I have found it is not an issue with the query. In the view model class the value is always there. It seems to be an issue with the async task in the fragment.

Additionally, whenever the current workout does happen to be found and then the next step of populating the exercises is initiated, I start to get gaps in the exercises returned. With large lists returned from the databases, I start seeing gaps in the list around starting around index 300 (Error messages below).

I have a feeling that my code below is perhaps naive and it's not doing what I think it is doing. I thought that the doInBackground inside the async task will take as long as it needs to execute the async Room database query and then once its done, it will call onPostExecute() which will advance further in the chain.

I can share code from the database classes if necessary but I didn't want to overwhelm with too much code, especially since the results are always fine in the view model classes and repository. The issue seems to only be with the code in the fragment.

    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_workout,container,false);
        entities = new ArrayList<>();
        /*
            Set up the view models
         */
        logModel = ViewModelProviders.of(getActivity()).get(LogViewModel.class);
        workoutModel = ViewModelProviders.of(getActivity()).get(WorkoutViewModel.class);

        GetCurrentWorkoutTask task = new GetCurrentWorkoutTask();
        task.execute();
        return view;
    }

    private class GetCurrentWorkoutTask extends AsyncTask<Void, Void, Void>{

        @Override
        protected Void doInBackground(Void... voids) {
            // get the current workout from the database
            logModel.getCurrentWorkout(); // view model then calls an async method to query the database
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            if(logModel.getCurrentWorkoutResult()!=null) {
                // database found a workout, so assign it then move to the next stop in the chain
                currentWorkout = logModel.getCurrentWorkoutResult();
                Log.d("TAG","CurrentWorkout: "+currentWorkout);
                getExercises();
            }
            else{
                // no workout found,error
                Log.d("TAG","Get current workout result was null!");
            }
        }
    }

    public void getExercises(){
        GetExercisesTask task = new GetExercisesTask();
        task.execute();
    }

    private class GetExercisesTask extends AsyncTask<Void, Void, Void>{

        @Override
        protected Void doInBackground(Void... voids) {
            // get the exercises from the database
            workoutModel.getExercises(currentWorkout); // view model then calls an async method to query the database
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            if(workoutModel.getExercisesResult()!=null){
                // all of the exercises have been loaded into the view model's list member variable since the query is complete
                printExercises(workoutModel.getExercisesResult());
            }
            else{
                Log.d("TAG","Get exercises result was null!");
            }
        }
    }

    public void printExercises(ArrayList<WorkoutEntity> rawData){
        Log.d("TAG","Rawdata size: "+rawData.size());
        int count = 0;
        for(WorkoutEntity entity : rawData){
            Log.d("TAG","Entity is: "+entity.toString());
            count++;
        }
        Log.d("TAG","Count is: "+count);
    }     

Right now, I'm just inserting 1000 records into the database using a for loop and assigning the day to be the counter. The size is always 1000 but shown here it doesn't ever reach day 1000 as this is the where it stops from the printExercises method.

Day: 807

Day: 821

Day: 822

Day: 823

See how it skips from 807 to 821? It's different each time too which is why I'm certain I'm just mistaken in how the async tasks function but haven't been able to find anything to answer my questions. Additionally, the log message that is supposed to print the count while looping through the result in the printExercises() method is never called.

I have a theory that maybe it's because I'm returning null in the doInBackground and that I need to directly return something from the viewModel method so the task knows that async call is finished. I will attempt to do that tomorrow in the morning but wanted to post this in case someone else could give me any insight since I've been staring at this for hours and haven't gotten anywhere.

After looking into it more it seems it's actually just a problem with the logcat. I debugged through the app and found that the list is complete with no gaps, so I guess just having so many logcats happen at once was causing some strange behavior.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM