【问题标题】:Understanding how Service, LocationListener and BroadcastReceiver work to get location in background了解 Service、LocationListener 和 BroadcastReceiver 如何在后台获取位置
【发布时间】: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吗?

【问题讨论】:

    标签: android broadcastreceiver google-play-services android-location locationlistener


    【解决方案1】:

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

    1. http://www.androidhive.info/2012/07/android-gps-location-manager-tutorial/
    2. onLocationChanged(位置位置)
    3. 不,转到 1
    4. 是的,再次,转到 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 对象。
    • 现在我做了一个例子。可能有错别字,但应该能很好地展示主要思想。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-02
    • 2015-07-24
    • 1970-01-01
    相关资源
    最近更新 更多