2012-06-27 12 views
5

Sono in esecuzione di un servizio in background che legge GPS/posizione di rete e ha bisogno di fare quanto segue:Servizio Android e compito ripetitivo in esecuzione in discussioni

  • eseguito in background senza interruzioni al riavvio app e tenerlo vivo il più possibile senza essere uccisi (Questa è risolto con l'aiuto di commento muggito di Merlino)

  • su una nuova posizione ricevuta, chiamare un servizio web e inviare la posizione di lettura

  • hanno un repeti attività in esecuzione ogni 60 secondi e inviare nuovamente l'ultima posizione al servizio web. Ciò aiuterà nel caso in cui l'utente rimanga nella stessa posizione.

Ci sono alcune cose che ho considerato e non sono sicuro di aver capito bene. Il servizio viene eseguito nello stesso thread dell'app principale, pertanto l'invio della posizione al server sullo stesso thread del thread dell'interfaccia utente potrebbe causare il blocco dell'interfaccia utente e ciò non è corretto. Inoltre, non sono sicuro che gli ascoltatori GPS/rete abbiano i loro thread o utilizzano lo stesso thread dell'app.

Ecco un codice abbreviata del servizio per rendere le cose più chiare:

public class GPSLoggerService extends Service { 
@Override 
public void onCreate() { 
    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 
} 

@Override 
public int onStartCommand(Intent intent, int flags, int startId) { 

    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 50, locationListenerNetwork); 
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 50, locationListenerGps); 

    scheduleTaskExecutor = Executors.newScheduledThreadPool(5); 
    scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() { 
     @Override 
     public void run() { 
       updateLocation(lastLocation); 
     }, 60, 60, TimeUnit.SECONDS); 

    return START_STICKY; 
} 

LocationListener locationListenerGps = new LocationListener() { 
    @Override 
    public void onLocationChanged(Location location) { 
     updateLocation(location); 
    } 
... 
}  

LocationListener locationListenerNetwork = new LocationListener() { 
    @Override 
    public void onLocationChanged(Location location) { 
     updateLocation(location); 
    } 
... 
} 

private void updateLocation(Location readLocation) { 
    //web service call 
    String response = WebServiceCalls.updateLocation(readLocation); 

    //log data in a local Sqlite database 
    saveLocation(readLocation) 
} 

La mia preoccupazione principale è come gestire la chiamata updateLocation e farlo in un thread separato dal thread applicazione principale. Il planningTaskExecutor credo che non sia la strada da percorrere. A volte, anche dopo aver chiamato stopService() il servizio rimane attivo, anche se dico a TaskExecutor di shutDown. Non riesco a trovare un'altra spiegazione per la quale il servizio non si stia fermando. Quindi per ricapitolare: ho bisogno di inviare la posizione ogni volta che gli ascoltatori ricevono una nuova posizione e la rinvia ogni 60 secondi. Devo anche essere in grado di interrompere il servizio rapidamente con la cancellazione dei thread attivi.

Come mi consiglieresti a gestire il mio caso?

+0

hai bisogno per avviarlo appiccicoso? – Merlin

risposta

0

Per evitare che il servizio venga distrutto, è possibile avviare il servizio come foreground service.

E dopo aver ottenuto una posizione dal metodo onLocationChanged() è possibile utilizzare uno asynctask per inviare una posizione al servizio web in modo che non bloccherà l'interfaccia utente.

Modifica

  1. È possibile impostare il tempo minimo e la distanza minima viaggiato nei tuoi requestLocationUpdates metodo. Quindi non penso che dovresti usare l'attività dello schedulatore per inviare la posizione al server. In base all'argomento relativo al tempo minimo e alla distanza minima, il responsabile della posizione controllerà la posizione.Se c'è una posizione modificata, chiamerà il metodo onLocationChanged() con la nuova posizione. Ora, per la soluzione, l'utente rimane nella stessa posizione. è possibile modificare alcune logiche sul lato server come se ci fosse una differenza di 1 ora tra due posizioni successive location1 e location2 significa che l'utente è rimasto 1 ora in posizione1.

  2. È possibile utilizzare una sola classe LocationListener ad ascoltare GPS e percorso di rete.

  3. Quando si arriva posizione nel metodo onLocationChanged() è possibile inviare quella posizione utilizzando un AsyncTask.
  4. Dopo aver ottenuto la posizione è possibile salvare quella posizione nella preferenza o database per controllare il meteo il GPS e il provider di rete inviarti stessa posizione, quindi se si traccia quindi è possibile salvare la chiamata WebAPI e così è possibile salvare una parte del batteria.
