deveLost
deveLost

Reputation: 1171

Android : IntentService or Handler

I'm meeting a problem to understand which is the best solution for what I want to do. (And I've problems to understand ATM how they work exactly)

Often I use Asynctask, but in this case I think it's not what I need.

In an activity (A) I want to start a task which sends datas to a WS and it can take 10-20 secondes to be done. I want to allow the user to do otherthing on the app during this time.

When this task is done, I want to call another activity, but if there are errors, I want to show them in a toast. I want too, to show a progressbar if the user is on this activity (A).

So I see that IntentService can help me, because it's not "linked" to an activity, it works in background etc... but it seems a little complicated to have a link with the UI Thread. (in my case, if there is a problem, I want to do something in my activity A).

The other part, the handler can be used, but if the activity is destroyed, the thread runs always, but how can I "restore" the link with the activity if the users come back on the activity (A) ? (with a static class to save it ?).

So if you have any links/advise/other to give me more explanation, I will appreciate it :) (I readed the Android's doc.)

Upvotes: 0

Views: 1291

Answers (1)

JoeyJubb
JoeyJubb

Reputation: 2321

First up, use an IntentService - they're designed for exactly this kind of thing. The second part of your question takes a little longer to answer, but bear with me ;-)

Essentially one of two things can happen whilst your IntentService is busy talking to the server: 1) the user navigates away from your, 2) the user stays in your app. You can account for this by doing the following:

  1. Your IntentService should send an Ordered Broadcast when it has completed with the information on whether or not it was successful.
  2. For the activities that you want to react to this broadcast, create a base implementation for them which registers a broadcast receiver in onResume() and gets rid of it in onPause(). These should cancel the broadcast if they react to it
  3. Create a second (but stand-alone) broadcast receiver for your broadcast and register it in the manifest with a priority 0 so it will always be the last to know about your IntentService finishing. This receiver is responsible for creating a notification for the user to click, which will take them to the relevant place in your app.

Here's a barebones manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="bubblebearapps.co.uk.blah" >

<permission android:name="change_this_name"
    android:label="my_permission"
    android:protectionLevel="dangerous"/>

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >

    <uses-permission android:name="change_this_name"/>

    <activity
        android:name=".MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <receiver
        android:name=".MyReceiver"

        android:enabled="true"
        android:exported="false"
        android:permission="change_this_name">
        <intent-filter android:priority="0">
            <action android:name="action_name_here"/>

        </intent-filter>
    </receiver>
</application>

</manifest>

Barebones activity:

public class MainActivity extends AppCompatActivity {

public static final String YOUR_ACTION = "this_action_matches_the_one_in_the_manifest";
public static final String YOUR_PERMISSION = "this_permission_matches_the_one_in_the_manifest";


private InterceptsReciever mReceiver;

private void doSomethingWithBroadcast(Intent intent) {
    // this method must return quickly! If you've got something long to do, do it on a background thread
}

@Override
protected void onResume() {
    super.onResume();
    mReceiver = new InterceptsReciever(this);
}

@Override
protected void onPause() {
    unregisterReceiver(mReceiver);
    super.onPause();
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

public static class InterceptsReciever extends BroadcastReceiver {


    private final MainActivity mainActivity;

    public InterceptsReciever(MainActivity mainActivity) {
        this.mainActivity = mainActivity;
        IntentFilter filter = new IntentFilter(YOUR_ACTION);
        filter.setPriority(1); //anything above the manifest. You could have higher priorities for nested fragments or whatever if you like....

        mainActivity.registerReceiver(this,
                filter, 
                YOUR_PERMISSION,
                null);
    }

    @Override
    public void onReceive(Context context, Intent intent) {

        if (YOUR_ACTION.equals(intent.getAction())) {

            mainActivity.doSomethingWithBroadcast(intent);
            abortBroadcast(); // this prevents other the manifest broadcast being called

        }

    }
}


/**
 * Example of how to send broadcasts
 * @param context
 */
public static void sendBroadcast(Context context){

    Intent intent = new Intent(YOUR_ACTION);

    context.sendOrderedBroadcast(
            intent,
            YOUR_PERMISSION        // this protects your broadcast from being seen by just anyone
    );

}



}

Upvotes: 2

Related Questions