JobIntentService not call OnHandleWork - java

I've custom JobIntentService witn static method enqueueWork.
public static void enqueueWork(#NonNull Context context, #NonNull Intent intent) {
enqueueWork(context, MyJobIntentService.class, JOB_ID, intent);
}
Also I've custom implementation of the FirebaseMessagingService. When I receive the push notification from FCM, I call the enqueueWork of my JobIntentService.
MyJobIntentService.enqueueWork(context, new Intent());
But method OnHandleWork not called on Android 8.0 and higher.
My manifest.xml.
<service android:name="com.company.MyJobIntentService"
android:permission="android.permission.BIND_JOB_SERVICE" />
Do you have any ideas why it work not correctly? Thank you.

Nothing incorrectly. Unfortunately, JobIntentService will not run immediately on Android 8.0 and higher.
When running as a pre-O service, the act of enqueueing work will generally start the service immediately, regardless of whether the device is dozing or in other conditions. When running as a Job, it will be subject to standard JobScheduler policies for a Job with a setOverrideDeadline(long) of 0: the job will not run while the device is dozing, it may get delayed more than a service if the device is under strong memory pressure with lots of demand to run jobs.
When testing,I new a empty project, it runs immediately when call, but when i use in a real complex project,it runs several minutes later after called.

Related

Avoid automatic restart of Service using StartCommandResult.Sticky/NonSticky

What I have going on is that I made a simple service in Xamarin.Android which for now simply just sends a single Local Push Notification.
In my main application (MainActivity) I have made a statement that checks whether or not this service runs. If it does not, I will simply start the service, otherwise I'll do nothing.
if (UtilityController.IsServiceRunning(typeof(WidgetService), this) == false)
{
StartService(new Intent(this, typeof(WidgetService)));
}
This works fine aswell. No problems here.
Now, the issue is when it comes to my Service being ran multiple times.
[Service]
public class WidgetService : Service
{
public override StartCommandResult OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId)
{
SendPushNotification();
return StartCommandResult.Sticky;
}
//Other functions such as OnBind, OnDestroy etc..
}
Here I have a service that is straight forward. It's only purpose is to send a Push Notification in the function SendPushNotification(); which it does.
However, when I'm using different StartCommandResult enums, my OnStartCommand function gets triggered in different ways (which I assume is because it restarts the service):
Using StartCommandResult.Sticky makes the Service restart itself every time I close/kill the main app.
Using StartCommandResult.NotSticky makes the Service restart itself every time I start the main app.
This is a problem. I want the Service to only be run ONCE while it's still running. I don't want it ever to be restarted unless I specifically tells it to.
How do I achieve this?
Based on the info you have provided, what is happening should be something like this:
While using StartCommandResult.Sticky: As you have described, service is being restarted when you kill the service process. But this time OnStartCommand is being called with a null intent.
While using StartCommandResult.NotSticky: In this case, service is being stopped when you kill the process but notifications are not removed. When you start the app again, since service is not started, it will start a fresh from your activity.
What you could do depends on the behaviour you do expect from your app. If you want the service to stop when you close/kill the app, you can do something like this:
[Service]
public class WidgetService : Service
{
bool isStarted;
public override StartCommandResult OnStartCommand(Android.Content.Intent
intent, StartCommandFlags flags, int startId)
{
if (!isStarted)
{
SendPushNotification();
isStarted = true;
}
return StartCommandResult.NotSticky;
}
//Only will be called if stopWithTask attribute is set to false
public override void OnTaskRemoved(Intent rootIntent)
{
// Remove the notification from the status bar.
base.OnTaskRemoved(rootIntent);
}
public override void OnDestroy()
{
// We need to shut things down.
// Remove the notification from the status bar.
isStarted = false;
base.OnDestroy();
}
}
And stop the service when you are done with it or app is being closed. But if you want to keep the service running, since you are displaying a notification, I would suggest to make your service a foreground service

Don't destroy a bound Service on Activity destroy

