Redfox
Redfox

Reputation: 1034

Android startService() takes a long time to return to UI thread

my usecase is (roughly) the following on first startup:

  1. activity starts a service
  2. service gets and saves data in a database
  3. service notifies activity with an intent
  4. activity displays data

Now I want to display a progress bar while the service is busy. The problem is:

startService(new Intent(getApplicationContext(), UpdateDataService.class));

takes a very long time to "come back" to the UI thread. It seems to be a synchronized function (or not?). If a empty the service class the startService command is processed almost instant. It seems the UI thread waits for the Serice to handle its work, which does not make sense at all. I tried to start (as stupid as it may seem) to start the service a async task while displaying a progress bar in my UI thread. Weird enough this works sometimes. Othertimes I just get a white screen while my service is working and afterwards for a millisecond ma progressbar and then my UI.

Now my question: How do I start the service without blocking my UI?

public class MyClass extends TabActivity {
private ProgressDialog pd;

@Override
public void onCreate(final Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Intent intent = null;

    //building some tabs here, setting some text views....

    // starting service if does not exist yet
    boolean serviceRunning = false;

    final ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    for (final RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if ("aegir.mobile.UpdateDataService".equals(service.service.getClassName())) {
            serviceRunning = true;
            Log.i(MY_APP_TAG, "Service found.");
        }
    }
    if (!serviceRunning) {
        pd = ProgressDialog.show(this, "Loading...", "Setting up data.", true, false);
        new StartServiceAsync().execute("");
    }

}

private final Handler handler = new Handler() {
    @Override
    public void handleMessage(final Message msg) {
        pd.dismiss();

    }
};

public class StartServiceAsync extends AsyncTask<String, Void, String> {

    @Override
    protected String doInBackground(final String... params) {
        // starting service
        startService(new Intent(getApplicationContext(), UpdateDataService.class));
        return null;
    }

    @Override
    protected void onPostExecute(final String result) {
        handler.sendEmptyMessage(0);
        super.onPostExecute(result);
    }
}

Upvotes: 4

Views: 5549

Answers (4)

Jignesh Ansodariya
Jignesh Ansodariya

Reputation: 12685

please Use this code the easy way to do what you asked in question.

@Override
public void onCreate(final Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Intent intent = null;
    registerReceiver(dataUpdated, new IntentFilter("<FLAG>"));
    //building some tabs here, setting some text views....

    // starting service if does not exist yet
    boolean serviceRunning = false;

    final ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    for (final RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if ("aegir.mobile.UpdateDataService".equals(service.service.getClassName())) {
            serviceRunning = true;
            Log.i(MY_APP_TAG, "Service found.");
        }
    }
    if (!serviceRunning) {
        pd = ProgressDialog.show(this, "Loading...", "Setting up data.", true, false);
        startService(new Intent(getApplicationContext(), UpdateDataService.class));
    }

}


private BroadcastReceiver dataUpdated= new BroadcastReceiver() {
    @SuppressLint("ShowToast")
    @Override
    public void onReceive(Context context, Intent intent) {
        //<Your Process which you want when Service finishes a task >
              pd.dismiss();
    }
};

@Override
protected void onDestroy() {

    unregisterReceiver(dataUpdated);
}

In Service when your Task will Complete call this Method

sendBroadcast(new Intent("<FLAG>"));

Upvotes: 0

kabuko
kabuko

Reputation: 36302

Either do your work in the AsyncTask itself, use an IntentService instead of a plain old Service or start a thread from your Service to do your work. A Service in Android does not inherently use a different thread (IntentService does to do its work).

Despite starting your Service from an AsyncTask, right now it seems the actual work is being performed in your UI thread.

Upvotes: 1

gwvatieri
gwvatieri

Reputation: 5183

I think you should just move the logic from the service to the doInBackground method in the async task. That's what async task are for, executing hard work giving you a simple way to interact with the UI. It's weird to call a service in the async task, is there any reason why you did that?

Upvotes: 1

Ted Hopp
Ted Hopp

Reputation: 234795

From the guide topic Services:

Caution: A services runs in the same process as the application in which it is declared and in the main thread of that application, by default. So, if your service performs intensive or blocking operations while the user interacts with an activity from the same application, the service will slow down activity performance. To avoid impacting application performance, you should start a new thread inside the service.

This doesn't change just because you call startService from an AsyncTask.

Upvotes: 9

Related Questions