Android startService () kost veel tijd om terug te keren naar UI-threads

mijn usecase is (ruwweg) het volgende bij de eerste startup:

  1. activiteit start een service
  2. service haalt en bewaart gegevens in een database
  3. service meldt activiteit met een intentie
  4. activiteit geeft gegevens weer

Nu wil ik een voortgangsbalk weergeven terwijl de service bezet is. Het probleem is:

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

duurt erg lang om "terug te komen" naar de UI-thread. Het lijkt een gesynchroniseerde functie te zijn (of not ?). Als de serviceklasse leeg is, wordt de opdracht startservice vrijwel onmiddellijk verwerkt. Het lijkt erop dat de UI-thread wacht totdat de Serice zijn werk afhandelt, wat helemaal niet logisch is. Ik probeerde te starten (hoe stom het ook mag lijken) om de service asynchroon te laten beginnen met een voortgangsbalk in mijn UI-thread. Raar genoeg werkt dit soms. Vaak krijg ik een wit scherm terwijl mijn service werkt en daarna voor een milliseconde ma voortgangsbalk en dan mijn gebruikersinterface.

Nu mijn vraag: Hoe start ik de dienst zonder mijn gebruikersinterface te blokkeren?

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 {

    @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

4 antwoord

Uit de handleiding Services :

Let op: services worden standaard uitgevoerd in hetzelfde proces als de toepassing waarin deze wordt gedeclareerd en in de hoofddraad van die toepassing. Dus als uw service intensieve of blokkerende bewerkingen uitvoert terwijl de gebruiker communiceert met een activiteit uit dezelfde toepassing, vertraagt ​​de service de prestaties van de activiteit. Als u geen invloed wilt hebben op de prestaties van de toepassing, start u een nieuwe thread in de service.

Dit verandert niet alleen omdat u startService aanroept vanuit een AsyncTask.

9
toegevoegd

Doe uw werk in de AsyncTask zelf, gebruik een IntentService in plaats van een gewone oude Service of start een thread vanuit uw Service om je werk te doen. Een Service in Android maakt niet inherent gebruik van een andere thread ( IntentService doet zijn werk).

Ondanks starten uw Service van een AsyncTask , lijkt het erop dat het daadwerkelijke werk wordt uitgevoerd in uw UI-thread.

1
toegevoegd

Ik denk dat je gewoon de logica van de service naar de doInBackground-methode in de async-taak moet verplaatsen. Dat is de async-taak voor hard werk, zodat u op een eenvoudige manier kunt communiceren met de gebruikersinterface. Het is raar om een ​​service te bellen in de async-taak, is er een reden waarom je dat hebt gedaan?

1
toegevoegd
Hm, waar. Ik dacht dat het starten van een thread zou resulteren in een andere thread die parallel moet worden uitgevoerd. Dit lijkt verkeerd te zijn. Ik zal proberen het "werk" van mijn service in een async-taak te plaatsen. Dank je
toegevoegd de auteur Redfox, de bron

Gebruik alstublieft deze code op de gemakkelijke manier om te doen wat u in vraag stelde.

@Override
public void onCreate(final Bundle savedInstanceState) {

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

    Intent intent = null;
    registerReceiver(dataUpdated, new IntentFilter(""));
    //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) {
        //
              pd.dismiss();
    }
};

@Override
protected void onDestroy() {

    unregisterReceiver(dataUpdated);
}

In dienst wanneer uw taak voltooid is, roep deze methode

sendBroadcast(new Intent(""));
0
toegevoegd