Currently, I need a bound (Music)Service, because I need to interact with it. But I also want it to not be stopped, even when all components have unbound themselves.
As the Android Developer Guide says
"[...] Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed."
The Guide also says
"[...] your service can work both ways—it can be started (to run indefinitely) and also allow binding."
In my application, the service is started when the application starts.
I want to have this service destroyed only by a user-click on a close-button I am displaying in a custom notification. But currently, when I am destroying my MainActivity the service also stops.
This is where I am now, this is called when I want to create my Service:
public void createServiceConnection(){
musicConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.MusicBinder binder = (MusicService.MusicBinder)service;
musicSrv = binder.getService();
attachMusicService();
}
};
}
...which calls this:
public void attachMusicService(){
playerFragment.setMusicService(musicSrv);
musicSrv.attach(context); //need this for my listeners, nevermind
bindService(context);
}
...which calls this:
public void bindService(Context act){
if(playIntent==null){
playIntent = new Intent(act, MusicService.class);
act.startService(playIntent);
act.bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
}else{
act.startService(playIntent);
act.bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
}
//finished. I can do stuff with my Service here.
}
Have I misunderstood something?
I feel like the service should keep running, even the activity is destroyed, because I first made a started service and then bound to it.
Bind to your service from custom Application class. I don't think you can keep service alive after activity that's bound to it is destroyed (when onDestroy is called). You can keep service alive if activity pauses (onPause) by calling startForeground from service
Seems like the code was correct.
According to this Question I found out that my problem was the notification I displayed, wich is pretty interesting.
Seems like that a Service that is created for running indefinitely needs to have a Notification wich is displayed by startForeground(NOTIFY_ID, notification);.
I showed my notification with notificationmanager.notify(NOTIFY_ID, notification); before, now I have
`notificationmanager.notify(NOTIFY_ID, notification);
startForeground(NOTIFY_ID, notification);`
and the service won't stop anymore after all my bound Activities are destroyed.

ScheduledExecutorService android doesn't work on boot

I want to launch a ScheduledExecutorService on boot for checking my database all days.
I should launch this service at boot because if user doesn't launch the app this service couldn't work.
So when I launch my ScheduledExecutorService when app started it's okay but on boot ScheduledExecutorService seems not to work.
The BroadcastReceive on boot is working.
This is my code
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, Intent intent) {
Toast.makeText(context, "Ca passe", Toast.LENGTH_LONG).show();
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
Log.e("sc", "Ca passe");
Toast.makeText(context,"scheduler fonctionne", Toast.LENGTH_LONG).show();;
}
},10, 10, TimeUnit.SECONDS);
}
}
Do you have any idea ?
You need to read the documentation. Especially the documentation on the BroadcastReceiver lifecycle:
A BroadcastReceiver object is only valid for the duration of the call to onReceive(Context, Intent). Once your code returns from this function, the system considers the object to be finished and no longer active.
This has important repercussions to what you can do in an onReceive(Context, Intent) implementation: anything that requires asynchronous operation is not available, because you will need to return from the function to handle the asynchronous operation, but at that point the BroadcastReceiver is no longer active and thus the system is free to kill its process before the asynchronous operation completes.
In particular, you may not show a dialog or bind to a service from within a BroadcastReceiver. For the former, you should instead use the NotificationManager API. For the latter, you can use Context.startService() to send a command to the service.
If you need to use an Executor, host it in an actual Android Service. Otherwise, consider using AlarmManager to wake up your Service.

Starting an IntentService from FileObserver

I'm writing an app that makes use of the fileobserver in android. When I file is modified in anyway (creation, etc.) it should upload. In order to implement a queue and keep from running out of memory by using threads and such, I want to use an IntentService to upload the files one at a time, and keep from executing when it fails so that when the user regains connectivity, it uploads. But here is the problem:
All of the given constructors for Intent...
Intent();
Intent(Intent );
Intent(String );
Intent(Context, Class<?>); //The one I always use
Intent(String, Uri );
Intent(String, Uri, Context, Class<?> );
...wont work. Because I'm working in an extension of FileObserver, there is no acceptable context from which I can feed the Intent. Is there anyway I can use just the String one to start the IntentService? I don't need it to return anything, I just need to feed it a few strings for it to work (filename, etc.) Or is there another way I can start the IntentService. This one's really got me stumped.
Thanks for any help in advanced!
Edit: Alright. I've tried many contexts but none see to work. The intent service isn't being fired by application or base contexts from the service class being passed through the constructors as they're called. Here is the basic layout of my app:
Login Activity goes to Menu Activity, Menu Activity starts Service, Service Starts Service Handler (see the example of a service in the android docs to see what it is) and passes the context through the constructor. Service Handler starts FileSync and passes context through the constructor. FileSync holds onto the context in a class variable. FileSync then waits until a file is modified and then uses the context to start the IntentService to upload the file requested through the Intent. I know it's really complicated, but it's really the only way I can do it at the moment.
Because I'm working in an extension of FileObserver, there is no acceptable context from which I can feed the Intent.
This FileObserver cannot exist in a vacuum. It needs to be managed by an activity or service, and that will give you your Context.
You can create a static field of you Application by overriding Application. In oncreate
sInstance = this;
Use
MyApplication.sInstance.startActivity(intent);
Edit:
On second thought you could use PendingIntent if all you need to do is start a service without passing any information from FileObservver, you can create a PendingIntent and set it at the time of creation of FileObserver and use
pendingintent.send()

