5

I have created IntentService class and performing asyncTask but getting exception when onPreExecute() is called at this code line pDialog.show();

AsyncHandlerService Class ---

public class AsyncHandlerService extends IntentService{
ProgressDialog pDialog;
HttpPost post;
HttpResponse response;
Context ctx;

public AsyncHandlerService() {
    super("AsyncHandlerService");
    ctx = this;
}

@Override
protected void onHandleIntent(Intent intent) {
    new LoadDeviceInfo().execute();   
}


class LoadDeviceInfo extends AsyncTask<String, String, String> {

@Override
protected void onPreExecute() {
    super.onPreExecute();
    pDialog = new ProgressDialog(ctx);
    pDialog.setMessage("Updating device info...");
    pDialog.setIndeterminate(false);
    pDialog.setCancelable(false);
    pDialog.show(); //Exception here..
}

protected String doInBackground(String... args) {
}

protected void onPostExecute(String file_url) {
    pDialog.dismiss();
}

UPDATE:

I am calling the IntentService in the broadcast receiver that has the intent filter of android.intent.action.PACKAGE_REPLACED defined in android manifest. The code ---

public class OnUpgradeBroadcastReceiver extends BroadcastReceiver {
Context activity;
@Override
    public void onReceive(final Context context, final Intent intent) {
         activity = context;
         Intent msgIntent = new Intent(activity, AsyncHandlerService.class);
            activity.startService(msgIntent);
    }
}

Error Log:

com.testapp.main fatal error : Unable to add window -- 
token null is not for an application
android.view.WindowManager$BadTokenException: Unable to add window -- 
token null is not for an application
at android.view.ViewRootImpl.setView(ViewRootImpl.java:588)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:326)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:224)
at android.view.WindowManagerImpl$CompatModeWrapper.
addView(WindowManagerImpl.java:149)
at android.app.Dialog.show(Dialog.java:277)
at com.testapp.main.AsyncHandlerService$LoadDeviceInfo.
onPreExecute(AsyncHandlerService.java:62)
at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:586)
at android.os.AsyncTask.execute(AsyncTask.java:534)
sjain
  • 23,126
  • 28
  • 107
  • 185

5 Answers5

13

First, IntentService already uses a background thread. You do not need another background thread. Do the work that needs to be done in the background in onHandleIntent().

