How can I cancel the task of Firebase JobDispatcher

376 Views Asked by At

I have a Firebase JobDispatcher in my app that is set up to run an AsyncTask. The JobDispatcher is created:

        dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(getContext())) ;
    monitorEggJob = dispatcher.newJobBuilder()
            .setService(EggMonitorJobService.class)
            .setTag(JOB_TAG)
            .setLifetime(Lifetime.UNTIL_NEXT_BOOT)
            .setRecurring(false)
            .setReplaceCurrent(true)
            .setConstraints(Constraint.ON_ANY_NETWORK)
            .build() ;
    dispatcher.mustSchedule(monitorEggJob);

When the "Stop" event of the fragment that started this JobDispatcher is called it cancels the JobService:

        int result ;
    if ( dispatcher != null )
    {
        result = dispatcher.cancel(JOB_TAG) ;
        Log.d(TAG, "Dispatcher cancelled Egg Monitor Task (Result = " + result + "(");
    }

The result is "0", meaning success.

However when the app has been closed, after a period of time the JobService runs the AsyncTask again and a exception occurs:

Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

Also, if I look at the "App Info" after the app has been closed completely, not just on the back stack, the "force Stop" option is available, indicating the Dispatcher is still running I think.

My question is, how can I ensure the dispatcher is killed in the "onStop" event. The service is only required while the app is running in foreground.

*********** Add EggMonitorService code ************

public class EggMonitorJobService extends JobService {
    private EggMonitorTask  eggMonitorTask ;
    private boolean         keepGoing ;
    private JobParameters   jobParameters ;


    @Override
    public boolean onStartJob(JobParameters job) {
        jobParameters = job ;
        keepGoing = true ;
        eggMonitorTask = new EggMonitorTask();
        eggMonitorTask.execute() ;
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters job) {
        //keepGoing = false ;
        if ( eggMonitorTask != null ) {
            eggMonitorTask.cancel(true) ;
        }
        return false;
    }

    private class EggMonitorTask extends AsyncTask<Void, Void, Void> {
        public static final String TAG = "EggMonitorTask" ;

        @Override
        protected void onPreExecute() {
            Log.d(TAG, "Starting ...");
            super.onPreExecute();
        }

        @Override
        protected Void doInBackground(Void... voids) {
            final DatabaseReference eggsReference = FirebaseDatabase.getInstance().getReference().child("eggs") ;
            Query query = eggsReference.orderByChild("userKey") ;
            final ValueEventListener listener = new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    //
                    List<EggModel> eggs = new ArrayList<>() ;
                    for ( DataSnapshot snapshot : dataSnapshot.getChildren() ) {
                        EggModel egg = snapshot.getValue(EggModel.class) ;
                        eggs.add(egg) ;
                    }
                    if ( eggs.size() > 0 ) {
                        for ( EggModel item : eggs ) {
                            //
                            // Run the hatch date  and write
                            // any updated data to database
                            //
                            if ( item.updateHatchSoon() ) {
                                //
                                // Update database
                                //
                                eggsReference.child(item.getDbKey()).setValue(item) ;
                            }
                        }

                    }
                    //
                    // All done
                    //
                    keepGoing = false ;
                }

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {

                }
            } ;
            query.addValueEventListener(listener) ;
            //
            // Sleep until all the work has been completed,
            // check for completion periodically.
            //
            while(keepGoing) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            query.removeEventListener(listener);
            return null;
        }

        //
        // There is no return data, this is here for
        // debug only
        //
        @Override
        protected void onPostExecute(Void aVoid) {
            Log.d(TAG, "Ending ...");
            jobFinished(jobParameters, keepGoing) ;

        }
    }

}

Thanks. Sid

1

There are 1 best solutions below

0
On

If AsyncTask is cancelled, onCancelled() is called instead of onPostExecute(). Call jobFinished() from there:

@Override
protected void onCancelled(Void aVoid){
    Log.d(TAG, "Cancelling ... ");
    jobFinished(jobParameters, false) ;
}

Also, handle errors in ValueEventListener:

@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
    Log.w(TAG, "Error: " + databaseError.toString());
    keepGoing = false;
}