2013-01-23 56 views
63

我正在創建一個將在其自己的進程中運行的後臺服務。它應該允許我聽取設備位置是否改變。我應該能夠在通知用戶界面之前更改移動距離等標準。在android中的位置監聽器的背景服務

我該怎麼辦?我對服務和LocationListener實現有一點了解。任何圍繞網絡的教程將不勝感激。

我從堆棧溢出中得到了一個back-link,但是我不太瞭解它。

+2

看看這個博客帖子:http://android-developers.blogspot.ro/2011/06/deep-dive-into-location.html – Felix

+0

見最新GoogleApiClient HTTP方法://stackoverflow.com/a/41981246/3496570 – Nepster

回答

97

首先您需要創建一個Service。在該Service中,創建一個延伸爲LocationListener的類。對於這一點,使用Service下面的代碼片段:

public class LocationService extends Service 
{ 
     public static final String BROADCAST_ACTION = "Hello World"; 
     private static final int TWO_MINUTES = 1000 * 60 * 2; 
     public LocationManager locationManager; 
     public MyLocationListener listener; 
     public Location previousBestLocation = null; 

     Intent intent; 
     int counter = 0; 

    @Override 
    public void onCreate() 
    { 
     super.onCreate(); 
     intent = new Intent(BROADCAST_ACTION);  
    } 

    @Override 
    public void onStart(Intent intent, int startId) 
    {  
     locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 
     listener = new MyLocationListener();   
     locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 4000, 0, listener); 
     locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 4000, 0, listener); 
    } 

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

    protected boolean isBetterLocation(Location location, Location currentBestLocation) { 
     if (currentBestLocation == null) { 
      // A new location is always better than no location 
      return true; 
     } 

     // Check whether the new location fix is newer or older 
     long timeDelta = location.getTime() - currentBestLocation.getTime(); 
     boolean isSignificantlyNewer = timeDelta > TWO_MINUTES; 
     boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES; 
     boolean isNewer = timeDelta > 0; 

     // If it's been more than two minutes since the current location, use the new location 
     // because the user has likely moved 
     if (isSignificantlyNewer) { 
      return true; 
     // If the new location is more than two minutes older, it must be worse 
     } else if (isSignificantlyOlder) { 
      return false; 
     } 

     // Check whether the new location fix is more or less accurate 
     int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy()); 
     boolean isLessAccurate = accuracyDelta > 0; 
     boolean isMoreAccurate = accuracyDelta < 0; 
     boolean isSignificantlyLessAccurate = accuracyDelta > 200; 

     // Check if the old and new location are from the same provider 
     boolean isFromSameProvider = isSameProvider(location.getProvider(), 
       currentBestLocation.getProvider()); 

     // Determine location quality using a combination of timeliness and accuracy 
     if (isMoreAccurate) { 
      return true; 
     } else if (isNewer && !isLessAccurate) { 
      return true; 
     } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) { 
      return true; 
     } 
     return false; 
    } 



/** Checks whether two providers are the same */ 
    private boolean isSameProvider(String provider1, String provider2) { 
     if (provider1 == null) { 
      return provider2 == null; 
     } 
     return provider1.equals(provider2); 
    } 



@Override 
    public void onDestroy() {  
     // handler.removeCallbacks(sendUpdatesToUI);  
     super.onDestroy(); 
     Log.v("STOP_SERVICE", "DONE"); 
     locationManager.removeUpdates(listener);   
    } 

    public static Thread performOnBackgroundThread(final Runnable runnable) { 
     final Thread t = new Thread() { 
      @Override 
      public void run() { 
       try { 
        runnable.run(); 
       } finally { 

       } 
      } 
     }; 
     t.start(); 
     return t; 
    } 




public class MyLocationListener implements LocationListener 
    { 

     public void onLocationChanged(final Location loc) 
     { 
      Log.i("**************************************", "Location changed"); 
      if(isBetterLocation(loc, previousBestLocation)) { 
       loc.getLatitude(); 
       loc.getLongitude();    
       intent.putExtra("Latitude", loc.getLatitude()); 
       intent.putExtra("Longitude", loc.getLongitude());  
       intent.putExtra("Provider", loc.getProvider());     
       sendBroadcast(intent);   

      }        
     } 

     public void onProviderDisabled(String provider) 
     { 
      Toast.makeText(getApplicationContext(), "Gps Disabled", Toast.LENGTH_SHORT).show(); 
     } 


     public void onProviderEnabled(String provider) 
     { 
      Toast.makeText(getApplicationContext(), "Gps Enabled", Toast.LENGTH_SHORT).show(); 
     } 


     public void onStatusChanged(String provider, int status, Bundle extras) 
     { 

     } 

    } 
} 

添加此Service任何地方在你的項目,你想要的方式! :)

