Autore Topic: Differenze tra IntentService e Service  (Letto 2912 volte)

Offline g4b0

  • Nuovo arrivato
  • *
  • Post: 36
  • Respect: 0
    • Mostra profilo
    • gabo 3.0
  • Dispositivo Android:
    Nexus One
  • Sistema operativo:
    Debian Testing
Differenze tra IntentService e Service
« il: 08 Luglio 2011, 11:00:07 CEST »
0
Ciao a tutti,
Come da subject, leggendo la Dev Guide su android.com  http://developer.android.com/guide/topics/fundamentals/services.html mi é sorto un dubbio. A parte il fatto che IntentService é un estensione di Service, in pratica per cosa differiscono? E sempre in pratica, in quali situazioni uno é meglio dell'altro?

Grazie
--
g4b0, linux user n. 369000
http://brosulo.net

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:Differenze tra IntentService e Service
« Risposta #1 il: 08 Luglio 2011, 12:41:20 CEST »
0
Il codice Service viene eseguito nel main thread. Tipicamente, se il lavoro che deve fare il thread è una operazione lunga (es.: download da internet) hai necessità di crearti un thread parallelo.

IntentService fa tutto questo da solo, è esclusivamente una utility:
Citazione
The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.

Attento che se hai più intent che arrivano in contemporanea questi vengono messi in coda ed esauditi uno alla volta.

Offline g4b0

  • Nuovo arrivato
  • *
  • Post: 36
  • Respect: 0
    • Mostra profilo
    • gabo 3.0
  • Dispositivo Android:
    Nexus One
  • Sistema operativo:
    Debian Testing
Re:Differenze tra IntentService e Service
« Risposta #2 il: 08 Luglio 2011, 13:00:10 CEST »
0
Ok. Rileggendo ho nototato che per l'intentService specificano:

This is the best option if you don't require that your service handle multiple requests simultaneously.

Quindi nei casi in cui si voglia servire un intent alla volta é meglio usare l'intentService, perché é piú semplice da gestire ed il codice risulta meno complesso. Nel caso in cui si vogliano gestire intent contemporanei, invece bisogna usare il Service e lanciare un nuovo Thread per ogni intent che arriva, con relative complicazioni nel codice.

Quale potrebbe essere un esempio pratico del caso degli intent contemporanei? Non mi viene in mente nulla...
--
g4b0, linux user n. 369000
http://brosulo.net

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:Differenze tra IntentService e Service
« Risposta #3 il: 08 Luglio 2011, 13:07:26 CEST »
0
Il caso più semplice che mi viene in mente è il seguente:
hai una comunissima ListView con immagine e testo per ogni riga.;
l'immagine viene presa da internet;
per il recupero di una immagine crei un Service che accetta la url dell'immagine, la scarica, la copia in cache, ed invia un intent di ritorno all'activity dicendo "Immagine X disponibile sulla cache al path Y".

Capisci bene che essendo una ListView vengono visualizzate più righe contemporaneamente, quindi partono in contemporanea più richieste al Service.

Se implementi il tutto con un IntentService, le immagini verranno scaricate una alla volta, immaginati la lentezza nella visualizzazione.
Se implementi un Service puro, puoi far partire in contemporanea tutti i download aumentando la velocità di visualizzazione.

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
Re:Differenze tra IntentService e Service
« Risposta #4 il: 08 Luglio 2011, 13:53:47 CEST »
0
Il caso più semplice che mi viene in mente è il seguente:
hai una comunissima ListView con immagine e testo per ogni riga.;
l'immagine viene presa da internet;
per il recupero di una immagine crei un Service che accetta la url dell'immagine, la scarica, la copia in cache, ed invia un intent di ritorno all'activity dicendo "Immagine X disponibile sulla cache al path Y".

Capisci bene che essendo una ListView vengono visualizzate più righe contemporaneamente, quindi partono in contemporanea più richieste al Service.

Se implementi il tutto con un IntentService, le immagini verranno scaricate una alla volta, immaginati la lentezza nella visualizzazione.
Se implementi un Service puro, puoi far partire in contemporanea tutti i download aumentando la velocità di visualizzazione.
ma questa cosa te la faresti con un action specifica o faresti un action "it.mio.action.FINISHED" e poi metti extras nell'intent?
mi trovo un po in difficoltà su questa tecnica, ho dei broadcast receiver che aspettano istruzioni ma vorrei evitare di fare 3 action per ogni activity (running-success-fail)
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:Differenze tra IntentService e Service
« Risposta #5 il: 08 Luglio 2011, 14:08:32 CEST »
0
ma questa cosa te la faresti con un action specifica o faresti un action "it.mio.action.FINISHED" e poi metti extras nell'intent?
mi trovo un po in difficoltà su questa tecnica, ho dei broadcast receiver che aspettano istruzioni ma vorrei evitare di fare 3 action per ogni activity (running-success-fail)

