Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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);
    }
}
like image 297
Redfox Avatar asked Dec 22 '22 05:12

Redfox


2 Answers

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.

like image 150
Ted Hopp Avatar answered Dec 27 '22 19:12

Ted Hopp


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?

like image 34
gwvatieri Avatar answered Dec 27 '22 20:12

gwvatieri