了解 Service、LocationListener 和 BroadcastReceiver 如何在后台获取位置

Posted

技术标签:

【中文标题】了解 Service、LocationListener 和 BroadcastReceiver 如何在后台获取位置【英文标题】:Understanding how Service, LocationListener and BroadcastReceiver work to get location in background 【发布时间】:2013-10-02 20:27:42 【问题描述】:

我是android 的新手,我正在开发一个跟踪用户距离的应用程序。它只会在用户点击按钮时开始跟踪,并在他们再次点击时停止。似乎有大量关于如何做到这一点的混淆信息和方法,所以我至少对最佳实践有一个大致的了解。

public class BackgroundLocationService extends Service implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, LocationListener 

    IBinder mBinder = new LocalBinder();

    private LocationClient mLocationClient;
    private LocationRequest mLocationRequest;
    private boolean mInProgress;

    //Milliseconds per second
  private static final int MILLISECONDS_PER_SECOND = 1000;
  // Update frequency in seconds
  private static final int UPDATE_INTERVAL_IN_SECONDS = 30;
  // Update frequency in milliseconds
  public static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS;
  // The fastest update frequency, in seconds
  private static final int FASTEST_INTERVAL_IN_SECONDS = 30;
  // A fast frequency ceiling in milliseconds
  public static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;
  private static final int TWO_MINUTES = 1000 * 60 * 2;

  public Location previousBestLocation = null;

  private Boolean servicesAvailable = false;

  public class LocalBinder extends Binder 
    public BackgroundLocationService getServerInstance() 
        return BackgroundLocationService.this;
    
  

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

      mInProgress = false;
      mLocationRequest = LocationRequest.create();
      mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
      mLocationRequest.setInterval(UPDATE_INTERVAL);
      mLocationRequest.setFastestInterval(FASTEST_INTERVAL);

      // Check that Google Play Services are connected
      servicesAvailable = servicesConnected();

      // Create the client
      mLocationClient = new LocationClient(this, this, this);

  //end

  private boolean servicesConnected() 

      // Check that Google Play services is available
      int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);

      // If Google Play services is available
      if (ConnectionResult.SUCCESS == resultCode) 
          return true;
       else 
          return false;
      

  //end

  public int onStartCommand (Intent intent, int flags, int startId) 

      super.onStartCommand(intent, flags, startId);

      if(!servicesAvailable || mLocationClient.isConnected() || mInProgress)
        return START_STICKY;

      setUpLocationClientIfNeeded();
      if(!mLocationClient.isConnected() || !mLocationClient.isConnecting() && !mInProgress) 
            mInProgress = true;
            mLocationClient.connect();
      

      return START_STICKY;
  //end


  private void setUpLocationClientIfNeeded() 
    if (mLocationClient == null) 
          mLocationClient = new LocationClient(this, this, this);
  


  @Override
  public void onLocationChanged(Location location) 

      String msg = Double.toString(location.getLatitude()) + "," +Double.toString(location.getLongitude());
      Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();

  //end

  @Override
  public IBinder onBind(Intent intent) 
    return mBinder;
  

  public String getTime() 
    SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return mDateFormat.format(new Date());
  


  @Override
  public void onDestroy()
      // Turn off the request flag
      mInProgress = false;
      if(servicesAvailable && mLocationClient != null) 
            mLocationClient.removeLocationUpdates(this);
            // Destroy the current location client
            mLocationClient = null;
      
      // Display the connection status
      Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
      super.onDestroy();  
  

  /*
   * Called by Location Services when the request to connect the
   * client finishes successfully. At this point, you can
   * request the current location or start periodic updates
   */
  @Override
  public void onConnected(Bundle bundle) 

      // Request location updates using static settings
      mLocationClient.requestLocationUpdates(mLocationRequest, this);

  

  /*
   * Called by Location Services if the connection to the
   * location client drops because of an error.
   */
  @Override
  public void onDisconnected() 
      // Turn off the request flag
      mInProgress = false;
      // Destroy the current location client
      mLocationClient = null;
      // Display the connection status
      Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();

  

  /*
   * Called by Location Services if the attempt to
   * Location Services fails.
   */
  @Override
  public void onConnectionFailed(ConnectionResult connectionResult) 
    mInProgress = false;

      /*
       * Google Play services can resolve some errors it detects.
       * If the error has a resolution, try sending an Intent to
       * start a Google Play services activity that can resolve
       * error.
       */
      if (connectionResult.hasResolution()) 

      // If no resolution is available, display an error dialog
       else 

      
  


