A Few Examples Of How The JobIntentService Android Works

Content posted here with the permission of the author Sambhaji Karad, who is currently employed at Josh Software. Original post available here.

What is JobIntentService?

Helper for processing work that has been enqueued for a job/service. When running on Android O or later, the work will be dispatched as a job via JobScheduler.enqueue. When running on older versions of the platform, it will use Context.startService.

You must publish your subclass in your manifest for the system to interact with. This should be published as a JobService, as described for that class, since on O and later platforms it will be executed that way.

Use enqueueWork(Context, Class, int, Intent) to enqueue new work to be dispatched to and handled by your service. It will be executed in onHandleWork(Intent).

One of Android’s greatest strengths is its ability to use system resources in the background regardless app execution. sometimes it became the behaviour to use system resources excessively.

Checkout Background Execution Limits in Android O

Lets Start

IntentService.class is an extensively used service class in Android because of its simplicity and robust in nature. Since the release of Oreo, made things more difficult for developers to use this class in a full swing for their applications. For those who are relied on IntentService class, from oreo onwards you cannot simply use this class. I was also searching for an exact and efficient alternative for this class so that I can change old intentservice class to that. The search ended up in JobIntentService which is exactly does the same job of IntentService by using new Job APIs of oreo. This class is available in the support library of SDK 26.

Implementation of JobIntentService class is a simple process. Also, You can easily migrate from IntentServiceClass to JobIntentServiceClass.For device targeting SDK 26 or later, This class’ works are dispatched via JobScheduler class and for SDK 25 or below devices, It uses Context.startService() (Same as in IntentService). First, compile the dependency on your app level gradle.

implementation 'com.android.support:support-compat:27.0.0'

or later version

Steps to implement JobIntentService

1. Create a subclass of JobIntentService

2. Override onHandleWork() method

3. Expose enqueueWork() method

4. Write code in Manifest file

– For Pre-Oreo devices

  • add in Manifest WAKE-LOCK permission

– For Oreo device or above

  • Allow JobIntentService to user JobScheduler API
  • Declare android.premssion.BIND_JOb_SERVICE

1) Create a JobService.java extends JobIntentService

private static final String TAG = JobService.class.getSimpleName();
public static final String RECEIVER = "receiver";
public static final int SHOW_RESULT = 123;
/**
 * Result receiver object to send results
 */
private ResultReceiver mResultReceiver;
/**
 * Unique job ID for this service.
 */
static final int DOWNLOAD_JOB_ID = 1000;
/**
 * Actions download
 */
private static final String ACTION_DOWNLOAD = "action.DOWNLOAD_DATA";

/**
 * Convenience method for enqueuing work in to this service.
 */
public static void enqueueWork(Context context, ServiceResultReceiver workerResultReceiver) {
    Intent intent = new Intent(context, JobService.class);
    intent.putExtra(RECEIVER, workerResultReceiver);
    intent.setAction(ACTION_DOWNLOAD);
    enqueueWork(context, JobService.class, DOWNLOAD_JOB_ID, intent);
}

@SuppressLint("DefaultLocale")
@Override
protected void onHandleWork(@NonNull Intent intent) {
    Log.d(TAG, "onHandleWork() called with: intent = [" + intent + "]");
    if (intent.getAction() != null) {
        switch (intent.getAction()) {
            case ACTION_DOWNLOAD:
                mResultReceiver = intent.getParcelableExtra(RECEIVER);
                for(int i=0;i<10;i++){
                    try {
                        Thread.sleep(1000);
                        Bundle bundle = new Bundle();
                        bundle.putString("data",String.format("Showing From JobIntent Service %d", i));
                        mResultReceiver.send(SHOW_RESULT, bundle);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                break;
        }
    }
}

2) Add WAKELOCK Permission to Manifest.xml

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

3) Add JobIntentService class to Manifest.xml

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

4) Create a ServiceResultReceiver.java to communicate with Activity from JobIntentService

private Receiver mReceiver;

/**
 * Create a new ResultReceive to receive results.  Your
 * {@link #onReceiveResult} method will be called from the thread running
 * <var>handler</var> if given, or from an arbitrary thread if null.
 *
 * @param handler the handler object
 */

public ServiceResultReceiver(Handler handler) {
    super(handler);
}

public void setReceiver(Receiver receiver) {
    mReceiver = receiver;
}


@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
    if (mReceiver != null) {
        mReceiver.onReceiveResult(resultCode, resultData);
    }
}

public interface Receiver {
    void onReceiveResult(int resultCode, Bundle resultData);
}

5) Create MainActivity.java to enqueue work to JobIntentService, Initialise the ServiceResultReceiver, Show data from the Service

public class MainActivity extends AppCompatActivity implements ServiceResultReceiver.Receiver {

    private ServiceResultReceiver mServiceResultReceiver;
    private TextView mTextView;

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

        mServiceResultReceiver = new ServiceResultReceiver(new Handler());
        mServiceResultReceiver.setReceiver(this);
        mTextView = findViewById(R.id.textView);
        showDataFromBackground(MainActivity.this, mServiceResultReceiver);
    }

    private void showDataFromBackground(MainActivity mainActivity, ServiceResultReceiver mResultReceiver) {
        JobService.enqueueWork(mainActivity, mResultReceiver);
    }

    public void showData(String data) {
        mTextView.setText(String.format("%s\n%s", mTextView.getText(), data));
    }

    @Override
    public void onReceiveResult(int resultCode, Bundle resultData) {
        switch (resultCode) {
            case SHOW_RESULT:
                if (resultData != null) {
                    showData(resultData.getString("data"));
                }
                break;
        }
    }
}

Download source code from Github

For any questions or suggestions, please leave comments.

Thank you Happy Coding

3 thoughts on “A Few Examples Of How The JobIntentService Android Works

  1. Thank you Sachin. This article is really helpful to get started with the JobIntentService.
    I have started working on JobIntentService since last week.
    I have following observation which might be changing the application behavior.

    When we migrate IntentService to JobIntentService there is one behavior change:
    1) Kill your app while your service is performing onHandleWork() (We can produce this scenario by putting some thread sleep in onHandleWork()).
    2) Your service will stop for a few seconds and then it starts by restarting onHandleWork().

    If you perform the same scenario with IntentService then it will not execute onHandleIntent() when your app is killed. The user has to start that particular service again.

    So, if some task is performing by your service and your app gets killed.
    – With IntentService your task will not get completed.
    – With JobIntentService your task will be completed.

    Please let me know your thoughts.
    Thank you.

    When we migrate IntentService to JobIntentService there is one behavior change:
    1) Kill your app while your service is performing onHandleWork() (We can produce this scenario by putting some thread sleep in onHandleWork()).
    2) Your service will stop for a few seconds and then it starts by restarting onHandleWork().

    If you perform the same scenario with IntentService then it will not execute onHandleIntent() when your app is killed. The user has to start that particular service again.

    So, if some task is performing by your service and your app gets killed.
    – With IntentService your task will not get completed.
    – With JobIntentService your task will be completed.

    Please let me know your thought 🙂
    Thank you.

    1. hi , i run the code of printing 1 to 100 using jobintentservice what i hv noted is sometimes it completed the task and destoryed well,
      but sometime it stopped like when remove from recent list and when open app again it started whole process from starting ,
      and Of course sometime it completed the task and didn’t destroyed .

      can anybody have answer regarding this how to solve this behavior changes by the way right now i am testing it in lollipop not oreo and above

  2. While using JobIntentService the device dozes off then it is not working properly in Android Q. Also if it runs properly then I am not able to access the db data which is being downloaded in onHandleIntent(). Can anybody has the solution for this?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.