Android: How to use JobFinished of JobService

2019-02-25 00:19发布

问题:

I didn't see example of using jobFinshed of JobService, seems like we have to track changes when some condition meet we have to call jobFinished(), am I right?

回答1:

The difficulty of calling jobFinished() from another class like an IntentService seems to be getting an instance of your class that extends JobService to use to call jobFinished(). You can get info on the scheduled job, but not on the JobService (at least, I can't find a way). I can think of 3 ways to call jobFinished().

If you don't care if your work is successful or not, or if your work takes very little time.

In one of my JobService classes, I'm doing periodic work. I'm not worried about handling failures. The task will execute again soon enough. If this is the case, you can do this.

    public boolean onStartJob(JobParameters params) {
        startService(new Intent(this, MyIntentServiceThatDoesTheWork.class));

        // job not really finished here but we assume success & prevent backoff procedures, wakelocking, etc.
        jobFinished(params, false);
        return true;
    }

This is also the way you want to do it if your work is short enough it's no problem to do it on the UI thread. In this case, do all your work in onStartJob() then return false.

Use a BroadcastReceiver to send a message from the IntentService to the JobService (a separate file for each class).

    // common Strings
    public static final String IS_SUCCESS = "isSuccess";
    public static final String MY_BC_RCVR = "MyBroadcastRcvr";

Your JobService

    public class MyJobService extends JobService {
        JobParameters mParams;

        public boolean onStartJob(JobParameters params) {
            mParams = params;
            LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
                    new IntentFilter(MY_BC_RCVR));
            startService(new Intent(this, MyIntentServiceThatDoesTheWork.class));
            return true;
        }

        private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                boolean isSuccess = false;
                if(intent.hasExtra(IS_SUCCESS)) {
                    isSuccess = intent.getBooleanExtra(IS_SUCCESS, false);
                }
                LocalBroadcastManager.getInstance(context).unregisterReceiver(this);
                jobFinished(mParams, !isSuccess);
            }
        };
    }

& your IntentService

    public class MyIntentServiceThatDoesTheWork extends IntentService {
        @Override
        protected void onHandleIntent(Intent intent) {

            boolean isSuccess = methodToDoAllMyWork();
            Intent bcIntent = new Intent(MY_BC_RCVR);
            bcIntent.putExtra(IS_SUCCESS, isSuccess);
            LocalBroadcastManager.getInstance(this).sendBroadcast(bcIntent);
        }
    }

Nest your worker thread class in the JobService class.

I've given an example of an AsyncTask based on this Medium post (also referenced by Arseny Levin) from a Google Developer Advocate but it should also be possible to use an IntentService (see this SO post for nesting IntentService).

    public class MyJobService extends JobService {
        JobParameters mParams;

        public boolean onStartJob(JobParameters params) {
            mParams = params;
            new MyAsyncTaskThatDoesTheWork().execute();
            return true;
        }

        private class MyAsyncTaskThatDoesTheWork extends AsyncTask<Void, Void, Boolean> {
            @Override
            protected Boolean doInBackground(Void... params) {
                return methodToDoAllMyWork();
            }

            @Override
            protected void onPostExecute(Boolean isSuccess) {
                if(mParams != null) {
                    jobFinished(mParams, !isSuccess);
                }
            }
        }
    }


回答2:

If your onStartJob() method returns true, that means that you are doing work in the background in support of this job. That background thread needs to call jobFinished() when that work has been completed or if the job needs to be rescheduled.



回答3:

As @CommonsWare explained - inside onStartJob you'll decide if further work is required on a background thread. Only if that's the case, then you should call jobFinished from that background thread. Just to answer your specific question - no condition tracking is required on your behalf. JobService will call onStopJob if the conditions you asked are no longer true.

Example of jobFinished can be found here: https://medium.com/google-developers/scheduling-jobs-like-a-pro-with-jobscheduler-286ef8510129