那么我的问题:

从我的主要Activity 我如何启动我的服务?我该如何阻止它? 我的Activity 班级如何知道我的Service 何时收到Location 更新,以便我可以更新 UI? 我还需要BroadcastReceiver吗? 有什么需要进入我的Manifest吗?

【问题讨论】:

【参考方案1】:

让我们按顺序回答您的问题:

    http://www.androidhive.info/2012/07/android-gps-location-manager-tutorial/ onLocationChanged(位置位置) 不,转到 1 是的,再次,转到 1

编辑:向 MainActivity 报告

在你的 MainActivity 中添加一个这样的界面:

public class MainActivity implements NewLocationsListener 

    public interface NewLocationsListener 

        public void onNewLocation(Location location);
    

    private GPSTracker gps;

    ...

    // when your button is clicked or where ever you want to start gps
    gps = new GPSTracker(this, this);

    ...

    // and get Locations in onNewLocation
    public void onNewLocation(Location location) 
        // location reported back from gps 
    

    // if you want gps to stop after exiting your app
    @Override
    protected void onPause() 
        if (gps != null) 
            gps.stopUsingGPS();
        
        super.onPause();
    


并添加到 GPSTracker:

private NewLocationsListener mListener;

public GPSTracker(Context context, NewLocationsListener listener) 
    this.mContext = context;
    this.mListener = listener;
    getLocation();



@Override
public void onLocationChanged(Location location) 
    // report back to MainActivity
    mListener.onNewLocation(location);
    canGetLocation = true;

Edit2:如何处理退出重新进入和方向更改的示例:

正如您所说,由于您是 Android 新手,所以我想我不妨添加这个。

public class StrategyActivity extends Activity 

    public static final String TAG = "StrategyActivity";

    protected GPSTracker gps;

    private Button startButton;
    private boolean isStarted = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);

        startButton = (Button) findViewById(R.id.start_button);

        if (savedInstanceState != null) 
            isStarted = savedInstanceState.getBoolean("isStarted");
        
    


    @Override
    protected void onResume() 
        if (isStarted) 
            startStrategy();
        
        updateOnOffButton();
        super.onResume();
    

    @Override
    protected void onSaveInstanceState(Bundle outState) 
        outState.putBoolean("isStarted", isStarted);
        super.onSaveInstanceState(outState);
    

    @Override
    public void onBackPressed() 
        if (isStarted) 
            stopStrategy();
        
        super.onBackPressed();
    

    @Override
    protected void onPause() 
        if (isStarted) 
            killStrategy();
        
        super.onPause();
    

    @Override
    protected void onDestroy() 
        killStrategy();
        super.onDestroy();
    

    public void startStopClicked(View view) 
        if (isStarted) 
            stopStrategy();
         else 
            startStrategy();
        
    

    private void updateOnOffButton() 
        if (isStarted) 
            startButton.setText("Stop");
         else 
            startButton.setText("Start");
        
    


    protected void killStrategy() 
        if (gps != null) 
            gps.stopUsingGPS();
        
    

    protected void startStrategy() 
        isStarted = true;
        gps = new GPSTracker(this);
        updateOnOffButton();
        Toast.makeText(this, "Started", Toast.LENGTH_LONG).show();
    

    protected void stopStrategy() 
        isStarted = false;
        killStrategy();
        updateOnOffButton();
        Toast.makeText(this, "Stopped", Toast.LENGTH_LONG).show();
    

【讨论】:

好吧,即使我离开应用程序,它也能正常工作并为我提供位置更新。在我的Activity 中,我使用startService(new Intent(this, BackgroundLocationService.class)); 开始了我的服务。仍然不清楚我的Service 如何与我的主要Activity 交谈,以便在我每次获得位置更新时让它知道。 实际上我现在可以使用LocalBroadcastManager。我可以发送一个字符串。但我现在正在努力解决如何发送Location 对象。 现在我做了一个例子。可能有错别字,但应该能很好地展示主要思想。

以上是关于了解 Service、LocationListener 和 BroadcastReceiver 如何在后台获取位置的主要内容,如果未能解决你的问题,请参考以下文章

service mesh初了解

了解 Linkerd Service Mesh 架构

了解 Service、LocationListener 和 BroadcastReceiver 如何在后台获取位置

了解 Web Service

#云原生征文#深入了解Kubernetes(k8s)Service

了解spring-integration service-activator