Non capisco la domanda... che differenza c'è tra una "action specifica" e "it.mio.action.FINISHED"... non sono tutte e due specifiche?

In ogni caso io farei una cosa di questo tipo: la ListView fa partire il service DownloadService inserendo nell'extra dell'intent la url dell'immagine da scaricare. Appena finito il download dell'url e dopo avere salvato l'immagine sulla cache, il service invia un intent "com.marcoduff.downloadservice.action.DOWNLOAD_COMPLETED" con extrast SOURCE_URL che contiene la url in input e DOWLOADED_FILE con il path locale all'immagine.

La View personalizzata dell'immagine si occupa di registrare un broadcast receiver che riceve tutti gli intent e appena trova il suo si unregistra e visualizza l'immagine.

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
Re:Differenze tra IntentService e Service
« Risposta #6 il: 08 Luglio 2011, 14:41:14 CEST »
0
Non capisco la domanda... che differenza c'è tra una "action specifica" e "it.mio.action.FINISHED"... non sono tutte e due specifiche?

In ogni caso io farei una cosa di questo tipo: la ListView fa partire il service DownloadService inserendo nell'extra dell'intent la url dell'immagine da scaricare. Appena finito il download dell'url e dopo avere salvato l'immagine sulla cache, il service invia un intent "com.marcoduff.downloadservice.action.DOWNLOAD_COMPLETED" con extrast SOURCE_URL che contiene la url in input e DOWLOADED_FILE con il path locale all'immagine.

La View personalizzata dell'immagine si occupa di registrare un broadcast receiver che riceve tutti gli intent e appena trova il suo si unregistra e visualizza l'immagine.

Ecco, io intendevo un'action specifica per service!
cioè metti che la mia app ha due activity:
1-scarica una lista di persone (formato json) fa il parsing e salva su db. Finito di scaricare le persone vengono mostrate in una listview
2-scarica una lista di operazioni (sempre json) fa parsing e salva su db. Poi vengono mostrate le cose in listview.
Il miei dubbi sono:
-fare 2 service? farne uno?
-gli intent, saranno uguali per entrambe le activity?

cioè tu faresti per entrambi "com.marcoduff.downloadservice.action.DOWNLOAD_COMPLETED"
oppure un "com.marcoduff.downloadservice.action.DOWNLOAD__PEOPLE_COMPLETED" e poi "com.marcoduff.downloadservice.action.DOWNLOAD_WORKS_COMPLETED"

questi i miei dubbi, che sono piu crucci mentali che altro, non credo che il sistema faccia storie se uso uno o due action (nel modo corretto)...
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia

Offline g4b0

  • Nuovo arrivato
  • *
  • Post: 36
  • Respect: 0
    • Mostra profilo
    • gabo 3.0
  • Dispositivo Android:
    Nexus One
  • Sistema operativo:
    Debian Testing
Re:Differenze tra IntentService e Service
« Risposta #7 il: 08 Luglio 2011, 15:04:49 CEST »
0
Il caso più semplice che mi viene in mente è il seguente:
hai una comunissima ListView con immagine e testo per ogni riga.;
l'immagine viene presa da internet;
per il recupero di una immagine crei un Service che accetta la url dell'immagine, la scarica, la copia in cache, ed invia un intent di ritorno all'activity dicendo "Immagine X disponibile sulla cache al path Y".

Capisci bene che essendo una ListView vengono visualizzate più righe contemporaneamente, quindi partono in contemporanea più richieste al Service.

Se implementi il tutto con un IntentService, le immagini verranno scaricate una alla volta, immaginati la lentezza nella visualizzazione.
Se implementi un Service puro, puoi far partire in contemporanea tutti i download aumentando la velocità di visualizzazione.

Ok, ora mi é piú chiara la differenza. Peccato che l'esempio sulla guida sia poco esplicativo, almeno dal mio punto di vista, dato che mi aveva confuso le idee :-\

Ora mi studio i Bound Service, poi torno con le nuove domande :)
--
g4b0, linux user n. 369000
http://brosulo.net

Offline MarcoDuff

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1073
  • Respect: +202
    • Google+
    • marcoduff
    • Mostra profilo
    • MarcoDuff's Blog
  • Dispositivo Android:
    Samsung Galaxy Nexus
  • Play Store ID:
    MarcoDuff
  • Sistema operativo:
    Windows 7
Re:Differenze tra IntentService e Service
« Risposta #8 il: 08 Luglio 2011, 17:32:53 CEST »
+4
Ok, siccome non sapevo come risponderti e siccome ho un poco di tempo libero e siccome c'è caldissimo mi sono messo a scrivere un boato di codice!

