title: Store Android user location in Firebase database and display it on map using Geofire
body: <p>I have created an Android app that has a user login and registration linked to my Firebase database.</p>
  
  <p>I am trying to use Geofire to store and display the users that are logged in on a map, I have used the SF vehicle example and if I'm honest I don't understand it that much. I have used the exact same code to test and see if it worked and I get the error in the image provided.<a href="https://i.stack.imgur.com/2xiPJ.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/2xiPJ.jpg" alt="Error on device when I open the app"></a></p>
  
  <p>I am looking for help with writing a function to detect the logged in user's location and display it on the map in real-time, updating as the user moves, I am stuck on this weeks now and have tried all there is out there (which is not a lot).</p>
  
  <p>Some help would be greatly appreciated, any further information needed just ask.  </p>
  
  <p>This is the code from the SF Vehicle example that I am using, the original is connected to the San Fransisco bus department and displaying them, so i need the code to write the location to my database and display them in the same way. </p>
  
  <pre><code>package nixer.nixer;
  
  import android.app.AlertDialog;
  import android.app.Fragment;
  import android.content.Intent;
  import android.graphics.Color;
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.SystemClock;
  import android.support.v4.app.FragmentActivity;
  import android.support.v7.app.AppCompatActivity;
  import android.support.v7.widget.Toolbar;
  import android.view.Menu;
  import android.view.MenuItem;
  import android.view.animation.AccelerateDecelerateInterpolator;
  import android.view.animation.Interpolator;
  import com.firebase.client.Firebase;
  import com.firebase.client.FirebaseError;
  import com.firebase.geofire.GeoFire;
  import com.firebase.geofire.GeoLocation;
  import com.firebase.geofire.GeoQuery;
  import com.firebase.geofire.GeoQueryEventListener;
  import com.firebase.geofire.LocationCallback;
  import com.google.android.gms.maps.CameraUpdateFactory;
  import com.google.android.gms.maps.GoogleMap;
  import com.google.android.gms.maps.SupportMapFragment;
  import com.google.android.gms.maps.model.*;
  import java.util.HashMap;
  import java.util.Map;
  
  
  public class MapActivity extends AppCompatActivity implements   GeoQueryEventListener, GoogleMap.OnCameraChangeListener {
  
  private Firebase mRef;
  private String mUserId;
  private String itemsUrl;
  private static final GeoLocation INITIAL_CENTER = new GeoLocation(53.349805,  -6.260309 );
  private static final int INITIAL_ZOOM_LEVEL = 14;
  private static final String GEO_FIRE_REF = "https://nixer.firebaseio.com/";
  private GoogleMap map;
  private Circle searchCircle;
  private GeoFire geoFire;
  private GeoQuery geoQuery;
  
  private Map&lt;String,Marker&gt; markers;
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_map);
      Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
      setSupportActionBar(toolbar);
  
      // setup map and camera position
      SupportMapFragment mapFragment =  (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
      this.map = mapFragment.getMap();
      LatLng latLngCenter = new LatLng(INITIAL_CENTER.latitude,  INITIAL_CENTER.longitude);
      this.searchCircle = this.map.addCircle(new CircleOptions().center(latLngCenter).radius(1000));
      this.searchCircle.setFillColor(Color.argb(66, 255, 0, 255));
      this.searchCircle.setStrokeColor(Color.argb(66, 0, 0, 0));
       this.map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLngCenter,   INITIAL_ZOOM_LEVEL));
      this.map.setOnCameraChangeListener(this);
  
      Firebase.setAndroidContext(this);
  
      // setup GeoFire
      this.geoFire = new GeoFire(new Firebase(GEO_FIRE_REF));
      // radius in km
      this.geoQuery = this.geoFire.queryAtLocation(INITIAL_CENTER, 1);
  
      // setup markers
      this.markers = new HashMap&lt;String, Marker&gt;();       
  
  
  
  
      // Check Authentication
      mRef = new Firebase(Constants.FIREBASE_URL);
      if (mRef.getAuth() == null) {
          loadLoginView();
      }
  
  
      try {
          mUserId = mRef.getAuth().getUid();
      } catch (Exception e) {
          loadLoginView();
      }
  
  }
  
  
  
  
  @Override
  protected void onStop() {
      super.onStop();
      // remove all event listeners to stop updating in the background
      this.geoQuery.removeAllListeners();
      for (Marker marker: this.markers.values()) {
          marker.remove();
      }
      this.markers.clear();
  }
  
  @Override
  protected void onStart() {
      super.onStart();
      // add an event listener to start updating locations again
      this.geoQuery.addGeoQueryEventListener(this);
  }
  
  @Override
  public void onKeyEntered(String key, GeoLocation location) {
      // Add a new marker to the map
      Marker marker = this.map.addMarker(new MarkerOptions().position(new   LatLng(location.latitude, location.longitude)));
      this.markers.put(key, marker);
  }
  
  @Override
  public void onKeyExited(String key) {
      // Remove any old marker
      Marker marker = this.markers.get(key);
      if (marker != null) {
          marker.remove();
          this.markers.remove(key);
      }
  }
  
  @Override
  public void onKeyMoved(String key, GeoLocation location) {
      // Move the marker
      Marker marker = this.markers.get(key);
      if (marker != null) {
          this.animateMarkerTo(marker, location.latitude, location.longitude);
      }
  }
  
  @Override
  public void onGeoQueryReady() {
  }
  
  @Override
  public void onGeoQueryError(FirebaseError error) {
      new AlertDialog.Builder(this)
              .setTitle("Error")
              .setMessage("There was an unexpected error querying GeoFire: " + error.getMessage())
              .setPositiveButton(android.R.string.ok, null)
              .setIcon(android.R.drawable.ic_dialog_alert)
              .show();
  }
  
  // Animation handler for old APIs without animation support
  private void animateMarkerTo(final Marker marker, final double lat, final double lng) {
      final Handler handler = new Handler();
      final long start = SystemClock.uptimeMillis();
      final long DURATION_MS = 3000;
      final Interpolator interpolator = new AccelerateDecelerateInterpolator();
      final LatLng startPosition = marker.getPosition();
      handler.post(new Runnable() {
          @Override
          public void run() {
              float elapsed = SystemClock.uptimeMillis() - start;
              float t = elapsed/DURATION_MS;
              float v = interpolator.getInterpolation(t);
  
              double currentLat = (lat - startPosition.latitude) * v +   startPosition.latitude;
              double currentLng = (lng - startPosition.longitude) * v +   startPosition.longitude;
              marker.setPosition(new LatLng(currentLat, currentLng));
  
              // if animation is not finished yet, repeat
              if (t &lt; 1) {
                  handler.postDelayed(this, 16);
              }
          }
      });
  }
  
  private double zoomLevelToRadius(double zoomLevel) {
      // Approximation to fit circle into view
      return 16384000/Math.pow(2, zoomLevel);
  }
  
  @Override
  public void onCameraChange(CameraPosition cameraPosition) {
      // Update the search criteria for this geoQuery and the circle on the map
      LatLng center = cameraPosition.target;
      double radius = zoomLevelToRadius(cameraPosition.zoom);
      this.searchCircle.setCenter(center);
      this.searchCircle.setRadius(radius);
      this.geoQuery.setCenter(new GeoLocation(center.latitude,  center.longitude));
      // radius in km
      this.geoQuery.setRadius(radius/1000);
  }
  </code></pre>
  
  <p>Update:</p>
  
  <p>Firebase rules :</p>
  
  <pre><code>{
  "rules": {
    "users": {
      "$uid": {
        ".read": "auth != null &amp;&amp; auth.uid == $uid",
        ".write": "auth != null &amp;&amp; auth.uid == $uid",
        "items": {
          "$item_id": {
            "title": {
              ".validate": "newData.isString() &amp;&amp; newData.val().length &gt; 0"
              }
          }
        }
      }
    }
  
    }
  }
  </code></pre>