2013-01-23 62 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;}' –