Create background task using JobIntentService

Services are used in Android to perform long running tasks like downloading files or images from the server, playing or streaming music. Services do not have any UI component as they do not have any user interaction. The main objective of services is to get work done in the background. Android SupportLib v26.0.0 released JobIntentService for background task processing and to save device resources like RAM and battery. JobIntentService provides same functionality as IntentService but uses Jobs instead of Services in devices running Android 8 and above. Although JobIntentService uses the old services in devices below 8.0.

Another advantage of using JobIntentService is you don’t have to manage wake lock. JobIntentService do not require WakefulIntentService. Though you need to add  “android.permission.WAKE_LOCK” permission if you are targeting API below 26.

Adding JobIntentService to your project:

Add Google repository in projects build.gradle file

allprojects {
    repositories {
        google()
        jcenter ()

    }
}

 

In app build.gradle file add

implementation "com.android.support:support-compat:27.1."

In AndroidManifest.xml file register JobIntentService inside the application tag.

 <service
            android:name=".UpdateJobIntentService"
            android:permission="android.permission.BIND_JOB_SERVICE" />

Now let’s see a basic example of using JobIntentService for background task in your app.

public class JobReceiver extends UpdateJobIntentService {
    public static final int JOB_ID = 1;
    private static final String ACTION_FOO = "com.app.action.FOO";

    public static void enqueueWork(Context context, Intent work) {
        if (ACTION_FOO.equals(work.getAction()))
            enqueueWork(context, JobReceiver.class, JOB_ID, work);
        }
    }

    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        if (ACTION_FOO.equals(intent.getAction())) {
            try {
                updateTask(intent.getExtras().getInt("data"));
                Bundle bundle = new Bundle();
                if(intent.hasExtra("receiver")){
                    Bundle bundle = new Bundle();
                    bundle.putString("data", String.format(Locale.getDefault(), "Result JobIntent Service %d", intent.getExtras().getInt("data")));
                    JobResultReceiver mResultReceiver = intent.getParcelableExtra("receiver");
                    mResultReceiver.onReceiveResult(RESULT_OK, bundle);
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
    }
}

To start JobIntentService you can call enqueueWork function to add background work.

Intent jobIntent = new Intent(context, UpdateJobIntentService.class);
jobIntent.putExtra("data", 100);
jobIntent.setAction(UpdateJobIntentService.ACTION_FOO);
JobReceiver.enqueueWork(context, intent);

How to communicate with Activity

Now we have seen how to create our new JobIntentService we may need to communicate with the activity. If there is a need to send result back to the activity then we can use ResultReceiver. ResultReceiver is an interface to receive callback results from anyone. Use resultReceiver by extending ResultReceiver class.

Let’s create our ResultReceiver class.

import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;

import static android.app.Activity.RESULT_OK;

public class JobResultReceiver<T> extends ResultReceiver {

    private JobResultReceiverCallback mReceiver;

    public interface JobResultReceiverCallback<T>{
        void onWorkDone(T data);
        void onError();
    }

    /**
     * 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
     */
    public JobResultReceiver(Handler handler) {
        super(handler);
    }

    public void setReceiver(JobResultReceiverCallback<T> receiver){
        mReceiver = receiver;
    }

    @Override
    protected void onReceiveResult(int resultCode, Bundle resultData) {
        if (mReceiver != null) {
            if(resultCode == RESULT_OK){
                mReceiver.onWorkDone(resultData);
            } else {
                mReceiver.onError("Error reason");

            }
        }
    }
}

Activity example

public class JobActivity extends AppCompatActivity implements JobResultReceiver.JobResultReceiverCallback<String> {

    private JobResultReceiver mServiceResultReceiver;

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

    private void enqueueWork(){
        mServiceResultReceiver = new JobResultReceiver(new Handler());

        Intent jobIntent = new Intent(this, JobReceiver.class);
        jobIntent.putExtra("data", 100);
        jobIntent.setAction(JobReceiver.ACTION_FOO);
        Bundle bundle  = new Bundle();
        bundle.putParcelable("receiver", mServiceResultReceiver);
        jobIntent.putExtras(bundle);
        JobReceiver.enqueueWork(this, jobIntent);
    }

    @Override
    public void onWorkDone(String data) {
        Log.w("TAG", "Work done:" + data);
    }

    @Override
    public void onError(String error) {
        Log.w("TAG", "Service failed:" + error);

    }
}

 

 

Leave a Reply