2012-01-12 13 views
45

Devo monitorare le posizioni dell'utente utilizzando un servizio in background, quindi caricarle e mostrare il percorso all'utente.Ottenere la posizione GPS tramite un servizio in Android

Utilizzando un'attività, era abbastanza facile ottenere posizioni GPS, ma quando ho avuto modo di farlo tramite un servizio, sono venuto in un problema in quanto sembra funzionare solo per thread looper (o qualcosa del genere).

Come ho cercato su Internet per una soluzione, ho scoperto che molte persone hanno avuto lo stesso problema, ma non sono riuscito a trovare una soluzione funzionante. Alcuni dicono che devi usare prepare-> loop-> quit, e alcuni dicono che devi usare un handlerThread, ma ancora, non riesco a scoprire come fare queste cose in modo corretto.

+0

discussioni loopy: D Vuoi dire fili dei crochet. Un thread Looper è un thread speciale con un meccanismo di coda di richieste. Il thread principale o dell'interfaccia utente è un thread Looper. Per quanto riguarda il problema con un servizio, stai invocando requestLocationUpdates sul thread principale? O lo stai facendo in un thread diverso? Poiché le attività e i servizi vengono eseguiti tramite il thread principale che è un thread looper, pertanto il richiamo di RequestLocationUpdates deve essere lo stesso. Puoi indicare gli altri post che menzionano questo problema di cui stai parlando? –

risposta

-7

ok, ho risolto con la creazione di un gestore sul onCreate del servizio e chiamando le funzioni gps da lì.

+62

Invia il codice per favore. Aiuterebbe davvero gli altri a imbattersi in questa pagina quando cercano risposte. – Razgriz

+1

questo è stato risposto molto tempo fa, ma proverò a spiegare: poiché la gestione GPS deve essere eseguita sul thread dell'interfaccia utente, creare un oggetto Handler su uno qualsiasi dei metodi sul servizio che vengono eseguiti sul thread dell'interfaccia utente (come onCreate) e impostarlo su un campo nel servizio. Quindi, ogni volta che è necessario utilizzare le operazioni GPS, basta chiamare post (eseguibile) su questa istanza dell'handler. –

+0

Puoi postare il codice per favore? – delive

40

Non capisco quale sia esattamente il problema con l'implementazione della funzionalità di ascolto della posizione nel Servizio. Sembra molto simile a quello che fai in Activity. Basta definire un listener di posizione e registrarsi per gli aggiornamenti di posizione. È possibile fare riferimento al seguente codice come ad esempio:

manifest:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 
<application 
    android:icon="@drawable/ic_launcher" 
    android:label="@string/app_name" > 
    <activity android:label="@string/app_name" android:name=".LocationCheckerActivity" > 
     <intent-filter > 
      <action android:name="android.intent.action.MAIN" /> 
      <category android:name="android.intent.category.LAUNCHER" /> 
     </intent-filter> 
    </activity> 
    <service android:name=".MyService" android:process=":my_service" /> 
</application> 

Il file di servizio:

import android.app.Service; 
import android.content.Context; 
import android.content.Intent; 
import android.location.Location; 
import android.location.LocationManager; 
import android.os.Bundle; 
import android.os.IBinder; 
import android.util.Log; 

public class MyService extends Service 
{ 
private static final String TAG = "BOOMBOOMTESTGPS"; 
private LocationManager mLocationManager = null; 
private static final int LOCATION_INTERVAL = 1000; 
private static final float LOCATION_DISTANCE = 10f; 

private class LocationListener implements android.location.LocationListener{ 
    Location mLastLocation; 
    public LocationListener(String provider) 
    { 
     Log.e(TAG, "LocationListener " + provider); 
     mLastLocation = new Location(provider); 
    } 
    @Override 
    public void onLocationChanged(Location location) 
    { 
     Log.e(TAG, "onLocationChanged: " + location); 
     mLastLocation.set(location); 
    } 
    @Override 
    public void onProviderDisabled(String provider) 
    { 
     Log.e(TAG, "onProviderDisabled: " + provider);    
    } 
    @Override 
    public void onProviderEnabled(String provider) 
    { 
     Log.e(TAG, "onProviderEnabled: " + provider); 
    } 
    @Override 
    public void onStatusChanged(String provider, int status, Bundle extras) 
    { 
     Log.e(TAG, "onStatusChanged: " + provider); 
    } 
} 
LocationListener[] mLocationListeners = new LocationListener[] { 
     new LocationListener(LocationManager.GPS_PROVIDER), 
     new LocationListener(LocationManager.NETWORK_PROVIDER) 
}; 
@Override 
public IBinder onBind(Intent arg0) 
{ 
    return null; 
} 
@Override 
public int onStartCommand(Intent intent, int flags, int startId) 
{ 
    Log.e(TAG, "onStartCommand"); 
    super.onStartCommand(intent, flags, startId);  
    return START_STICKY; 
} 
@Override 
public void onCreate() 
{ 
    Log.e(TAG, "onCreate"); 
    initializeLocationManager(); 
    try { 
     mLocationManager.requestLocationUpdates(
       LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE, 
       mLocationListeners[1]); 
    } catch (java.lang.SecurityException ex) { 
     Log.i(TAG, "fail to request location update, ignore", ex); 
    } catch (IllegalArgumentException ex) { 
     Log.d(TAG, "network provider does not exist, " + ex.getMessage()); 
    } 
    try { 
     mLocationManager.requestLocationUpdates(
       LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE, 
       mLocationListeners[0]); 
    } catch (java.lang.SecurityException ex) { 
     Log.i(TAG, "fail to request location update, ignore", ex); 
    } catch (IllegalArgumentException ex) { 
     Log.d(TAG, "gps provider does not exist " + ex.getMessage()); 
    } 
} 
@Override 
public void onDestroy() 
{ 
    Log.e(TAG, "onDestroy"); 
    super.onDestroy(); 
    if (mLocationManager != null) { 
     for (int i = 0; i < mLocationListeners.length; i++) { 
      try { 
       mLocationManager.removeUpdates(mLocationListeners[i]); 
      } catch (Exception ex) { 
       Log.i(TAG, "fail to remove location listners, ignore", ex); 
      } 
     } 
    } 
} 
private void initializeLocationManager() { 
    Log.e(TAG, "initializeLocationManager"); 
    if (mLocationManager == null) { 
     mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE); 
    } 
} 
} 
+0

so, ha funzionato bene in un progetto parallelo, ma lavoro con alcune persone e per qualche ragione, ottengo sempre un'eccezione: java.lang.RuntimeException: impossibile creare il gestore all'interno del thread che non ha chiamato Looper. prepare() ho guardato il codice e non riesco a vedere che funzioni su un thread speciale e, proprio come nel tuo codice, il servizio gira su un processo con un nome specifico. –

+0

forse è perché il servizio ha il suo processo e, quando successivamente apri l'applicazione, usa un thread diverso, che non è quello originale? –

+1

btw, è necessario chiamare "removeUpdates" per il metodo "onDestroy"? penso che rimuoverlo non comporterà perdite di memoria, no? –

2

Proprio complemento, ho implementato in questo modo e di solito ha lavorato nella mia classe di servizio

nel mio servizio

@Override 
public void onCreate() 
{ 
    mHandler = new Handler(Looper.getMainLooper()); 
    mHandler.post(this); 
    super.onCreate(); 
} 

@Override 
public void onDestroy() 
{ 
    mHandler.removeCallbacks(this);  
    super.onDestroy(); 
} 

@Override 
public void run() 
{ 
    InciarGPSTracker(); 
} 
17
public class GPSService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener { 
    private LocationRequest mLocationRequest; 
    private GoogleApiClient mGoogleApiClient; 
    private static final String LOGSERVICE = "#######"; 

    @Override 
    public void onCreate() { 
     super.onCreate(); 
     buildGoogleApiClient(); 
     Log.i(LOGSERVICE, "onCreate"); 

    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     Log.i(LOGSERVICE, "onStartCommand"); 

     if (!mGoogleApiClient.isConnected()) 
      mGoogleApiClient.connect(); 
     return START_STICKY; 
    } 


    @Override 
    public void onConnected(Bundle bundle) { 
     Log.i(LOGSERVICE, "onConnected" + bundle); 

     Location l = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); 
     if (l != null) { 
      Log.i(LOGSERVICE, "lat " + l.getLatitude()); 
      Log.i(LOGSERVICE, "lng " + l.getLongitude()); 

     } 

     startLocationUpdate(); 
    } 

    @Override 
    public void onConnectionSuspended(int i) { 
     Log.i(LOGSERVICE, "onConnectionSuspended " + i); 

    } 

    @Override 
    public void onLocationChanged(Location location) { 
     Log.i(LOGSERVICE, "lat " + location.getLatitude()); 
     Log.i(LOGSERVICE, "lng " + location.getLongitude()); 
     LatLng mLocation = (new LatLng(location.getLatitude(), location.getLongitude())); 
     EventBus.getDefault().post(mLocation); 

    } 

    @Override 
    public void onDestroy() { 
     super.onDestroy(); 
     Log.i(LOGSERVICE, "onDestroy - Estou sendo destruido "); 

    } 

    @Nullable 
    @Override 
    public IBinder onBind(Intent intent) { 
     return null; 
    } 

    @Override 
    public void onConnectionFailed(ConnectionResult connectionResult) { 
     Log.i(LOGSERVICE, "onConnectionFailed "); 

    } 

    private void initLocationRequest() { 
     mLocationRequest = new LocationRequest(); 
     mLocationRequest.setInterval(5000); 
     mLocationRequest.setFastestInterval(2000); 
     mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); 

    } 

    private void startLocationUpdate() { 
     initLocationRequest(); 

     if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 
      // TODO: Consider calling 
      // ActivityCompat#requestPermissions 
      // here to request the missing permissions, and then overriding 
      // public void onRequestPermissionsResult(int requestCode, String[] permissions, 
      //           int[] grantResults) 
      // to handle the case where the user grants the permission. See the documentation 
      // for ActivityCompat#requestPermissions for more details. 
      return; 
     } 
     LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); 
    } 

    private void stopLocationUpdate() { 
     LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); 

    } 

    protected synchronized void buildGoogleApiClient() { 
     mGoogleApiClient = new GoogleApiClient.Builder(this) 
       .addOnConnectionFailedListener(this) 
       .addConnectionCallbacks(this) 
       .addApi(LocationServices.API) 
       .build(); 
    } 

} 
+0

Sto usando libb EventBus per inviare la posizione da visualizzare. -> EventBus.getDefault(). Post (mLocation) – vrbsm

+0

Non è in esecuzione in background. Sto usando Red MI note 3. Funziona perfettamente quando l'app è attiva ma non funziona come servizio quando uccido l'app. –

+1

come gestire le autorizzazioni e le impostazioni della posizione qui ?? –

Problemi correlati