Second, a Service cannot display a Dialog. Instead, let the UI layer of your app know that the work was done via a message on an event bus (e.g., LocalBroadcastManager, greenrobot's EventBus, Square's Otto). If the UI layer does not handle the event, your service can raise a Notification or otherwise let the user know about the work that was done, if that is needed.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Check my update. I am delegating the `asyncTask` to the `service` from `broadcast receiver`. So UI layer isn't handling this event. Should I use Notification then OR is there any other good way? – sjain May 29 '14 at 14:37
  • @VedPrakash: "Should I use Notification" -- if your application is not in the foreground, yes. As I noted in my answer, you can use an event bus to try to tell your foreground UI that work is done, and display a `Notification` if your UI is not in the foreground. Here are three implementations of the same basic sample app for each of the three event bus implementations that I cited: https://github.com/commonsguy/cw-omnibus/tree/master/EventBus – CommonsWare May 29 '14 at 14:46
  • My purpose to show the dialog is to stop the user to do anything when the service is doing its background work because that work is updating app package info (intent PACKAGE_REPLACED is called) whenever the app is updated from Google Play. After this work is complete, the user may use this latest package info to create certain records. So the `Notification` will not work here. – sjain May 29 '14 at 14:51
  • 1
    @VedPrakash: You cannot "stop the user to do anything", except perhaps via your own custom ROM. And popping up a dialog, just because one app out of hundreds happens to be doing something, is very hostile to the user. *If* the user happens to open up your app, and *if* you determine that your app cannot be used at that moment due whatever it is that you are doing, handle that *in the UI of your app*. – CommonsWare May 29 '14 at 14:54
  • OK. So If the user updated the app from Google Play and then open the app then will the above `OnUpgradeBroadcastReceiver` will get called immediately OR will it even get called when the app will be in background just after update. – sjain May 29 '14 at 15:08
  • @VedPrakash: I do not know for certain. My guess is that the broadcast will go out before the user would have a chance to open the updated app. By definition, the app will not be in the background during the update itself, as your process has to be terminated to do the update. A new process for your app will be started to send you the broadcast. – CommonsWare May 29 '14 at 15:10
  • You said -By definition, the app will not be in the `background` during the update itself. It seems wrong. During update, the apps are in background ? Please correct. – sjain May 29 '14 at 15:25
  • @VedPrakash: Your process should be stopped during the update itself. – CommonsWare May 29 '14 at 16:55
  • Intent Service + AsyncTask + httpClient fail? dont works httpClient without async process. Need make same function sync and async? – e-info128 Jul 27 '15 at 17:19
  • @CommonsWare I think sometimes having an asynctask with intentservice make sense. For example, you want to upload a photo in the background. So you go start your intentservice with an eventbus or a broadcastreceiver, and inside of your intentservice, you start your asynctask to do the upload. The asynctask will show you the progress of the upload and you can send that progress back to your UI through the event bus or broadcastreceiver. – Simon Apr 17 '16 at 17:38
  • @Simon: ...and then your process is terminated before the upload is complete, because your `IntentService` was destroyed while your separate background thread is running. `IntentService` already gives you a background thread, **you do not need another one** for doing your upload. [This sample app](https://github.com/commonsguy/cw-omnibus/tree/master/HTTP/OkHttpProgress) demonstrates showing progress without a separate background thread, just using the thread from `IntentService`. – CommonsWare Apr 17 '16 at 18:01
0

Service isn't a UI thread.
Since you try to display a ProgressDialog from a service context, it can't be completed.
Try this solution:
https://stackoverflow.com/a/4369755/1405268

Community
  • 1
  • 1
SagiLow
  • 5,721
  • 9
  • 60
  • 115
0

If for whatever reason you really really really want to use an AsyncTask (e.g. you've set up your framework to use AsyncTask to make calls to some web api) you can always use wait/notify such as:

public class GetCacheIntentService extends DebuggableIntentService implements ApiAsyncTask.Callback {
    private static final String ACTION_GET_CACHE = "action.GET_CACHE";

    private static final String EXTRA_INT_START = "extras.START";
    private static final String EXTRA_INT_LIMIT = "extras.LIMIT";

    private static final int API_GET_CACHE = 0;

    private final Object mApiCallLock = new Object();
    private GetCacheResponse getCacheResponse;

    public GetCacheIntentService() {
        super("GetCacheIntentService");
        setIntentRedelivery(true);
    }

    public static void startServiceActionGetCache(Context context, int start, int limit) {
        Intent intent = new Intent(context, GetCacheIntentService.class);
        intent.setAction(ACTION_GET_CACHE);
        intent.putExtra(EXTRA_INT_START, start);
        intent.putExtra(EXTRA_INT_LIMIT, limit);
        context.startService(intent);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent == null) {
            return;
        }

        String action = intent.getAction();

        if (ACTION_GET_CACHE.equals(action)) {
            int start = intent.getIntExtra(EXTRA_INT_START, 0);
            int limit = intent.getIntExtra(EXTRA_INT_LIMIT, 100);
            getCache(start, limit);
        }
    }

    private void getCache(int start, int limit) {
        GetCacheTask task = new GetCacheTask(this, API_GET_CACHE);
        task.setStart(start);
        task.setLimit(limit);
        task.execute();

        synchronized (mApiCallLock) {
            try {
                mApiCallLock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }

        processResponse(mGetCacheResponse);
    }

    public void processResponse(GetCacheResponse response) {
           // do something
    }

    @Override
    public void onRequestFailed(int id, ApiResponse apiResponse) {
        synchronized (mApiCallLock) {
            switch (id) {
                case API_GET_CACHE:
                    break;
            }
            mApiCallLock.notify();
        }
    }

    @Override
    public void onRequestSuccess(int id, ApiResponse response) {
        synchronized (mApiCallLock) {
            switch (id) {
                case API_GET_CACHE:
                    mGetCacheResponse = (GetCacheResponse) response;
                    break;
            }
            mApiCallLock.notify();
        }
    }
}

this is quite ugly though :(

clockwerk
  • 263
  • 3
  • 15
0

Not a good practise to call Asynctask from an Intent service. If you need to do spin other thread from IntentService consider using Executor.

ExecutorService es = Executors.newFixedThreadPool(5);
es.execute(new Runnable() {
                @Override
                public void run() {

                }
            });

es.execute(new Runnable() {
                @Override
                public void run() {
                }
            });
es.shutdown();
es.awaitTermination(1, TimeUnit.HOURS);
Sayooj Valsan
  • 536
  • 5
  • 16
0

It is not a good practice to use AsyncTask inside IntentService sub-classes or even JobIntentService sub-classes. In the case of JobIntentServices it causes crash too.

M Shafaei N
  • 409
  • 3
  • 6