questi i miei dubbi, che sono piu crucci mentali che altro, non credo che il sistema faccia storie se uso uno o due action (nel modo corretto)...

Il punto è sempre lo stesso: quanto vuoi rendere modulare e flessibile il tuo codice? Ma anche, vale la pena renderlo tanto modulare e flessibile?

La risposta sembra banale: Ovvio che è meglio un codice modulare! Ma questo non è sempre vero. Creare codice modulare e flessibile ha un costo elevato in termini di tempo e sopratutto molto spesso un codice modulare non è mai ottimizzato per il tuo problema... questo significa che lo mantieni bene ma è poco performate! La cosa migliore... semplicemente non esiste. Sta a te capire quanto rendere modulare un codice (o quanto renderlo performante) senza mettere troppo alle strette l'altra parte.

Possiamo discutere per anni su questo punto senza mai arrivare alla soluzione! Io sono per il "piccolo, robusto e modulare" più che "viaggia come una scheggia", ma ognuno ha le proprie fissazioni.

Quello che sto per scrivere si poteva benissimo scrivere con un AsyncTask da 10 righe di codice ad hoc per la tua applicazione, ma io ho preferito creare un piccolo framework per risolvere il tuo problema.

Via alle danze!

Questo è il Service: quello che fa è esclusivamente scaricare byte di una URL da internt. Punto. Tutto il business della classe sta qui! Fare il download:
Codice (Java): [Seleziona]
package com.marcoduff.test;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import org.apache.http.util.ByteArrayBuffer;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class DownloadService extends Service {
        public static final String TAG = "DownloadService";
       
        public static final String ACTION_DOWNLOAD = "com.marcoduff.test.action.DOWNLOAD";
        public static final String EXTRA_DOWNLOAD_URL = "EXTRA_DOWNLOAD_URL";
        public static final String EXTRA_POST_DOWNLOAD_CLASS = "EXTRA_POST_DOWNLOAD_CLASS";
       
        public interface OnPostDownload {
                public void onPostDownload(Context context, byte[] downloadedBytes);
        }
       
        public static final Intent getIntent(String downloadUrl, Class<? extends OnPostDownload> className) {
                Intent intent = new Intent(ACTION_DOWNLOAD);
                intent.putExtra(EXTRA_DOWNLOAD_URL, downloadUrl);
                intent.putExtra(EXTRA_POST_DOWNLOAD_CLASS, className.getName());
                return intent;
        }
       
        @Override
        public IBinder onBind(Intent intent) {
                return null;
        }
       
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
                final Context context = this.getApplicationContext();
                final String urlString = intent.getStringExtra(EXTRA_DOWNLOAD_URL);
                final OnPostDownload postDownloadInterface = getPostDownloadClass(intent);
                new Thread() {
                        public void run() {
                                try {
                                        URL url = new URL(urlString);
                                        byte[] downloadedBytes = startDownload(url);
                                        postDownloadInterface.onPostDownload(context, downloadedBytes);
                                }
                                catch(Exception e) {
                                        Log.e(TAG, "Error downloading url "+urlString, e);
                                }
                        };
                }.start();
                return Service.START_STICKY;
        }

        private OnPostDownload getPostDownloadClass(Intent intent) {
                try {
                        String postDownloadString = intent.getStringExtra(EXTRA_POST_DOWNLOAD_CLASS);
                        Class<?> postDownloadClass = Class.forName(postDownloadString);
                        return (OnPostDownload)postDownloadClass.newInstance();
                }
                catch(Exception e) {
                        Log.w(TAG, "EXTRA_POST_DOWNLOAD_CLASS not valid!", e);
                        return null;
                }
        }

        private byte[] startDownload(URL url) throws IOException {
                URLConnection connection = url.openConnection();
                InputStream inputSteam = connection.getInputStream();
        BufferedInputStream bufferedInputStream = new BufferedInputStream(inputSteam);
        ByteArrayBuffer byteArrayBuffer = new ByteArrayBuffer(50);
        int current = 0;
        while ((current = bufferedInputStream.read()) != -1) {
                byteArrayBuffer.append((byte) current);
        }
        byte[] downloadedBytes = byteArrayBuffer.toByteArray();
        bufferedInputStream.close();
        inputSteam.close();
        return downloadedBytes;
        }
}

Dentro il Service è definita anche l'interfaccia OnPostDownload che mi serve come callback. Ho creato anche un metodo di utility statico getIntent per le creazione automatica dell'intent da creare per il download. Appena richiamato il service vengono recuperati i parametri di input dall'intent e viene fatto partire il download da internet da un thread parallelo. Finito il download uso l'interfaccia di callback per inviare i dati recuperati ad un'altra classe.
// TODO: controllo migliore delle eccezioni e dei parametri di input


