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...
Related
I have big problems with stopping a service, which plays audio file. I want to stop the current service before I play another file.
Activity:
public void playTrack(View view){
Intent i=new Intent(this,playService.class);
i.setAction("com.c0dehunterstudios.relaxer.PLAY");
if(isPlaying){
stopService(i);
isPlaying=false;
Log.v("ACTIVITY", "Stopping..");
}
startService(i);
isPlaying=true;
}
Service:
#Override
public void OnDestroy(){
Log.v("SERVICE","Service killed");
player.stop();
super.onDestroy();
}
But sadly it doesn't work - actually it doesn't even come down to the "Service killed" inside OnDestroy().
What am I doing wrong?
First, it's onDestroy, not OnDestroy . Second, you must use the #Override annotation for compile-time checking, so your Service code should look somewhat like this:
#Override
public void onDestroy(){
Log.v("SERVICE","Service killed");
player.stop();
super.onDestroy();
}
First, you need to clarify how many types of services in Android. AFAIK, there are:
Foreground service.
Background service.
Bound service.
Intent service.
These services stop in different ways.
Foreground: only stop when you intentionally stop it by calling stopService() in activity or fragment where you start that service or call stopSelf() in its own service. And Please note only these methods trigger service's onDestroy().
Background: stopService() and stopSelf() do in the same way as foreground. Moreover, you should know this service is in the same thread with activity or fragment calling it, so if you destroy activity or fragment, this service will stop also, but without calling onDestroy(). It basically destroys underground. Thus, if you want to catch when this service stops you need to add android:stopWithTask="false" when declaring service in Manifest file like this:
<application>
//....
<service android:name=".services.catchingStopService"
android:stopWithTask="false" />
//....
</application>
And now in your service class, you can override this method which triggers whenever this service stops:
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
// Your job when the service stops.
}
Bound: you need to handle by your self by bindService() and unbindService(), you will find out it's totally the same as starService() and stopService()
Intent: this type of service stops by itself when it finishes its jobs. And you can use ResultReceiver to communicate between service and activity or fragment. It's similar to BroadcastReceiver. You can search for example on Google easily.
Summary: base on your purpose, pick the type of service satisfying you. And they all agree with:
Don't count on onDestroy() to know when service stops because it
sometimes gets called underground; more accurately, onDestroy calls
when stopService() or stopSelf() calls (BoundService works in the
same way, I think, but by a similar method, maybe unBind(), I did not
test yet).
Use attribute android:stopWithTask="false", instead to know when the
service really stops.
All types of service stop when the device shutdown or OS kills it if
device leaks of memory.
You also should have a look at flag return by onStartCommand() to
be able to deal with when services stop like restart service again or
something. Here are some keyword you can search:
START_STICKY
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
<actionandroid:name="android.intent.action.QUICKBOOT_POWEROFF" />
I had a similar problem even with onDestroy correctly set up - the answer for which could be useful for people coming to this page. For me, onDestroy was not called immediately during stopService, sometimes for a very long time - leaving the service doing work when it should have stopped.
The answer is that this is expected behaviour - I can guess but don't exactly know why. So my solution in this case was to create a public static method to stop the actions of the service manually, which happens at the time it's called, then stopService() will call onDestroy in it's own good time...
In the case for this example (which is probably long gone, I would probably decide to keep the service running until it's expected to quite the app, but provide ways to change audio file, while the service is still active.
In my case I was printing a log inside the onDestroy and It was not printing the log and I thought onDestroy not calling when I call stopService. but in Android studio many times does not print the log so you can once double check or verify with the debug or toast.
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.
I have a BroadcastReceiver, and on its OnReceive I am supposed to call a method which is defined in the MainActivity. wherever I searched I found that I will have to write the following code.
Bundle bundle = intent.Extras;
Intent callingIntent = new Intent(context, typeof(MainActivity));
callingIntent.PutExtra("isSynched", true);
callingIntent.AddFlags(ActivityFlags.NewTask);
callingIntent.AddFlags(ActivityFlags.SingleTop);
context.StartActivity(callingIntent);
Now this calls my method, but the app keeps opening up. I don't want that to happen. I want the method to be called when the app is in background and want the app to be in background. What should I do? I am using xamarin to write the code.
I have created a service that gets the data but after I receive data I have to call a method in MainActivity to update the calendar. I am currently doing it in OnReceive like this, public override void
OnReceive(Context context, Android.Content.Intent intent)
{
if (context.GetType().Equals(typeof(MainActivity)))
{
((MainActivity)context).SyncCalendar();
}
}
this context is coming as restrictedaccess. So not able to call SyncCalendar Method
Depending on whether you need or not execute that code all the time your app lives, I'd recommend:
AsyncThread: This is somelike an improved version of a Thread as it already implements some of the mechanisms you would need to set manually with a Thread, but it's not recommended to execute all your app life, just for ending processes. You may find more info there
Service: Otherwise, if your function is intended to run all your app's life long, Service is the correct choice. It's a bit harder to understand than the AsyncThread, as it's a class that it's executed until you stop it paralelly to your main UI, but it's not a thread. You may find this useful and also this.
How can I tell from my Application whether it was started/resumed from my BroadcastReceiver or not?
I intercept outgoing calls (android.intent.action.NEW_OUTGOING_CALL). If getString(Intent.EXTRA_PHONE_NUMBER) is one of a set of numbers, I abort that call (setResultData(null)) and instead startActivity my app, putExtraing the particular number. If (and only if) coming from the BroadcastReceiver, I want to be able to put up an alert that's basically "use this app with this number/return to call". However, sometimes when I return to the app from elsewhere, the number still seems to be in the extras of the intent, even though I haven't come from the BroadcastReceiver. I tried checking for the FLAG_ACTIVITY_NEW_TASK flag, but it shows up sometimes when not coming from the BroadcastReceiver.
As you said: you can pass any parameters to your activity, indicating that it was called from your BroadcastReceiver. However, when resuming to your activity some code might be executed again - potentially causing unwanted outcomes. When I had once a similar issue I stored/overwrote some information in the intent, e.g.
myActivity.getIntent().putExtra("phoneNumber", "nil");
What worked for me was, that I overwrote the extra in the intent after it has been processed while finishing an ActionMode (let's say with "nil"). So later I was able to evaluate that information in onResume(), e.g.:
#Override
public void onResume() {
super.onResume();
String phoneNumber = getIntent().getExtras().getString("phoneNumber")
if ("nil".equals(PhoneNumber)) {
...
}
}
Just did a small test and it works pretty well.
Hope this helps ... Cheers!
I am trying to create a service that will handle file I/O in the background. Activities that update the data will bind to the service and call the service's methods to perform the I/O. I am using the Android documentation for guidance.
My service does not seem to want to start, however. In the onCreate() method of my Activity, I have:
Intent smsIntent = new Intent(this, SurveyManagerService.class);
String surveyFilename = getIntent().getStringExtra("surveyFilename");
System.out.println(startService(smsIntent)); //testing if it starts
SurveyManagerServiceConnection connection = new SurveyManagerServiceConnection();
sms = connection.getSurveyManagerService();
At line 3 LogCat outputs a ComponentInfo object, so it would appear that the service is created; however, sms is null. Furthermore, the SurveyManagerService onStartCommand() method never seems to be called:
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
System.out.println("starting service");
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
openSurveyFromIntent(intent);
return START_REDELIVER_INTENT;
}
I never see any "starting service" output in LogCat, nor does the Toast appear.
My service is declared in my manifest as:
<service android:name=".SurveyManagerService" android:exported="false" android:enabled="true">
</service>
Am I missing something obvious? Let me know what other information I should provide to diagnose the problem.
Be sure to declare your service in AndroidManifest.xml
<application>
...
<service android:name=".path.to.service.MyService"/>
</application>
Maybe you've accidentally placed the service tag outside application tag? Then the service just fails silently. Although there should be a "Unable to start service Intent..." error in the log.
It seems the onCreate() method has to exit before the service can actually start. Once I removed the getSurveyManagerService() request, and once a bit of time had passed, I received the System.out messages indicating the service was starting.
Unfortunately that creates another problem: the Activity relies on the Service for its data, so I need to determine how to cause the Activity to wait for the service to start.
EDIT: My solution was to create a private subclass of my ServiceConnection in my Activity. I then overrode the onServiceConnected() method to provide the Activity with its data (populating a ListView, in this case).
In my case i refactored the service class & noticed that it was not automatically refactored in manifest. So i had to manually update the fully qualified name of the service in manifest.