Custom JobIntentService onHandleWork not called - android

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?

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.

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).

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.

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.

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.

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.

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

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);

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.

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 ;)

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.

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.

Related

What can I expect when onCreate() calls startService()

I am trying to understand the Service Life Cycle while working through some Android Open Source Code.
I was looking at a Service implementation which I distilled down to something like the following...
public class MyService extends Service {
public MyService() { super(); }
#Override
public void onCreate() {
super.onCreate();
init();
//==this seems odd to me
//comment in AOSP says startService() is called to make
//sure Service stays around long enough for the async call
//to complete.
startService(new Intent(this, myservice.class()));
doSomeMoreInitAsync();
}
#Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
if(actionableIntent(intent,flags,startId)) {
//do something
//NOTE: the Intent passed to startService() in onCreate()
//above will go around this block of code, doing nothing
//except returning START_STICKY
}
return START_STICKY;
}
public void onDestroy() {
//destroy stuff
}
#Override
public IBinder onBind(final Intent intent) {
return mBinder; //an instance of android.os.Binder derivative
// created when this service was instantiated
}
//other stuff
}
Why would someone want to have onCreate() call startService() on itself like above, doing nothing? The comment in code sheds some light, but it's like assumptions are being made about the Life Cycle that I don't understand. I.e., is it reasonable to expect onCreate() to effectively start its own service?
I know that if a service has already been started then onCreate() will only be called once (unless destroyed and restarted, then a new instance of the service is created and onCreate() is called once on it). My first concern with this example would be that there is an expectation placed upon the underlying Service API implementation that the Service is already in the initialized state before onCreate() is called (else there be an infinite recursion, but there is not).
But isn't onCreate() supposed to be part of the initialization (albeit an optional part for the subclass)?
Is this coding logic a reasonable way of making sure the Service is forced to be an Unbounded Service? Or am I looking at a bad example in the AOSP which may have undefined behavior in the future?
You are correct in that a Service will call onCreate and onStartCommand if it is started via Context.startService. So in this sense, when you return START_STICKY, the Service will continually run until an explicit call to stopService() is called. It will also be destroyed and restarted during this lifecycle.
Another way to create a Service, is by binding to it. As per the docs:
Clients can also use Context.bindService() to obtain a persistent connection to a service. This likewise creates the service if it is not already running (calling onCreate() while doing so), but does not call onStartCommand().
So, it's possible for a Service to be created by simply binding to it. However, the lifecycle of a Service indicates that it will remain if it is started or a client is still bound to it. Meaning, that if it was created by a bind command, it will immediately be destroyed as soon as the client unbinds.
So, if a Service starts itself in the onCreate(), it will ensure that it puts itself in the started state regardless of whether it was created by binding or by an explicit call to startService. Since there's no actionable intent, the onStartCommand will just pass straight through. An clients that call startSevice will, presumably, have actionable Intents in which case the Service will perform its duties.

Android Service running on separate Process gets killed when I swipe out my App (running in other process)