+0

完美的作品。 –

+4

請注意:該代碼看起來可能來自[GPL'd項目](https://code.google.com/p/chataround-dto/source/browse/chataround-client/src/com/service /chataround/listener/MyLocationListener.java?r=101)(或者,它可能來自[this](https://code.google.com/p/apk/source/browse/trunk/src/com/vouov/聽衆/ MyLocationListener.java?r = 5)麻省理工學院許可的項目。任何人都知道上述代碼的許可證狀態? – Inactivist

+0

@Nilanchala如果這對你有用比標記它正確,以便我可以幫助其他人有這樣的問題 –

11

我知道我發佈這個答案有點晚,但我覺得這是值得使用谷歌的保險絲位置提供商服務來獲取當前位置。

這個API的主要特點是:

1.Simple的API:讓你選擇你的準確度水平以及功耗。

2.立即可用:讓您的應用能夠立即訪問最佳的最近位置。

3.電源效率:它選擇最有效的方式用更少的功耗

獲得位置

4.Versatility:滿足廣泛的需求,從需要高度精確的應用前景位置到後臺使用,需要週期性的位置更新而忽略電力影響。

它在位置更新時也很靈活。 如果您只希望當前位置在您的應用程序啓動時使用,則可以使用getLastLocation(GoogleApiClient)方法。

如果您想更新您的位置不斷,那麼你可以使用requestLocationUpdates(GoogleApiClient,LocationRequest, LocationListener)

您可以找到有關保險絲的位置here和谷歌文檔保險絲的位置也是一個非常不錯的博客可以發現here

更新

據他們增加的背景位置的新限制的AndroidØ開始開發文檔。

如果您的應用程序在後臺運行,位置系統服務 每小時只計算一次您的應用的新位置。即使您的應用程序請求更頻繁的位置 更新,這種情況也是如此 。 但是,如果您的應用在前臺運行,與Android 7.1.1(API級別25)相比, 位置採樣率沒有變化。

+1

我認爲你是對的,但一些自定義Rom刪除谷歌播放服務,所以你不能使用保險絲位置提供商。 – Chen

+1

如果你只是想大致瞭解你在某個特定時間的位置或者不太準確的跟蹤,那麼'FusedLocationProvider'沒問題,但對於需要高精度跟蹤的應用程序來說,它只是不夠好 – StuStirling

+2

這些自定義Rom的解決方案是使用[失去](https://github.com/mapzen/LOST)從Mapzen。提供與Google的FusedLocationProviderAPI相同的功能,無需向Google Play服務註冊 –

1

非常容易,不需要創建類擴展LocationListener的 1-可變

private LocationManager mLocationManager; 
private LocationListener mLocationListener; 
private static double currentLat =0; 
private static double currentLon =0; 

2- onStartService()

@Override public void onStartService() { 
    addListenerLocation(); 
} 

3-方法addListenerLocation()

private void addListenerLocation() { 
    mLocationManager = (LocationManager) 
      getSystemService(Context.LOCATION_SERVICE); 
    mLocationListener = new LocationListener() { 
     @Override 
     public void onLocationChanged(Location location) { 
      currentLat = location.getLatitude(); 
      currentLon = location.getLongitude(); 

      Toast.makeText(getBaseContext(),currentLat+"-"+currentLon, Toast.LENGTH_SHORT).show(); 

     } 

     @Override 
     public void onStatusChanged(String provider, int status, Bundle extras) { 
     } 

     @Override 
     public void onProviderEnabled(String provider) { 
      Location lastKnownLocation = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); 
      if(lastKnownLocation!=null){ 
       currentLat = lastKnownLocation.getLatitude(); 
       currentLon = lastKnownLocation.getLongitude(); 
      } 

     } 

     @Override 
     public void onProviderDisabled(String provider) { 
     } 
    }; 
    mLocationManager.requestLocationUpdates(
      LocationManager.GPS_PROVIDER, 500, 10, mLocationListener); 
} 

4 onDestroy()

@Override 
public void onDestroy() { 
    super.onDestroy(); 
    mLocationManager.removeUpdates(mLocationListener); 
} 
4

後臺定位服務,即使在殺應用後我也會開始。

MainActivity.java

public class MainActivity extends AppCompatActivity { 
    AlarmManager alarmManager; 
    Button stop; 
    PendingIntent pendingIntent; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     if (alarmManager == null) { 
      alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); 
      Intent intent = new Intent(this, AlarmReceive.class); 
      pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); 
      alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 30000, 
        pendingIntent); 
     } 
    } 
} 

BookingTrackingService.java

public class BookingTrackingService extends Service implements LocationListener { 