Ho poi creato una classe che implementa DownloadService.OnPostDownload per la gestione dei download di tipo JSON:
Codice (Java): [Seleziona]
package com.marcoduff.test;

import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.content.Intent;

public abstract class JSonPostDownload implements DownloadService.OnPostDownload {

        @Override
        public void onPostDownload(Context context, byte[] downloadedBytes) {
                try {
                        String jsonValue = new String(downloadedBytes);
                        JSONObject json = new JSONObject(jsonValue);
                        Intent intent = downloadedJson(json);
                        context.sendBroadcast(intent);
                } catch (JSONException e) {}
        }
       
        public abstract Intent downloadedJson(JSONObject json);
}

Quello che fa è semplice: trasforma i byte recuperati in stringa e crea l'oggetto JSON. Dopo averlo creato chiama il metodo astratto per una gestione puntuale del json ed invia un intent in broadcast.

Service più classi che implementano l'interfaccia OnPostDownload  fanno parte di un progetto libreria Android. Sono e devono restare totalmente indipendenti da qualsiasi altro progetto. In poche parole ho creato un framework indipendente, modulare e flessibile.

Nel tuo progetto vai a creare una estensione della classe JSonPostDownload per la gestione del tuo particolare JSON:
Codice (Java): [Seleziona]
package com.marcoduff.test;

import org.json.JSONObject;

import android.content.Intent;

public class JSonPeopleDownload extends JSonPostDownload {
        public static final String ACTION_NEW_PEOPLE = "com.marcoduff.test.action.NEW_PEOPLE";
       
        @Override
        public Intent downloadedJson(JSONObject json) {
                // TODO Fai quello che devi fare con il json!
                Intent intent = new Intent(ACTION_NEW_PEOPLE);
                // TODO Riempi opportunamente gli extras
                return intent;
        }

}

In questa classe, attualmente l'unica del tuo progetto, fai il parsing dell'oggetto JSon delle persone (lo salvi sul db, lo spacchetti, lo manipoli, ecc...) e ritorni l'intent che vuoi venga inviato appena finisce il download.
In modo analogo crei un'altra classe per la gestione dei json work (o altri).

Nella tua HomeActivity (quella che contiene la ListView) quello che fai è semplicemente questo:
Codice (Java): [Seleziona]
package com.marcoduff.test;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;

public class AndroidTest extends Activity {
        private BroadcastReceiver peopleReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                        // TODO Aggiorni adapter ListView persone
                }
        };
       
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        Intent intent = DownloadService.getIntent("PEOPLE JSON URL GOES HERE", JSonPeopleDownload.class);
        this.startService(intent);
    }
   
    @Override
    protected void onStart() {
        super.onStart();
        registerReceiver(peopleReceiver, new IntentFilter(JSonPeopleDownload.ACTION_NEW_PEOPLE));
    }
   
    @Override
    protected void onStop() {
        unregisterReceiver(peopleReceiver);
        super.onStop();
    }
}

Ovvero richiami il service con l'intent contenente la URL del tuo json e la class che lo deve gestire ed hai finito.



Ecco, perché tutto questo codice per una stupida domanda? Perché non vi è risposta al "è meglio un service che gestisce due action o due action gestite da due service diverse?"! Dipende da cosa vuoi fare.

Ripeto al posto di tutto questo codice per uno stupido download poteva andare bene anche un metodo nell'activity (magari statico) è tutto funzionava lo stesso (e magari tutto era molto più veloce)! Ma...

Ma appena un domani avrai bisogno di scaricare un altro JSON da internet ti basta includere il progetto libreria e creare la classe ad hoc per quel JSON ed hai finito... non devi più preoccuparti di "come" lo stai recuperando... la tua libreria pensa a tutto!

Ma se domani vorrai gestire anche il download di XML, immagini, file flash, XLS, WSDL e chi più ne ha più ne metta, ti basta modificare solo la libreria creando altre classi astratte che implementano OnPostDownload... in automatico tutti i progetti che la importano avranno la gestione del download di quel particolare tipo di file.

Ma se un giorno vorrai ottimizzare il codice inserendo politiche di caching (del tipo se ho già scaricato un json e tu me lo richiedi di nuovo, non lo scarico ma ti do la versione già memorizzata) ti basta modificare il DownloadService (magari aggiungendo un parametro EXTRA_TRY_CACHE true/false che di default è false per mantenere la compatibilità con il passato) che tutti i tuoi progetti che usano la libreria avranno una politica di caching!

E tanto altro...

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
Re:Differenze tra IntentService e Service
« Risposta #9 il: 09 Luglio 2011, 00:09:44 CEST »
0
è semplicemente un post fenomenale! alcune cose ci sono,altre sono ottime soluzioni a cui non avevo pensato! grazie mille!!!!
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia