Friday, May 1, 2015

Example of JobScheduler and JobService

Android 5.0 provides a new JobScheduler API that lets developers optimize battery life by defining jobs for the system to run asynchronously at a later time or under specified conditions. Here is a example to use JobScheduler to run JobService repeatly in every 10 seconds.


Create MyJobService.java extends JobService
package com.example.androidjobscheduler;

import android.app.job.JobParameters;
import android.app.job.JobService;
import android.widget.Toast;

//Require API Level 21
public class MyJobService extends JobService {

 public MyJobService() {
 }

 @Override
 public boolean onStartJob(JobParameters params) {
  Toast.makeText(this, 
   "MyJobService.onStartJob()", 
   Toast.LENGTH_SHORT).show();
  /*
   * True - if your service needs to process 
   * the work (on a separate thread). 
   * False - if there's no more work to be done for this job.
   */
  return false;
 }

 @Override
 public boolean onStopJob(JobParameters params) {
  Toast.makeText(this, 
    "MyJobService.onStopJob()", 
    Toast.LENGTH_SHORT).show();
  return false;
 }

}

Edit AndroidManifest.xml, specify <service> of ".MyJobService", with "android.permission.BIND_JOB_SERVICE". And also set android:minSdkVersion="21".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.androidjobscheduler"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="21"
        android:targetSdkVersion="22" />

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

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            
        </activity>
        <service android:name=".MyJobService"
            android:permission="android.permission.BIND_JOB_SERVICE" />
    </application>

</manifest>

MainActivity.java
package com.example.androidjobscheduler;

import java.util.List;

import android.support.v7.app.ActionBarActivity;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.Toast;


public class MainActivity extends ActionBarActivity {
 
 Chronometer chronometer;
 Button btnStartJob, btnCancelJobs;
 
 JobScheduler jobScheduler;
 private static final int MYJOBID = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        chronometer = (Chronometer)findViewById(R.id.chronometer);
        btnStartJob = (Button)findViewById(R.id.startjob);
        btnCancelJobs =  (Button)findViewById(R.id.canceljobs);

        jobScheduler = (JobScheduler)getSystemService(JOB_SCHEDULER_SERVICE);
        
        btnStartJob.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    chronometer.setBase(SystemClock.elapsedRealtime());
    chronometer.start();
         
    
    ComponentName jobService = 
     new ComponentName(getPackageName(), MyJobService.class.getName());
    JobInfo jobInfo = 
     new JobInfo.Builder(MYJOBID, jobService).setPeriodic(10000).build();
    /*
     * setPeriodic(long intervalMillis)
     * Specify that this job should recur with the provided interval, 
     * not more than once per period.
     */
    
    int jobId = jobScheduler.schedule(jobInfo);
    if(jobScheduler.schedule(jobInfo)>0){
     Toast.makeText(MainActivity.this, 
      "Successfully scheduled job: " + jobId, 
      Toast.LENGTH_SHORT).show();
    }else{
     Toast.makeText(MainActivity.this, 
       "RESULT_FAILURE: " + jobId, 
       Toast.LENGTH_SHORT).show();
    }
       
   }});
        
        btnCancelJobs.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    chronometer.stop();
    
    List<JobInfo> allPendingJobs = jobScheduler.getAllPendingJobs();
    String s = "";
    for(JobInfo j : allPendingJobs){
     int jId = j.getId();
     jobScheduler.cancel(jId);
     s += "jobScheduler.cancel(" + jId + " )";
    }
    Toast.makeText(MainActivity.this, 
      s, 
      Toast.LENGTH_SHORT).show();
    
    //or
    //jobScheduler.cancelAll();
    
    
   }});
    }


}

activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.androidjobscheduler.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Chronometer
        android:id="@+id/chronometer"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" />

    <Button
        android:id="@+id/startjob"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start a Job" />
    
    <Button
        android:id="@+id/canceljobs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Cancel all Jobs" />

</LinearLayout>


download filesDownload the files.

3 comments:

Unknown said...

In file,
MyJobService.java extends JobService,
toast in onStart method is not working
please give solution

amrita said...

works like a charm thanks

Unknown said...

I think you shouldn't schedule jobinfo twice
...
int jobId = jobScheduler.schedule(jobInfo);
if(jobId > 0){
...

Something like this?
if(jobId > 0){