Android startService () занимает много времени, чтобы вернуться в поток пользовательского интерфейса - PullRequest
4 голосов
/ 06 декабря 2011

Мой пример использования (примерно) следующий при первом запуске:

  1. действие запускает службу
  2. служба получает и сохраняет данные в базе данных
  3. служба уведомляетактивность с намерением
  4. активность отображает данные

Теперь я хочу отображать индикатор выполнения, когда служба занята.Проблема в том, что

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

требуется очень много времени, чтобы «вернуться» в поток пользовательского интерфейса.Кажется, это синхронизированная функция (или , а не ?).Если класс обслуживания пуст, команда startService обрабатывается практически мгновенно.Кажется, поток пользовательского интерфейса ждет, пока Serice справится со своей работой, что не имеет никакого смысла.Я попытался запустить (как бы глупо это ни казалось), чтобы запустить службу как асинхронную задачу, отображая индикатор выполнения в моем потоке пользовательского интерфейса.Как ни странно, иногда это работает.В других случаях я просто получаю белый экран во время работы моего сервиса, а затем - миллисекунду с индикатором прогресса, а затем и мой пользовательский интерфейс.

Теперь мой вопрос: как запустить службу без блокировки моего интерфейса?

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);
    }
}

Ответы [ 4 ]

9 голосов
/ 06 декабря 2011

Из темы руководства Услуги :

Внимание. Службы по умолчанию выполняются в том же процессе, что и приложение, в котором они объявлены, и в главном потоке этого приложения. Таким образом, если ваша служба выполняет интенсивные или блокирующие операции, когда пользователь взаимодействует с активностью из одного и того же приложения, эта служба снизит производительность активности. Чтобы избежать влияния на производительность приложения, вы должны запустить новый поток внутри службы.

Это не меняется только потому, что вы звоните startService из AsyncTask.

1 голос
/ 06 декабря 2011

Либо выполняйте свою работу в самом AsyncTask, используйте IntentService вместо простого старого Service или начните поток с вашего Service, чтобы выполнить свою работу.Service в Android по своей сути не использует другой поток (IntentService выполняет свою работу).

Несмотря на запуск вашего Service с AsyncTask, прямо сейчаскажется, что фактическая работа выполняется в вашем потоке пользовательского интерфейса.

1 голос
/ 06 декабря 2011

Я думаю, вам следует просто переместить логику из сервиса в метод doInBackground в асинхронной задаче.Это то, для чего предназначена асинхронная задача - выполнять тяжелую работу, предоставляя вам простой способ взаимодействия с пользовательским интерфейсом.Странно вызывать службу в асинхронной задаче, есть ли причина, по которой вы это сделали?

0 голосов
/ 08 декабря 2012

, пожалуйста, используйте этот код, чтобы легко сделать то, что вы спросили.

@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);
}

В Сервисе, когда ваша задача будет выполнена, вызовите этот метод

sendBroadcast(new Intent("<FLAG>"));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...