23

Nella mia applicazione Android, ho una semplice visualizzazione elenco con adattatore. C'è una query pesante che è quella di riempire la vista elenco con i dati. Quindi lo metto in un IntentService che viene eseguito in un altro thread.Avvia IntentService da Attività e aggiorna Attività quando IntentService è terminato

In genere, IntentService viene eseguito separatamente, solo per interrogare alcuni dati e inserirlo nel database SQLite.

Ma ora mi piacerebbe avere la seguente possibilità:

  1. L'attività inizia l'IntentService con StartService().
  2. IntentService fa il suo lavoro pesante.
  3. Al termine di IntentService, è necessario informare l'attività sul risultato in modo che l'attività possa essere aggiornata per mostrare i nuovi dati.

È possibile? Ho letto un sacco di domande qui su Stack Overflow su questo argomento. Ma in ogni domanda, c'era un'altra soluzione. Quindi voglio chiederti a tutti: quale soluzione è la migliore per il mio scopo?

  • Il collegamento di IntentService all'attività non sembra essere la soluzione migliore in quanto potrebbero esserci conflitti con le modifiche di configurazione dell'attività ecc. Corretto?
  • This blog post suggerisce di utilizzare AIDL con Parcelables - che per me è molto complesso. C'è un modo più semplice, non è vero?
  • Uno potrebbe impostare un ricevitore di trasmissione nell'attività e attivare questa trasmissione in IntentService al termine.
  • Alcune persone dicono che dovresti use createPendingResult() to pass a PendingIntent in IntentService. Se IntentService rileva che PendingIntent nei suoi extra, lo utilizza per attivare onActivityResult() nell'attività. È questo il modo di scegliere?

risposta

21

Per fare un esempio, io uso un ResultReceiver per chiamare notifyDataSetChanged() sull'adattatore del mio Activity (che si estende ListActivity). Può essere adattato per fare tutto ciò di cui hai bisogno.

codice ResultReceiver:

public class MyResultReceiver extends ResultReceiver { 

    private Context context = null; 

    protected void setParentContext (Context context) { 
     this.context = context; 
    } 

    public MyResultReceiver(Handler handler) { 
     super(handler); 
    } 

    @Override 
    protected void onReceiveResult (int resultCode, Bundle resultData) { 

     // Code to process resultData here 

     ((BaseAdapter) ((ListActivity)context).getListAdapter()).notifyDataSetChanged(); 
    } 
} 

codice MyActivity:

public class MyActivity extends ListActivity { 

    private MyResultReceiver theReceiver = null; 

    ... 

    private void callService() { 
     theReceiver = new MyResultReceiver(new Handler()); 
     theReceiver.setParentContext(this); 
     Intent i = new Intent("com.mycompany.ACTION_DO_SOMETHING"); 

     // Code to define and initialize myData here 

     i.putExtra("someData", myData); 
     i.putExtra("resReceiver", theReceiver); 
     startService(i); 

    } 
} 

codice IntentService:

Bundle resultBundle = new Bundle(); 
ResultReceiver resRec = intent.getParcelableExtra("resReceiver"); 

// Do some work then put some stuff in resultBundle here 

resRec.send(12345, resultBundle); 
+0

Grazie mille per questa soluzione e la descrizione dettagliata! Devo registrare ResultReceiver o Intent personalizzato nel file manifest di Android? E posso inserire elementi come ArrayList o Cursor nel pacchetto di risultati? Ho bisogno di parcelables lì? – caw

+0

Il ResultReceiver non ha bisogno di essere registrato nel manifest ma ho l'intento personalizzato registrato per i miei scopi. È possibile chiamare IntentService in qualsiasi modo si desideri purché ci sia un Intent per passare il ResultReceiver. Per quanto riguarda resultBundle puoi inserire tutto ciò che un Bundle può gestire. – Squonk

+0

È interessante notare che due thread simili hanno ottenuto la soluzione accettata di utilizzare ResultReceiver, tuttavia il modo ufficiale sembra essere LocalBroadcastManager. Penso che il motivo per cui LocalBroadcastManager sia preferibile in quanto il ResultReceiver può essere distrutto se l'attività viene distrutta e quindi riavviata? –

3

Suggerirei di utilizzare un Ricevitore Broadcast nell'Attività in attesa del risultato. Il servizio utilizzerà solo sendBroadcast con un numero personalizzato Intent.

+0

Grazie! Ma non è anche un po 'esagerato perché la trasmissione è disponibile a livello di sistema (per tutte le applicazioni)? – caw

+0

Penso che ci siano modi per non trasmettere per l'intero sistema. E se si volesse eseguire il servizio in un processo diverso, sarebbe un modo semplice di comunicazione. –

+2

[LocalBroadcastManager] (http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html) è l'oggetto che è necessario effettuare una trasmissione all'interno della tua app. – AlexSanchez

10

Quando l'IntentService completata, dovrebbe utilizzare LocalBroadcastManager per inviare l'intenzione di qualsiasi registrati attività.

L'IntentService conterrà il codice come questo:

private void sendBroadcast() { 
    Intent intent = new Intent("myBroadcastIntent"); 
    intent.putExtra("someName", someValue); 
    LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 
} 

L'attività riceve la notifica conterrà il codice come questo:

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    // ... 
    BroadcastReceiver receiver = new BroadcastReceiver() { 
     @Override 
     public void onReceive(Context context, Intent intent) { 
      String someValue = intent.getStringExtra("someName"); 
      // ... do something ... 
     } 
    }; 
    LocalBroadcastManager.getInstance(this) 
     .registerReceiver(receiver, new IntentFilter("myBroadcastIntent")); 
} 

Per ulteriori profondità, vedi il post sul blog Using LocalBroadcastManager In Service To Activity Communications.

11

Nessuna delle altre risposte fa riferimento alla documentazione ufficiale di Android

https://developer.android.com/training/run-background-service/report-status.html

che afferma chiaramente che per la comunicazione Activity-IntentService "Il metodo raccomandato per inviare e ricevere lo status è quello di utilizzare un LocalBroadcastManager, che limita trasmetti oggetti Intent a componenti nella tua app "!

+0

grazie per aver segnalato la documentazione ufficiale –

Problemi correlati