Search code examples
androidapiandroid-studioandroid-jobschedulerjobservice

JobScheduler for Nougat/Oreo


I followed some online tutorials about jobscheduling in android and I tried doing it and found out that the below code compiles without errors. But the problem is there is no toast from the onPostExecute/doInBackground return message. Is there anything that might be required? Its like I just run the code and placed some toasts and notice that myScheduler.schedule(myjobInfo); works, background tasks is carrying out.

my gradle file is not touched at all

compileSdkVersion 26
 defaultConfig {
    applicationId "com.example.umarmalik.myapplication"
    minSdkVersion 21
    targetSdkVersion 26
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}

This is my JobScheduler class

  public class MJobScheduler extends JobService {

private MJobExecutor executor;


@Override
public boolean onStartJob(final JobParameters params) {

executor = new MJobExecutor(){
    @Override
    protected void onPostExecute(String s) {
        Toast.makeText(getApplicationContext(),s,Toast.LENGTH_LONG).show();
       jobFinished(params,true);
    }
};
    executor.execute();
    return true;
}

@Override
public boolean onStopJob(JobParameters params) {
    executor.cancel(true);
    return false;
}
}

This is my JobExecutor

public class MJobExecutor extends AsyncTask<Void,Void,String> {

@Override
protected String doInBackground(Void... voids) {
    return "Background task running";
}
}

my Main activity class is as following:

public class MainActivity extends AppCompatActivity {


private static final int JOBID = 110;
private JobScheduler myScheduler;
private JobInfo myjobInfo;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ComponentName myComp = new ComponentName(this,MJobScheduler.class);
    JobInfo.Builder myBuilder = new JobInfo.Builder(JOBID,myComp);

    myBuilder.setPeriodic(6000);
    myBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
    myBuilder.setPersisted(true);


    myScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
    myjobInfo = myBuilder.build();


    myScheduler.schedule(myjobInfo);
}
}

My Manifest

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <service
        android:name=".MJobScheduler"
        android:permission="android.permission.BIND_JOB_SERVICE"
        android:exported="true" />

</application>

Solution

  • According to this answer the minimum possible time for periodic job is 15 minutes, that's why it doesn't work for you. https://stackoverflow.com/a/48337856/5604896

    The better approach to update activity when job finished is to use broadcast receiver. If activity is running it will be notified.

    public class MJobScheduler extends JobService {
    
        private MJobExecutor executor;
    
    
        @Override
        public boolean onStartJob(final JobParameters params) {
    
            executor = new MJobExecutor(this, params);
            executor.execute();
            return true;
        }
    
        @Override
        public boolean onStopJob(JobParameters params) {
            executor.cancel(true);
            return false;
        }
    
        private static class MJobExecutor extends AsyncTask<Void, Void, String> {
            private WeakReference<JobService> jobServiceReference;
            private JobParameters params;
    
            MJobExecutor(JobService jobService, JobParameters params) {
                jobServiceReference = new WeakReference<>(jobService);
                this.params = params;
            }
    
            @Override
            protected String doInBackground(Void... voids) {
                return "Background task running";
            }
    
            @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
                JobService jobService = jobServiceReference.get();
                if (jobService != null) {
                    Intent intent = new Intent("JOB_FINISHED");
                    intent.putExtra("result", s);
                    LocalBroadcastManager.getInstance(jobService).sendBroadcast(intent);
                    jobService.jobFinished(params, true);
                }
            }
        }
    }
    

    And your activity:

    public class MainActivity extends AppCompatActivity {
    
    
        private static final int JOBID = 110;
        private JobScheduler myScheduler;
        private JobInfo myjobInfo;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            ComponentName myComp = new ComponentName(this, MJobScheduler.class);
            JobInfo.Builder myBuilder = new JobInfo.Builder(JOBID, myComp);
            myBuilder.setPeriodic(15 * 60 * 1000);
    
            myBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
            myBuilder.setPersisted(true);
    
            myScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
            myjobInfo = myBuilder.build();
    
    
            myScheduler.schedule(myjobInfo);
    
            LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, new IntentFilter("JOB_FINISHED"));
        }
    
        private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                Toast.makeText(context, intent.getStringExtra("result"), Toast.LENGTH_LONG).show();
            }
        };
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
        }
    }