I have an Android Service (implementation of Servcie interface) which is running on a separate process compared to my real app. Unfortunately when I leave my real App (in which I clicked the Button to start my Service) and swipe it out from Task Manager, my Service gets killed as well.
I know there are a lot of questions like this here, but somehow none are targeting the Problem in my concrete constellation or they are vaguely answered.
So in my manifest I have something like:
<application ...>
<activity .../>
<service Android:name="MyService"
Android:label="MyLabel"
Android:export="false"
Android:process=":MyRemoteProcessName" />
</application>
I first have played around with an IntentService, but also switched to an own implementation of the Service Interface (eliminating the IntentService to be the point of failure) which looks something like:
public class MyService extends Service {
private ScheduledExecutorService scheduledWorker = Executors.newSingleThreadScheduledExecutor();
#Override
public void onStart() {
// Init components
startForeground(this, MyNotification);
}
#Override
public int onStartCommand(Intent i, int startId) {
// Execute Work on Threadpool here
scheduledWorker.execute(new ScheduledStopRequest(this, startId), 5, TimeUnit.Minutes);
return START_REDILIVER_INTENT;
}
// Overwritten onDestroy-Method
#Override
public void onLowMemory() {
Log.e(LOG_TAG, "On Low Memory called!");
}
#Override
public IBind onBind() {
// Dont't want to let anyone bind here
return null;
}
// Simply tries to stop the service after e.g. 5 Minutes after a call
private static class MyRunnable implements Runnable {
// Constructor with params used in run method..
#Override
public void run() {
mReferenceToMyService.stopSelfResult(startId);
}
}
}
I'm starting my Service in an onClick-Listener on a special button, with an explicit Intent, which kinda looks like the following:
#Override
public void onClick(View v) {
Intent i = new Intent(this, MyService.class);
startService(i);
}
My Intention is to keep the Service running when the user leaves the app, so that the Service can finish downloading and storing some important data. When the user comes back to my app again, he can view the data (That's why I'm executing it in a separate process). So is this possible?
My assumption right now is, that Android somehow notices my Service is just being used by my App (due to missing IntentFilters in Manifest or explicit call rather than by filter?!) and thus kills it immediately when my App is closed (even when running as ForegroundService as you can see above).
Does it seem possible to you and might some changes in the call of the service fix this problem or am I getting the concept of a service wrong?
(One last note: onLowMemory-Method doesn't get called -> No log entries.)
So, according to your hints (and so new keywords for me to look for) and after some additional research by myself, I think I have solved my problem. During my research I have found an very interisting blog post on this topic, maybe also for you, which is why I would like to share it with you: http://workshop.alea.net/post/2016/06/android-service-kill/ .
After verifying and going through the steps in this article everything seems to work fine (so startForeground seems to solve the problem). I want to point out here, that I have only tested it, with my service instance still running in separate process, so manifest entries as is above.
The actual thing which really confused me at the beginning was my android studio debug session being killed everytime, just after swiping out my app from recent apps (menu). This made me think my service being killed by the system as well. But according to the article (I have added some logs to the callback methods provided) when
Opening my app
starting service
swiping out app
starting app again and finally
calling service again,
I only received callbacks to the methods as if my service would still be running. Having an explicit look at DDMS (tool) also prooved my 2nd process, and thus my service, being still alive. Having verified this, I then cleared all my app data and repeated the steps above (excluding step no. 5). Having had a look in the database afterwards, prooved the data having been downloaded by the service.
For the curious of you:
The process of swiping out my app from recent apps (and thus having the onTaskRemoved callback method being called) lead to another problem. It somehow increases the startId parameter of onStartCommand by 1 so that my DelayedStopRequest malfunctiones and doesn't stop my service anymore.
This means: Repeating above steps 1 - 3 makes me receive startId = 1 in onStartCommand. By calling stopSelfResult(1) later on (which was the latest startId) it returnes false and the service keeps running. Continuing to follow step 4 + 5 then, makes onStartCommand being called with startId = 3 (but should actually be 2! which is skipped somehow). Calling stopSelfResult(3) with parameter 3 later on is then going to stop the service again (also visible in screenshots).
I hope my answer is correct so far (, understandable) and also helpful for you. Thank you for all of your answers which provided beneficial input and also pointed me to the solution. The android version I have been working with is:
4.1.2 - Jelly Bean | API Level : 16
I also added screenshots of the log entries from DDMS (imgur is rejecting my uploads so you'll temporarily have a link to my dropbox):
screenshots from logs from DDMS
Unfortunately running service in a separate process does not help you. I think there is no way you can prevent your service from being closed if user removes its task. You can however restart your service overriding onTaskRemoved. See this answer.
If you want to run this service class indefinitely after closing the app also.. you should use Alaram Manager class ..
public void scheduleAlarm() {
// Construct an intent that will execute the AlarmReceiver
Intent intent = new Intent(this, LocationListnerServiec.class);
// Create a PendingIntent to be triggered when the alarm goes off
final PendingIntent pIntent = PendingIntent.getBroadcast(this, MyAlarmReceiver.REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Setup periodic alarm every 5 seconds
long firstMillis = System.currentTimeMillis(); // alarm is set right away
AlarmManager alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
// First parameter is the type: ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC_WAKEUP
// Interval can be INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_DAY
alarm.setRepeating(AlarmManager.RTC_WAKEUP, firstMillis,
60000, pIntent);
}
Use this method for keep checking the service class is on or off.. By using this method Your service class will keep working after destroying of you application.

IntentService not firing

My application synchronizes data with a remote database via web service calls. I make these calls in an IntentService so they can run in the background (I call it SyncService).
The code to launch my IntentService looks like so:
Intent intent = new Intent();
intent.setClass(appContext, SyncService.class);
// place additional values in intent
intent.putExtra("data_type", SyncService.ITEM_TRACKING);
intent.putExtra("user_id", intUserId);
// call SyncService
appContext.startService(intent);
This, normally, looks great. However, one of my friends, who is also a user of my app, often tells me his data doesn't sync and get displayed on our website. His device happened to be displaying the symptoms while I was around. I plugged his device into my computer and here is what I found:
The code to launch SyncService (ie: the code above) was hit.
I had a breakpoint inside the onHandleIntent method of my IntentService and it never gets hit.
I checked his device's list of running services and SyncService was there and running. Interestingly, it had been running for about 20 minutes. I was under the impression that IntentService killed itself when it was all out of Intents to process.
I force stopped the SyncService (not the app) and, all of the sudden, onHandleIntent started getting hit over and over. It was like all the Intents were queued up somewhere on the device and were just now getting thrown at the SyncService.
Does anyone have any ideas as to what may be the problem? Do you think it's an issue with my app? With Android?
Again, I am handing a message to Android saying, "Start this IntentService or send the message to the already running IntentService." At that point, I have no control. The message never gets to the IntentService. Once I force quit the app, the messages get sent to the IntentService and it does its job.
UPDATE: I think this code is fine, but I'll put it up since a lot of you may want to see it.
Every Intent that comes in to the IntentService has an Extra denoting what "type" of call is to me made (ie: do I call this web service or that web service, etc). When an Intent comes in to the IntentService, I check the "type" and, if there is already an Intent in the queue for that type, I add an Extra to it called "skip" so, when it is reached, I don't execute the search (basically the IntentService can build up lots of Intents and it makes no sense to call this web service when this webservice was called 20 seconds ago). It basically protects the app from spamming the website.
It is important to note that none of this code is hit anyway (once the problem starts occurring). onStartCommand does not get called until the app is killed
#Override
public int onStartCommand (Intent intent, int flags, int startId) {
// here be dragons
// overriding this method and adding your own code is dangerous. i've wrapped
// my code in a try/catch because it is essential that the super method be called
// every time this method is entered. any errors in my code should not prevent this
// or the app will explode.
try {
if (flags == 0 && intent != null && intent.hasExtra("data_type")) {
Integer intDataType = intent.getExtras().getInt("data_type");
if (!mCurrentTypes.containsKey(intDataType)
|| !mCurrentTypes.get(intDataType)) {
mCurrentTypes.put(intDataType, true); // put this type in the list and move on
}
else {
intent.putExtra("skip", true); // mark this Intent to be skipped
}
}
}
catch (Exception e) {
// Log.e("Error onStartCommand", "error: " + e);
}
return super.onStartCommand(intent, flags, startId);
}
private void processIntent(Intent intent) {
// do stuff if no "skip" Extra
mCurrentTypes.put(intDataType, false);
}
There is definitly something that keeps your service running on your friend's device. If so all subsequent call to this intent service are queued until the current one finishes. If it doesn't finish then you will get what you have : next services won't start.
You should double check that :
you give proper timeouts to nework operations
you give proper timeouts to nework connections operations
there is no race condition between threads.
you log any exception that can occur inside the service, you don't wanna loose that kind of information.
Afterwards, if you think everything is green : just log what the service does and use some bug reporting mechanism to get it automatically sent from your friends device. A simple solution could be to use bugsense or equivalent.
Next, put in place some kind of watchdog : a thread that will go on running until your service stops (you just tell your thread to stop when service is stopped). The thread will have to stop your service after some time limit has been passed.
This watchdog thread could be put inside the service itself, or outside, although this may be more complex to put in place.
This answer suggests a solution that worked for me in similar situations. It doesn't fix your current code but suggests another, perhaps simpler (and easier to debug) option:
Add a BroadcastReceiver to your calling Activity that listens for SUCCESS Intents from the IntentService.
In your calling Activity, include the logic for when to start the IntentService (and don't include it in the IntentService). The logic is:
Call startService() and set a flag in the calling Activity to CANNOT_CALL.
If the Activity's BroadcastReceiver has not received a SUCCESS broadcast from the IntentService, then startService() can not be called again.
When the Activity does receive a SUCCESS intent, set the flag to CAN_CALL, and startService() can be called when the timer hits again.
In your IntentService, write your onStartCommand() like so:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
In you IntentService, when you've received, parsed and stores the web service response, call sendBroadcast() with an Intent with custom action SUCCESS.
This logic is just an outline and has to be fine-tuned for error messages from the web service that have to be broadcast from IntentService to the listening Activity.
Hope this helps.
It seems to me that setting a set of flags to your Intent may solve the problem.
Intent intent = new Intent();
intent.setClass(appContext, SyncService.class);
// This way
intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK|Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
You can make your Service start as fresh using the above flag in a fresh task.
One more comment. It's not an answer for your question. However, it may affect overall behavior of a service.
You do following:
return super.onStartCommand(intent, flags, startId);
Internally Service.onStartCommand() looks like following
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
mStartCompatibility is false if your app target SDK API 7 or later (which is most likely a case).
So, as result your service will be started as START_STICKY.
Here is piece from documentation:
For started services, there are two additional major modes of operation they can decide to run in, depending on the value they return from onStartCommand(): START_STICKY is used for services that are explicitly started and stopped as needed, while START_NOT_STICKY or START_REDELIVER_INTENT are used for services that should only remain running while processing any commands sent to them. See the linked documentation for more detail on the semantics.
Base on what you have described, I recommend to replace "return super.onStartCommand(intent, flags, startId);" to "return START_NOT_STICKY;"

Android startup Service onStart and another issue

I've been trying to figure this out for a while now and can't figure out why this is happening. This seems like it would be simple, but I can't get this to work out.
Here's what I'd like to happen
When I start the application,
1. If the background Service (long running singleton service) isn't running, start it before starting the activity.
2. Start the "homepage" activity
Updated 8/20
Here's what is happening:
1. I start the application and the service isn't running
2. I kick off the intent (via context.startService)
- the context.startService is called
3. The activity runs to completion
4. The onStartCommand is run
How can I get the onStartCommand to run before the activity starts running??
Any advice on this would relieve a lot of frustration. I've searched the forums prior to asking this but couldn't find anything that matches my issues
Thanks a lot!
Update
Thanks for the quick responses.
I should have mentioned that I'm already running this from an extension of Application (starting the service in the onCreate method).
In my current implementation (below), here's what happens in order as I step through the app. I thought this would cause the service to run before the activity but the activity runs and then the service runs. This is the main point of my confusion.
1. the application onCreate is called
2. the startService method is run
3. the starting activity runs
4. the service onCreate is called
- the service onStart is never called (I'll try the onStartCommand instead as I'm not targeting older platforms - thanks for that suggestion Alexander)
public class MyApp extends Application {
#Override
public final void onCreate()
{
if(!MyService.isRunning()) // this is a static method with thread lock
{
Intent i = new Intent(context, MyService.class);
i.setAction(MyConstants.INTENT_START_SERVICE);
context.startService(i);
}
}
}
You can create a new class that extends the Application class. This class will run before the main activity is called, and only when the app is first launched. This is where you can launch a service before your homepage activity is opened.
Thanks to Alexander O for his comment that pointed me in the right direction to getting the onStart command to run. I still can't get the onStartCommand to run before the activity though. Any suggestions?
My issue was that I had both an onStartCommand and an onStart function in my service.
Apparently I didn't understand the function of onStartCommand and thought that it was just supposed to define the service type (STICKY, NOT_STICKY).
Once I removed onStart and moved the onStart code into onStartCommand the application began working.
For those wondering, here's basically what I had.
public class MyService extends Service
{
...
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
// this was being executed but didn't really do anything
return Service.START_STICKY;
}
...
#Override
public void onStart(Intent intent, int startId)
{
// logic that was never executed
// problem fixed when I removed onStart and moved the code to onStartCommand
}
}

onServiceConnected never called after bindService method

I have a particular situation:
a service started by a broadcast receiver starts an activity. I want to make it possible for this activity to communicate back to the service. I have chosen to use AIDL to make it possible. Everything seems works good except for bindService() method called in onCreate() of the activity. bindService(), in fact, throws a null pointer exception because onServiceConnected() is never called while onBind() method of the service is. Anyway bindService() returns true.
The service is obviously active because it starts the activity.
I know that calling an activity from a service could sound strange, but unfortunately this is the only way to have speech recognition in a service.
Thanks in advance
I've just experienced another version of this problem, with the same symptom of onServiceConnected(...) not being called. The cause was different in my case.
You must make sure to have a service declaration in your AndroidManifest.xml within the application tag - this was the root of the problem for me.
<application android:name=".YourAppTitle" android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".Main" android:label="#string/app_name">
</activity>
<service android:name="YourService" />
</application>
There's an extra complication if you're using a separate Android library within Eclipse - adding this Service tag only seems to fix the issue if the referenced service is in the same package as the manifest; i.e. if your app is in package a.b.c and this is where AndroidManifest.xml resides, then 'YourService' must also be in package a.b.c. (manually copied from another library, if necessary) or else the <service..> tag may/will be ignored and onServiceConnected(...) still won't be called.
This was the case for my project even though I used a suitable import statement for the Service in my code. Eclipse showed no error, so the import was correctly identifying the class from another library in the Eclipse workspace.
HTH
After hours and hours of trying to figure this out, the issue is that the examples that show the creation of the service, don't include the onBind method or they have the following sample code or it generates this for you:
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
This causes the onServiceConnected method to fail or never actually get executed. The fix is VERY simple, which is the following:
public IBinder onBind(Intent intent) {
return mBinder;
}
Where you could create a simple binder such as the following to return:
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
public ConferenceService getService() {
return ConferenceService.this;
}
}
The onServiceConnected event was never being called in my application.
The problem was that I had the service name defined in my Application Manifest as:
<service android:name="MyService" android:enabled="true"></service>
Once I changed it to the full class name it worked:
<service android:name="com.example.MyService" android:enabled="true"></service>
Update: You can also have use a relative class name:
<service android:name=".MyService" android:enabled="true"></service>
Specify the class name using its full com.example.MyServiceClass instead of just MyServiceClass.
I can't make up the exact problem out of your description, so I'm going to guess here!
How can bindService() throw a NullPointerException? The only way this could (/should) happen is when you don't supply a Service or a ServiceConnection listener.
bindService() can't throw a NullPointerException because onServiceConnected() isn't called. The call to onServiceConnected() is a product of bindService().
So I guess you are calling a AIDL method, before the Service has actually bonded?
One more thing is that if you are calling bindservice method inside the oncreate method then the onserviceconnected is called after the oncreate method is finished.
So any references to the interface functions before the oncreate ends (or before onserviceconnected is called) shows null pointer exception.
Yet another cause to the original question might be that the service isn't already running and you are passing 0 as flag to bindService. Like so:
bindService(intent, serviceConnection, 0);
When what you are looking for would be:
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
If someone's still looking for the answer after trying all others then this might help..
onServiceConnected() is not called immediately after bindService(...). it takes few seconds. So if you are receiving some value from the onServiceConnected() and you have to use it somewhere else in onCreate or onStart it will throw a NullPointerException because of the delay. So if you can shift that line of code which needs the value from onCreate or onStart, inside onServiceConnected(){......}, below the line of declaration of the value that you need then it might work.
There can be another explanation, not a very frequent situation, but I managed to get into it and lose 2 hours to solve it.
So what I did was that I wanted to reuse the bundle from the intent received by the onBind method. But I went for the lazy version and changed the class of the intent. Apparently this causes the onServiceConnected not to get called. Probably because the system keeps a reference to the intent and uses it when calling onServiceConnected.
In conclusion don't change the intent you receive in onBind.
I also encountered the same problem. And minutes later I found that my code had absolutely no problem. It was the manifest file that had the issue.
Earlier I was declaring the service with its name only.
<service android:name=".MyBoundService"/>
Change it to the full name with the package name
<service android:name="com.pb.servicedemo.MyBoundService"/>
This way you will be able to see your service bound to the activity.
I was calling bind with an empty Intent - getContext().bindService(new Intent(), mConnection, Context.BIND_AUTO_CREATE). I have to make the intent more specific to indicate which service I want to bind to. This is obviously a code error, but the Logcat output was unfortunately not clear enough.
You Must Wait To Complete onCreate() method.
Example: Set Your Buy Service in Buttom:
Button button_useservice=findViewById(R.id.button_useservice);
button_useservice.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
UsinService();
}
});
I just spent a lot of time on this one, and since in my case it was neither of the above answers I'll just lay out another possible scenario:
This happened to me when I was using a kotlin.coroutines.Deferred object to represent my bound service, and I blocked the thread that onServiceConnected should be called on when I called await() on this object.
So basically - don't block the main thread waiting for onServiceConnected to be called, or it won't be able to be called...

Categories

Resources