+0

Come potete vedere ci sono letture sia dal gps che dalla rete e anche l'invio in programma. Ciò significa che potrei avere 3 chiamate per asynctask nello stesso tempo. Come dovrei cancellarli? – Alin

+0

Devo inviare la posizione anche se il conducente rimane nella stessa posizione in cui questo fa parte delle specifiche del progetto. Quindi non posso cambiarlo. Comunque non vedo asynctask come una buona soluzione per il mio caso. Immagina di poter ricevere una nuova posizione ogni 1 secondo se l'utente sta guidando. Ciò significa che ogni 1 secondo devo attivare l'asynctask in modo che possa avere 2-3 attività in esecuzione ... Come posso cancellarle quando il servizio si ferma? – Alin

+0

Basti pensare al caso in cui si desidera inviare la posizione ogni 1 secondo. Vuoi gestire la tua chiamata webAPI ogni 1 secondo (non tutte le volte, ma in caso di modifica della posizione successiva). Se annulli l'ultimo e se aggiorni quello nuovo allora ofcurse l'ultima posizione sarà ignorata. – Dharmendra

4

Vorrei utilizzare un IntentService e utilizzare semplicemente AlarmManager per attivare gli intent.

Il principale vantaggio di questo è che non esiste un codice discussione di cui preoccuparsi, come fa il suo lavoro in background

UPDATE

Un altro approccio interessante può essere trovato in https://stackoverflow.com/a/7709140/808940

+0

E la chiamata suLocationChanged? Ha una sua discussione o attiva un IntentService anche in questo? Devo anche sapere se la chiamata al web ha avuto successo o meno. Questa parte non penso che sarebbe facile da fare con un IntentService. Credo che ci dovrebbe essere una trasmissione inviata, giusto? – Alin

2
  • il servizio viene eseguito lo stesso processo come applicazione principale, non infilare. Inoltre, se si desidera eseguire il servizio in un altro processo, è possibile utilizzare il tag android:process.

  • Io non so perché si desidera chiamare WebService ogni 60 secondi, 60 secondi, perché è troppo poco. Inoltre, è possibile saltare la chiamata al servizio Web quando la posizione non è stata modificata, poiché richiede una comunicazione di rete ed è un'operazione costosa.

  • Non v'è alcuna necessità di utilizzare gli esecutori. Dovresti mantenere il numero di thread il meno possibile. Per eseguire un'attività a intervalli particolari, utilizzare AlarmManager per fornire l'intento in un determinato momento. Controllare il metodo setRepeating() per impostare l'allarme.

  • Un'altra cosa è, si dovrebbe cercare di evitare di fare qualsiasi operazione in Listener. Perché c'è un timeout di 10 secondi che il sistema consente prima di considerare il ricevitore/ascoltatore da bloccare e un candidato da uccidere. È necessario utilizzare Handler per eseguire attività nel thread in background (ad esempio ogni volta che si riceve l'aggiornamento dal listener, aggiungere un messaggio alla coda del gestore e verrà selezionato quando il thread del gestore è gratuito).

-1

Si dovrebbe usare AsynchTask:

public class RefreshTask extends AsyncTask<Integer, Void, Integer> { 



    /** 
    * The system calls this to perform work in a worker thread and delivers 
    * it the parameters given to AsyncTask.execute() 
    */ 

    public RefreshTask() { 

    } 

    protected Integer doInBackground(Integer... millis) { 
     try{ 
      int waitTime = 0; 
      while(waitTime<60000){ 
       Thread.sleep(100); 
       waitTime += 100; 
      } 

      //update location here 

     }catch(InterruptedException e){ 

     } 



     return 1; 
    } 

    /** 
    * The system calls this to perform work in the UI thread and delivers 
    * the result from doInBackground() 
    */ 
    protected void onPostExecute(Integer result) { 
     new RefreshTask.execute(); 
    } 


} 
+0

Non utilizzare 'AsyncTask' per questo tipo di problema. A seconda della versione API, bloccherà tutti gli altri AsyncTask. – chrulri

Problemi correlati