    private static final String TAG = "BookingTrackingService"; 
    private Context context; 
    boolean isGPSEnable = false; 
    boolean isNetworkEnable = false; 
    double latitude, longitude; 
    LocationManager locationManager; 
    Location location; 
    private Handler mHandler = new Handler(); 
    private Timer mTimer = null; 
    long notify_interval = 30000; 

    public double track_lat = 0.0; 
    public double track_lng = 0.0; 
    public static String str_receiver = "servicetutorial.service.receiver"; 
    Intent intent; 

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

    @Override 
    public void onCreate() { 
     super.onCreate(); 

     mTimer = new Timer(); 
     mTimer.schedule(new TimerTaskToGetLocation(), 5, notify_interval); 
     intent = new Intent(str_receiver); 
    } 

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

     this.context = this; 


     return START_NOT_STICKY; 
    } 

    @Override 
    public void onDestroy() { 
     super.onDestroy(); 
     Log.e(TAG, "onDestroy <<"); 
     if (mTimer != null) { 
      mTimer.cancel(); 
     } 
    } 

    private void trackLocation() { 
     Log.e(TAG, "trackLocation"); 
     String TAG_TRACK_LOCATION = "trackLocation"; 
     Map<String, String> params = new HashMap<>(); 
     params.put("latitude", "" + track_lat); 
     params.put("longitude", "" + track_lng); 

     Log.e(TAG, "param_track_location >> " + params.toString()); 

     stopSelf(); 
     mTimer.cancel(); 

    } 

    @Override 
    public void onLocationChanged(Location location) { 

    } 

    @Override 
    public void onStatusChanged(String provider, int status, Bundle extras) { 

    } 

    @Override 
    public void onProviderEnabled(String provider) { 

    } 

    @Override 
    public void onProviderDisabled(String provider) { 

    } 

    /******************************/ 

    private void fn_getlocation() { 
     locationManager = (LocationManager) getApplicationContext().getSystemService(LOCATION_SERVICE); 
     isGPSEnable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); 
     isNetworkEnable = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); 

     if (!isGPSEnable && !isNetworkEnable) { 
      Log.e(TAG, "CAN'T GET LOCATION"); 
      stopSelf(); 
     } else { 
      if (isNetworkEnable) { 
       location = null; 
       locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 0, this); 
       if (locationManager != null) { 
        location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); 
        if (location != null) { 

         Log.e(TAG, "isNetworkEnable latitude" + location.getLatitude() + "\nlongitude" + location.getLongitude() + ""); 
         latitude = location.getLatitude(); 
         longitude = location.getLongitude(); 
         track_lat = latitude; 
         track_lng = longitude; 
//      fn_update(location); 
        } 
       } 
      } 

      if (isGPSEnable) { 
       location = null; 
       locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, this); 
       if (locationManager != null) { 
        location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); 
        if (location != null) { 
         Log.e(TAG, "isGPSEnable latitude" + location.getLatitude() + "\nlongitude" + location.getLongitude() + ""); 
         latitude = location.getLatitude(); 
         longitude = location.getLongitude(); 
         track_lat = latitude; 
         track_lng = longitude; 
//      fn_update(location); 
        } 
       } 
      } 

      Log.e(TAG, "START SERVICE"); 
      trackLocation(); 

     } 
    } 

    private class TimerTaskToGetLocation extends TimerTask { 
     @Override 
     public void run() { 

      mHandler.post(new Runnable() { 
       @Override 
       public void run() { 
        fn_getlocation(); 
       } 
      }); 

     } 
    } 

// private void fn_update(Location location) { 
// 
//  intent.putExtra("latutide", location.getLatitude() + ""); 
//  intent.putExtra("longitude", location.getLongitude() + ""); 
//  sendBroadcast(intent); 
// } 
} 

AlarmReceive.java(廣播接收器)

public class AlarmReceive extends BroadcastReceiver { 

    @Override 
    public void onReceive(Context context, Intent intent) { 
     Log.e("Service_call_" , "You are in AlarmReceive class."); 
     Intent background = new Intent(context, BookingTrackingService.class); 
//  Intent background = new Intent(context, GoogleService.class); 
     Log.e("AlarmReceive ","testing called broadcast called"); 
     context.startService(background); 
    } 
} 

AndroidManifest.xml中

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 

<service 
      android:name=".ServiceAndBroadcast.BookingTrackingService" 
      android:enabled="true" /> 

     <receiver 
      android:name=".ServiceAndBroadcast.AlarmReceive" 
      android:exported="false"> 
      <intent-filter> 
       <action android:name="android.intent.action.BOOT_COMPLETED" /> 
      </intent-filter> 
     </receiver> 
+0

'if(isNetworkEnable){'它可能是'if(!isNetworkEnable){'NOT NOT NOT else case。 ;) –

+1

另外,需要檢查權限的可用性。 if(ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)!= PackageManager.PERMISSION_GRANTED){return;}' –