Zen
Zen

Reputation: 2728

Android IntentService not completing task if App is closed

I'm using an IntentService to saveData to a SQLDatabase & upload data to Parse. The IntentService works fine if I keep the app running. It also executes propery if I minimise it(by pressing the home button).

But if I press the navigation button and destory the app(the thing where the app screen scales down and you swipe it off); then the IntentService stops running(it doesnt even call onDestory).

What I want is to have the service execute all the tasks; and destory itself. Hence, START_STICKY (Intent) is not required as I dont want it to run continuously in the background.

Starting IntentService

Intent intent_publishService = new Intent(getApplicationContext(), PublishService.class);

Bundle basket_storyData = new Bundle();
basket_storyData.putAll( packStoryData() );
intent_publishService.putExtra(KEY_BASKET_STORY_DATA, basket_storyData);

intent_publishService.putParcelableArrayListExtra(KEY_BASKET_IMAGE_DATA, (ArrayList<? extends Parcelable>) final_image_data);
startService(intent_publishService);

PublishService.class (Snippet)

@Override
protected void onHandleIntent(Intent intent)
{
    Log.i(TAG, "ONHANDLEINTENT" );

    context = getApplicationContext();

    final String KEY_BASKET_IMAGE_DATA = "key_basket_image_data";
    final String KEY_BASKET_STORY_DATA = "key_basket_story_data";
    final String KEY_BASKET_EXTRA      = "key_basket_extra";


    ArrayList<ImagesData> _iDataSave = new ArrayList<ImagesData>();
    _iDataSave.addAll( (Collection<? extends ImagesData>) intent.getParcelableArrayListExtra(KEY_BASKET_IMAGE_DATA) );

    Log.i(TAG, "_iDataSize:" + Integer.toString(_iDataSave.size()) );

    //Get Bundle Values
    Bundle storyBundle = intent.getBundleExtra(KEY_BASKET_STORY_DATA);

    publishStory(storyBundle, _iDataSave);
}

Edit1: Manifest Declaration

<service android:name="com.example.create.main.PublishService" />

SOLVED

Upvotes: 2

Views: 1597

Answers (2)

Zen
Zen

Reputation: 2728

Here's what needs to be done:

1) Change IntentService >> Service

2) Move all the code to onStartCommand

3) Using a separate thread so that everything is done off the UI-Thread

4) Declaring it as a separate process in the Manifest

PublishService.class (Snippet)

@Override
public int onStartCommand(final Intent intent, int flags, int startId)
{
    Log.i(TAG, "ONSTARTCOMMAND" );

    Intent notificationIntent = new Intent(this, MyFriendList_Activity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

    Notification.Builder builder = new Notification.Builder(getApplicationContext());

    builder.setAutoCancel(false);
    builder.setTicker("this is ticker text");
    builder.setContentTitle("WhatsApp Notification");               
    builder.setContentText("You have a new message");
    builder.setSmallIcon(R.drawable.ic_launcher);
    //builder.setContentIntent(pendingIntent);
    builder.setOngoing(true);
    builder.setNumber(100);

    // Sets the progress indicator to a max value, the current completion
    // percentage, and "determinate" state
    builder.setProgress(0, 0, true);

    Notification notificationFinal = builder.getNotification();

    startForeground(ONGOING_NOTIFICATION_ID, notificationFinal );

    Runnable r = new Runnable() 
    {       
        public void run() 
        {
            context = getApplicationContext();

            final String KEY_BASKET_IMAGE_DATA = "key_basket_image_data";
            final String KEY_BASKET_STORY_DATA = "key_basket_story_data";
            final String KEY_BASKET_EXTRA      = "key_basket_extra";


            ArrayList<ImagesData> _iDataSave = new ArrayList<ImagesData>();
            _iDataSave.addAll( (Collection<? extends ImagesData>) intent.getParcelableArrayListExtra(KEY_BASKET_IMAGE_DATA) );

            Log.i(TAG, "_iDataSize:" + Integer.toString(_iDataSave.size()) );

            //Get Bundle Values
            Bundle storyBundle = intent.getBundleExtra(KEY_BASKET_STORY_DATA);

            publishStory(storyBundle, _iDataSave);               
        }
    };

    Thread t = new Thread(r);
    t.start();

    //return START_STICKY;
    //return START_REDELIVER_INTENT;
    //return START_CONTINUATION_MASK;
    return START_NOT_STICKY;
}

Manifest Declaration

   <service
        android:name="com.example.create.main.PublishService"
        android:process=".publishservice" />

Concern

startForeground() + separate Process + running on a separate Thread

--- maybe all 3-are not required?

Edit 1: Also; you could skip all the foreground stuff; and return START_CONTINUATION_MASK ; but thats not recommended as every device has a different way of handling that return type

Upvotes: 1

Doug Stevenson
Doug Stevenson

Reputation: 317457

You will need START_STICKY in this case to indicate to android that you wish to try to continue to do work after the app is killed.

When the user swipes away from the app chooser, that will kill the app process unconditionally. You can't prevent that from happening - it is intended to give the user control over what is running at that very moment.

Upvotes: 1

Related Questions