Using an Android Service to handle a network connection

I'm working on an Android app that needs to maintain a network connection to a chat server. I understand that I can create a service to initiate the connection to the server, but how would the service notify an Android Activity of new incoming messages? The Activity would need to update the view to show the new messages. I'm pretty new to Android, so any help is appreciated. Thanks!
Can you pass a handler to your service?
First, define your handler as an interface. This is an example, so yours may be more complex.
public interface ServerResponseHandler {
public void success(Message[] msgs); // msgs may be null if no new messages
public void error();
}
Define an instance of your handler in your activity. Since it's an interface you'll provide the implementation here in the activity, so you can reference the enclosing activity's fields and methods from within the handler.
public class YourActivity extends Activity {
// ... class implementation here ...
updateUI() {
// TODO: UI update work here
}
ServerResponseHandler callback = new ServerResponseHandler() {
#Override
public void success(Message[] msgs) {
// TODO: update UI with messages from msgs[]
YourActivity.this.updateUI();
}
#Override
public void error() {
// TODO: show error dialog here? (or handle error differently)
}
}
void onCheckForMessages() {
networkService.checkForMessages(callback);
}
and NetworkService would contain something like:
void checkForMessages(ServerResponseHandler callback) {
// TODO: contact server, check for new messages here
// call back to UI
if (successful) {
callback.success(msgs);
} else {
callback.error();
}
}
Also, as Aleadam says, you should also be away that a service runs on the same thread by default. This is often not preferred behavior for something like networking. The Android Fundamentals Page on Services explicitly warns against networking without separate threads:
Caution: A service runs in the main thread of its hosting process—the service does not
create its own thread and does not run in a separate process (unless you specify
otherwise). This means that, if your service is going to do any CPU intensive work or
blocking operations (such as MP3 playback or networking), you should create a new thread
within the service to do that work. By using a separate thread, you will reduce the
risk of Application Not Responding (ANR) errors and the application's main thread can remain dedicated to user interaction with your activities.
For more information on using threads in your service, check out the SO articles Application threads vs Service threads and How to start service in new thread in android
Did you check the Service API page: http://developer.android.com/reference/android/app/Service.html ?
It has a couple of examples on how to interact with a Service.
The service runs on the same thread and the same Context as the Activity. Check also here: http://developer.android.com/reference/android/content/Context.html#bindService%28android.content.Intent,%20android.content.ServiceConnection,%20int%29
Finally, take a look also at Lars Vogel's article: http://www.vogella.de/articles/AndroidServices/article.html
One common and useful approach is to register a broadcast receiver in your Activity, and have the Service send out notification events when it has useful data. I find this to be easier to manage than implementing a handler via a callback, mainly because it makes it easier and safer when there is a configuration change. If you pass a direct Activity-reference to the Service then you have to be very careful to clear it when the Activity is destroyed (during rotation, or backgrounding), otherwise you get a leak.
With a Broadcast Receiver you still have to unregister when the Activity is being destroyed, however the Service never has a direct reference to the Activity so if you forget the Activity will not be leaked. It is also easier to have the Activity register to listen to a topic when it is created, since it never has to obtain a direct reference to the Service...
Lars Vogel's article discusses this approach, it is definitely worth reading! http://www.vogella.com/tutorials/AndroidServices/article.html#using-receiver

Categories

Resources