Custom JobIntentService onHandleWork not called

21.2k views Asked by At

I recently was updating an app that I work on to handle notifications from push using a JobIntentService instead of a regular IntentService because it seems like the correct way to handle this on pre-Lollipop devices as well as post. I am enqueueing work as such:

enqueueWork(context, MyJobServiceExtension.class, JOB_ID, work);

This is the manifest declaration:

<service android:name="com.example.MyJobServiceExtension"
            android:permission="android.permission.BIND_JOB_SERVICE"
            android:exported="true"
            tools:node="replace">

I never see any callbacks in onHandleWork or any error logs in my logcat. Has anyone successfully integrated this that could help?

Update 1

I tested this on an API level 21 device and it worked.. but it doesn't seem to be getting called on my Android Oreo Pixel XL device.. Any clues as to why?

Update 2

Also I seem to be seeing the IntentService's onCreate be called, but none of the other lifecycle methods (including onHandleWork). Has anyone encountered this either?

12

There are 12 answers

3
agirardello On BEST ANSWER

I had the same issue after upgrading from IntentService to JobIntentService. Make sure you remove this method from your old implementation:

@Override
public IBinder onBind(Intent intent) {
    return null;
}

For me this solved the problem, and now it works both on pre- and post-Oreo.

6
Jule On

I had the same problem (worked fine on a pre-O device, no indication of anything happening whatsoever on an O-device). Today, I tried again with exactly the same code as yesterday, now it works - only difference is that I rebooted the device in between.

My current theory is that my initial setup did not work; my current one does and just redeploying new code does not clear out the broken state from the JobScheduler; a reboot or an uninstall/reinstall of the package does.

The setup that's working now (migrated from a former IntentService):

<service
    android:name=".MyJobIntentService"
    android:exported="false"
    android:permission="android.permission.BIND_JOB_SERVICE"/>

and start with

Intent intent = new Intent(); 
intent.putExtra(EXTRA_NAME, extraValue);
JobIntentService.enqueueWork(context, MyJobIntentService.class, FIXED_JOB_ID, intent);

Note that the intent is not an explicit intent (i.e., the ComponentName is not set).

3
Dimitar Darazhanski On

If you have overridden the onCreate method in your JobIntentService, it will prevent the onHandleWork to be called.

I converted my Service to JobIntentService and only after I removed the onCreate method it worked.

0
Tarun Goel On

For me I was still starting the service after enqueueWork and was giving me error because of that.

1
Redaniat On

For everyone who couldn't solve the problem with the other answers:

Try using different JOB_IDs every time enqueueWork is called. If a previous job hasn't finished, the Service may just be stuck (similar to the problem the user "git pull origin" has described) and a new job with a different ID may solve this issue.

0
CanCoder On

As funny as this may sound, l had a similar issue because l did not change the name of the class to its own name in the enqueueWork() because l copied the code from one of my classes. After l made the update it started working properly.

3
git pull origin On

I encountered a somewhat similar problem with onHandleWork not being called the second time after migrating from Service to JobIntentService. Logs were showing that enqueueWork was called but onHandleWork was executing only the first and appeared to be stuck.

After some more digging and logging, I discovered that the difference was that in a "stuck" scenario there was JobIntentService#onDestroy even though all operations in onHandleWork were performed and seemingly finished.

Turned out that the culprit was bindService call of that service to activity lifecycle which was preventing disposing of the first job and for some reason calling enqueueWork after this condition was causing the service to "stuck" and never run any of the following onHandleWork again.

So, here is an incorrect log of events in which JobIntentService will appear to be stuck after the first call never triggering onHandleWork again:

enqueueWork -> first call
onHandleWork started (log in the first line)
onHandleWork finished (log in the last line)
enqueueWork -> second call
enqueueWork -> third call

And here is the correct log of events with JobIntentService functioning correctly after removing bindService call:

enqueueWork -> first call
onHandleWork started (log in the first line)
onHandleWork finished (log in the last line)
onDestroy (service is destroyed after the job is finished)
enqueueWork -> second call
onHandleWork started (log in the first line)
onHandleWork finished (log in the last line)
onDestroy
enqueueWork -> third call
onHandleWork started (log in the first line)
onHandleWork finished (log in the last line)
onDestroy

Hope this will be helpful to someone.

0
Kabliz On

I ran into this issue trying to enqueue the JobIntentService using JobScheduler. While JobScheduler has its own enqueueWork() method, it doesn't work with JobIntentService. The service will start but onHandleWork() is never called.

It started working again when I used the static enqueueWork() method that is on the JobIntentService - eg:

MyJobIntentService.enqueueWork(context, ...)

None of this was obvious from reading Android's javadoc.

0
Jay On

Just try exiting and running the Android Studio again. Then test again. In my case, the version of Android Studio is v 3.3.1. See the sample code that works properly.

public class CustomizedIntentService extends JobIntentService
{
    public static final String MY_ACTION = "action.SOME_ACTION";
    private static final int MY_JOB_INTENT_SERVICE_ID = 500;

    public CustomizedIntentService() {
    }

    // Helper Methods to start this JobIntentService.
    public static void enqueueJobAction(Context context, String action) {
        Intent intent = new Intent(context, CustomizedIntentService.class);
        intent.setAction(MY_ACTION);

        enqueueWork(context, CustomizedIntentService.class, MY_JOB_INTENT_SERVICE_ID, intent);
    }

    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        String action = intent.getAction();

        // action will be "action.SOME_ACTION"
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public boolean onStopCurrentWork() {
        return super.onStopCurrentWork();
    }
}

// start the JobIntentService as you need.

CustomizedIntentService.enqueueJobAction(context, CustomizedIntentService.MY_ACTION);

0
Sanket Berde On

This is what worked for me,

Remove the IBind Override as suggested by @agirardello

and added the following

@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
    return super.onStartCommand(intent, flags, startId);
}

Have no idea why this worked.

0
M Shafaei N On

I think that I have such problem since I try to toast some text inside onHandleWork() but actually the problem was that it was wrong. I should use a Handler. It may be the problem if one uses for example AsyncTask subclasses to execute on another thread inside onHandleWork() which is a very bad idea.

2
I_4m_Z3r0 On

I finally found the solution for that problem LoL

If you Override the "onBind" method and u call the work using the "enqueueWork" method you need to return the bind to the engine of the work doing this:

@Override @Nullable
    public IBinder onBind(@NonNull Intent intent) {
        [... Do What You Want ... ]
        return super.onBind(intent);
    }

So returning the IBinder of the "super.onBind" method, so you must use that to bind to the JobIntentService.

If you want to bind and return another binder you can do that:

@Override @Nullable
    public IBinder onBind(@NonNull Intent intent) {
        IBinder binder = initSynchronizer();
        new Thread(
                () -> onHandleWork(intent)
            ).start();
        return binder;
    }

So by starting you "onHandleWork" in another Thread. This way you can use:

"bindService(....., JobIntentService.BIND_AUTO_CREATE);"

to bind to the service and return your Binder. Anyway when you unbind from the service the service will get killed, and if it still run you cannot bind again to it because the service got killed but the thread in which the "onHandleWork" is still running...

So I suggest you to use this version only if you have to do a task which need to communicate with the activity until it is alive and need to still working if the activity get killed (without the possibility to bind again the jobService, but only to start a new one...)

To don't kill the service after the unbind you need to start it in "foreground" the "stopForeground" in the "onDestroy". This way you service still be alive just for the thread which is handling the "onHandleWork" methods.

I hope google's will solve this sh*t fast LoL, I converted all the older "Service" and "IntentService" to the new one jobs but... they work really worst than before!

Bye have a nice coding ;)