IntentService not working

My application synchronizes data with a remote database through web service calls. I make these calls in IntentService so that they can run in the background (I call it SyncService).

The code to run my IntentService looks like this:

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

It usually looks great. However, one of my friends, who is also a user of my application, often informs me that his data is not synchronized and is not displayed on our website. His device, as it turned out, showed symptoms when I was near. I connected his device to a computer, and here is what I found:

  • The SyncService startup code was run (i.e.: the code above).
  • I had a breakpoint inside the onHandleIntent method of my IntentService and it never hit.
  • I checked his list of running services and SyncService was there and it works. Interestingly, it worked for about 20 minutes. I got the impression that the IntentService killed itself when it was all from Intents for processing.
  • I made SyncService (and not the application) stop, and suddenly onHandleIntent started to click again and again. It was like all intentions were queued somewhere on the device, and now they were thrown into SyncService.

Does anyone have any ideas on what might be the problem? Do you think this is a problem with my application? With Android?

Again, I pass the Android message: "Launch this IntentService or send a message to an already running IntentService." At this moment, I have no control. A message never hits the IntentService. As soon as I exit the application, messages are sent to the IntentService and it does its job.

UPDATE: I think this code is fine, but I will express it, as many of you may want to see it.

Each intention that is included in the IntentService has an Extra value, indicating that the "type" of the call is used for me (that is, I am calling this web service or this web service, etc.). When an IntentService enters IntentService, I check the "type", and if there is an Intent in the queue for this type, I add Extra to it called "skip", so when it is reached, t search (basically, the IntentService can create a lot intentions, and it makes no sense to call this web service when this web service was called 20 seconds ago). This basically protects the application from website spam.

It is important to note that none of these codes gets in any way (as soon as the problem starts). onStartCommand is not called until the application 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); } 
+6
source share
4 answers

Definitely something that makes your service work on your other device. If so, then all subsequent calls to this service of intent are queued until the end of the current one. If this does not end, you will get what you have: the following services will not start.

You should double check that:

  • you provide the correct timeouts for nework operations.
  • you provide the correct timeouts for nework connection operations.
  • there is no race condition between threads.
  • you register any exception that may occur within the service; you do not want to lose this information.

Subsequently, if you think everything is green: just register what the service is doing and use the error reporting mechanism to automatically send it from your friends device. A simple solution might be to use bugsense or equivalent.

Then add some kind of watchdog: a thread that will run until your service stops (you just say that your thread stops when the service is stopped). The flow will have to stop your service after a certain period of time has been accepted.

This security thread can be placed inside the service itself or externally, although it can be harder to create.

+3
source

This answer offers a solution that worked for me in similar situations. It does not fix your current code, but offers another, perhaps simpler (and easier to debug) option:

  • Add a BroadcastReceiver to your Activity call, which listens for SUCCESS Intents from the IntentService .

  • In your Activity call, specify the logic when to start the IntentService (and not include it in the IntentService). The logic is this:

    • Call startService() and set the flag in the calling Activity to CANNOT_CALL.
    • If the Activity's BroadcastReceiver did not receive the SUCCESS broadcast from the IntentService , then startService() cannot be called again.
    • When Activity receives the SUCCESS intent, set the CAN_CALL flag, and startService() can be called when the timer is gaining strength again.
  • In IntentService write onStartCommand() like this:

     @Override public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); return START_STICKY; } 
  • In IntentService , when you receive, IntentService , and save a web service response, call sendBroadcast() using the intent with a custom SUCCESS action.

This logic is just a loop and needs to be fine tuned for error messages from the web service that need to be broadcast from the IntentService to listen to the Activity .

Hope this helps.

+1
source

It seems to me that setting a set of flags for your intention can 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 run as fresh using the flag above in the new task.

0
source

Another comment. This is not an answer to your question. However, this may affect the overall behavior of the service.

You do the following:

  return super.onStartCommand(intent, flags, startId); 

Internal Service.onStartCommand () is as follows

 public int onStartCommand(Intent intent, int flags, int startId) { onStart(intent, startId); return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY; } 

mStartCompatibility is false if your application is intended for API SDK 7 or later (which is most likely the case).

So, as a result, your service will start as START_STICKY.

Here is a snippet from the documentation:

For running services, there are two additional main modes of operation that they can solve, depending on the value that they return from onStartCommand (): START_STICKY is used for services that explicitly start and stop as needed, while START_NOT_STICKY or START_REDELIVER_INTENT are used for services that should only work when processing any commands given to them. See the related documentation for more information on semantics.

Based on what you described, I recommend replacing "return super.onStartCommand (intent, flags, startId)"; "return START_NOT_STICKY;"

0
source

Source: https://habr.com/ru/post/919772/


All Articles