GithubHelp home page GithubHelp logo

geofire-java's Introduction

GeoFire for Java โ€” Realtime location queries with Firebase

Build Status

Note This library is only for server side Java development. If you want to use GeoFire in your Android application, see geofire-android.

GeoFire is an open-source library for Java that allows you to store and query a set of keys based on their geographic location.

At its heart, GeoFire simply stores locations with string keys. Its main benefit however, is the possibility of querying keys within a given geographic area - all in realtime.

GeoFire uses the Firebase Realtime Database database for data storage, allowing query results to be updated in realtime as they change. GeoFire selectively loads only the data near certain locations, keeping your applications light and responsive, even with extremely large datasets.

GeoFire clients are also available for other languages:

Integrating GeoFire with your data

GeoFire is designed as a lightweight add-on to the Firebase Realtime Database. However, to keep things simple, GeoFire stores data in its own format and its own location within your Firebase database. This allows your existing data format and security rules to remain unchanged and for you to add GeoFire as an easy solution for geo queries without modifying your existing data.

Example Usage

Assume you are building an app to rate bars and you store all information for a bar, e.g. name, business hours and price range, at /bars/<bar-id>. Later, you want to add the possibility for users to search for bars in their vicinity. This is where GeoFire comes in. You can store the location for each bar using GeoFire, using the bar IDs as GeoFire keys. GeoFire then allows you to easily query which bar IDs (the keys) are nearby. To display any additional information about the bars, you can load the information for each bar returned by the query at /bars/<bar-id>.

Upgrading GeoFire

Upgrading from GeoFire 1.x to 2.x

GeoFire 2.x is based on the new 3.x release of Firebase.

Upgrading from GeoFire 1.0.x to 1.1.x

With the release of GeoFire for Android/Java 1.1.0, this library now uses the new query functionality found in Firebase 2.0.0. As a result, you will need to upgrade to Firebase 2.x.x and add a new .indexOn rule to your Security and Firebase Rules to get the best performance. You can view the updated rules here and read our docs for more information about indexing your data.

Including GeoFire in your Java project

In order to use GeoFire in your project, you need to add the Firebase Admin SDK. After that you can include GeoFire with one of the choices below.

Gradle

Add a dependency for GeoFire to your build.gradle file:

dependencies {
    implementation 'com.firebase:geofire-java:3.0.0'
}

Maven

Add a dependency for GeoFire to your pom.xml file:

<dependency>
  <groupId>com.firebase</groupId>
  <artifactId>geofire-java</artifactId>
  <version>3.0.0</version>
</dependency>

Usage

GeoFire

A GeoFire object is used to read and write geo location data to your Firebase database and to create queries. To create a new GeoFire instance you need to attach it to a Firebase database reference.

DatabaseReference ref = FirebaseDatabase.getInstance().getReference("path/to/geofire");
GeoFire geoFire = new GeoFire(ref);

Note that you can point your reference to anywhere in your Firebase database, but don't forget to setup security rules for GeoFire.

Setting location data

In GeoFire you can set and query locations by string keys. To set a location for a key simply call the setLocation method. The method is passed a key as a string and the location as a GeoLocation object containing the location's latitude and longitude:

geoFire.setLocation("firebase-hq", new GeoLocation(37.7853889, -122.4056973));

To check if a write was successfully saved on the server, you can add a GeoFire.CompletionListener to the setLocation call:

geoFire.setLocation("firebase-hq", new GeoLocation(37.7853889, -122.4056973), new GeoFire.CompletionListener() {
    @Override
    public void onComplete(String key, FirebaseError error) {
        if (error != null) {
            System.err.println("There was an error saving the location to GeoFire: " + error);
        } else {
            System.out.println("Location saved on server successfully!");
        }
    }
});

To remove a location and delete it from the database simply pass the location's key to removeLocation:

geoFire.removeLocation("firebase-hq");

Retrieving a location

Retrieving a location for a single key in GeoFire happens with callbacks:

geoFire.getLocation("firebase-hq", new LocationCallback() {
    @Override
    public void onLocationResult(String key, GeoLocation location) {
        if (location != null) {
            System.out.println(String.format("The location for key %s is [%f,%f]", key, location.latitude, location.longitude));
        } else {
            System.out.println(String.format("There is no location for key %s in GeoFire", key));
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        System.err.println("There was an error getting the GeoFire location: " + databaseError);
    }
});

Geo Queries

GeoFire allows you to query all keys within a geographic area using GeoQuery objects. As the locations for keys change, the query is updated in realtime and fires events letting you know if any relevant keys have moved. GeoQuery parameters can be updated later to change the size and center of the queried area.

// creates a new query around [37.7832, -122.4056] with a radius of 0.6 kilometers
GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(37.7832, -122.4056), 0.6);

Receiving events for geo queries

Key Events

There are five kinds of "key" events that can occur with a geo query:

  1. Key Entered: The location of a key now matches the query criteria.
  2. Key Exited: The location of a key no longer matches the query criteria.
  3. Key Moved: The location of a key changed but the location still matches the query criteria.
  4. Query Ready: All current data has been loaded from the server and all initial events have been fired.
  5. Query Error: There was an error while performing this query, e.g. a violation of security rules.

Key entered events will be fired for all keys initially matching the query as well as any time afterwards that a key enters the query. Key moved and key exited events are guaranteed to be preceded by a key entered event.

Sometimes you want to know when the data for all the initial keys has been loaded from the server and the corresponding events for those keys have been fired. For example, you may want to hide a loading animation after your data has fully loaded. This is what the "ready" event is used for.

Note that locations might change while initially loading the data and key moved and key exited events might therefore still occur before the ready event is fired.

When the query criteria is updated, the existing locations are re-queried and the ready event is fired again once all events for the updated query have been fired. This includes key exited events for keys that no longer match the query.

To listen for events you must add a GeoQueryEventListener to the GeoQuery:

geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
    @Override
    public void onKeyEntered(String key, GeoLocation location) {
        System.out.println(String.format("Key %s entered the search area at [%f,%f]", key, location.latitude, location.longitude));
    }

    @Override
    public void onKeyExited(String key) {
        System.out.println(String.format("Key %s is no longer in the search area", key));
    }

    @Override
    public void onKeyMoved(String key, GeoLocation location) {
        System.out.println(String.format("Key %s moved within the search area to [%f,%f]", key, location.latitude, location.longitude));
    }

    @Override
    public void onGeoQueryReady() {
        System.out.println("All initial data has been loaded and events have been fired!");
    }

    @Override
    public void onGeoQueryError(DatabaseError error) {
        System.err.println("There was an error with this query: " + error);
    }
});

You can call either removeGeoQueryEventListener to remove a single event listener or removeAllListeners to remove all event listeners for a GeoQuery.

Data Events

If you are storing model data and geo data in the same database location, you may want access to the DataSnapshot as part of geo events. In this case, use a GeoQueryDataEventListener rather than a key listener.

These "data event" listeners have all of the same events as the key listeners with one additional event type:

  1. Data Changed: the underlying DataSnapshot has changed. Every "data moved" event is followed by a data changed event but you can also get change events without a move if the data changed does not affect the location.

Adding a data event listener is similar to adding a key event listener:

geoQuery.addGeoQueryDataEventListener(new GeoQueryDataEventListener() {

  @Override
  public void onDataEntered(DataSnapshot dataSnapshot, GeoLocation location) {
    // ...
  }

  @Override
  public void onDataExited(DataSnapshot dataSnapshot) {
    // ...
  }

  @Override
  public void onDataMoved(DataSnapshot dataSnapshot, GeoLocation location) {
    // ...
  }

  @Override
  public void onDataChanged(DataSnapshot dataSnapshot, GeoLocation location) {
    // ...
  }

  @Override
  public void onGeoQueryReady() {
    // ...
  }

  @Override
  public void onGeoQueryError(DatabaseError error) {
    // ...
  }

});

Updating the query criteria

The GeoQuery search area can be changed with setCenter and setRadius. Key exited and key entered events will be fired for keys moving in and out of the old and new search area, respectively. No key moved events will be fired; however, key moved events might occur independently.

Updating the search area can be helpful in cases such as when you need to update the query to the new visible map area after a user scrolls.

Deployment

  • In your local environment set $BINTRAY_USER and $BINTRAY_KEY to your Bintray.com username and API key.
  • Checkout and update the master branch.
  • Run ./release.sh to build and deploy.
  • On bintray.com, publish the draft artifacts.

geofire-java's People

Contributors

abeisgoat avatar adauvalter avatar choxmi avatar fatheroflegends avatar firebase-ops avatar jackie-d avatar jdimond avatar jgarcia162 avatar jonahbron avatar joreilly avatar m-tse avatar mikelehen avatar mimming avatar oalami avatar samtstern avatar startupandrew avatar vanniktech avatar vivekvinodh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

geofire-java's Issues

How to use this library with the new Firebase api?

i wanted to ask how are we suppose to use this library with the new Firebase api.
I tried using this library but while initializing GeoFire object it asks for a Firebase object which is not there in the new api.

Ionic 2 Integration

I cant seem to integrate this into an Ionic 2 app using webpack. is there any resources available for using it within Ionic ?

Add method to update GeoQuery center and radius together atomically

I have been calling GeoQuery setCenter() and setRadius() as user zooms in/out in google maps (in android app) and noticed that that seems to be kicking off parallel sets of firebase queries (they both call setupQueries()). Should there be single method to set both of these (similar to geoFire.queryAtLocation(() method when initially creating the GeoQuery object)?

Query for recently added locations first

Is there anyway I can get the recently added locations first rather than old - new locations. In my case I have thousands of entries so every time I query I have to go through all callbacks and then compare and find out recently added 10 locations out of that, its a huge burden on performance, is there any way this can be done? Is it possible to store time with location object in geofire node.

Max radius for queryAtLocation()

Through trial and error I've found that the max radius for which query results are returned is about 8587km. For bigger radiuses, onKeyEntered() is never called. Is that a bug? If not, how would I go about querying locations that are further apart? I'm using GeoFire 2.1.1 on Android.

    @Test
    public void queryAtLocation() throws InterruptedException {
        double radius = 8589; // Fails
//        double radius = 8587.8; //Passes
        CountDownLatch latch = new CountDownLatch(1);
        final boolean[] entered = {false};
        geoFire.queryAtLocation(new GeoLocation(0, 0), radius)
                .addGeoQueryEventListener(new GeoQueryEventListener() {
                    @Override
                    public void onKeyEntered(String key, GeoLocation location) {
                        entered[0] = true;
                    }

                    @Override
                    public void onKeyExited(String key) {
                    }

                    @Override
                    public void onKeyMoved(String key, GeoLocation location) {
                    }

                    @Override
                    public void onGeoQueryReady() {
                        latch.countDown();
                    }

                    @Override
                    public void onGeoQueryError(DatabaseError error) {
                    }
                });
        latch.await();
        Assert.assertTrue(entered[0]);
    }

GeoFire.setCenter() not firing GeoQueryEventListener when set

I expect the following code to fire the attached listener:

mapQuery.addGeoQueryEventListener(newMapQueryListener);
...
mMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
        @Override
        public void onCameraChange(CameraPosition position) {
            LatLngBounds bounds = mMap.getProjection().getVisibleRegion().latLngBounds;
            queryLocation = new GeoLocation(bounds.getCenter().latitude,bounds.getCenter().longitude);
            Log.i(TAG, "Map Camera Changed: " + queryLocation.latitude + ", " + queryLocation.longitude);
            mapQuery.setCenter(queryLocation);
            mapQuery.setRadius(defaultRadius);
            mClusterManager.onCameraChange(position);
        }
    });

but it never fires the listener..

Am I doing something wrong here ?

onKeyEntered never called

im my code I expect to get posts from my firebase database, but the onKeyEntered never called, to check if there is a problem in my code I wrote some toasts to check that, but I found that the onQueryReady is called as expected but the problem is in onKeyEntered, I even made the location static on a specific post's location, actually there are lots of posts with this location, but it still the same and the

` @nullable
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    posts = new ArrayList<>();

    //initialization work of the recycler view
    View rootView = inflater.inflate(R.layout.posts_fragment, container, false);

    //initialization work of the firebase database
    firebaseInitializationWork();

    return recyclerViewInitializationWork(rootView);
}

@Override
public void onStart() {
    super.onStart();
    geoQueryToSearchPosts.addGeoQueryEventListener(geoQueryEventListener);
}

@Override
public void onStop() {
    super.onStop();
    geoQueryToSearchPosts.removeAllListeners();
}

private void firebaseInitializationWork() {
    if (posts == null)
        posts = new ArrayList<>();
    //setting up the reference and the geoquery objects
    postsReference = FirebaseDatabase.getInstance().getReference().child("posts");
    geofireToSearchPosts = new GeoFire(postsReference);

    //set the query on the current location and around the user with 1 kilo meter.
    updateLocation();
    geoQueryToSearchPosts = geofireToSearchPosts.queryAtLocation(
            /*getLastKnownLocation()*/new GeoLocation(29.9061584,31.2710861), 1);

    //creating the listener and adding it to the geoQueryToSearchPosts.
    attachTheGeoQueryListener();

}

private GeoLocation getLastKnownLocation() {
    GeoLocation geoLocation = null;
    /*if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

    }*/
    Location location = locationManager.getLastKnownLocation("gps");
    geoLocation = new GeoLocation(location.getLatitude() , location.getLongitude());
    return geoLocation;
}

//function to initialize the geofire query listener
//and attach it to the geofire query object (geoQueryToSearchPosts)
private void attachTheGeoQueryListener() {
    if (geoQueryEventListener == null) {
        geoQueryEventListener = new GeoQueryEventListener() {
            @Override
            public void onKeyEntered(String key, GeoLocation location) {
                Toast.makeText(getActivity() , "onKeyEntered" , Toast.LENGTH_LONG).show();
                //retrieving the post by listening on the post node.
                postsReference.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        //adding the post to the array.
                        posts.add(0, (PostDataClass) dataSnapshot.getValue());

                        // notifying the adapter that there is
                        //an element inserted.
                        mAdapter.notifyItemInserted(0);
                        //scroll to the beginning of the list
                        mRecyclerView.smoothScrollToPosition(0);
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {

                    }
                });
            }

            @Override
            public void onKeyExited(String key) {
                postsReference.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        //deleting the post from the posts array and notify the adapter that
                        //the post the postion has been deleted.
                        PostDataClass post = (PostDataClass) dataSnapshot.getValue();
                        int postPosition = posts.indexOf(post);
                        posts.remove(post);
                        mAdapter.notifyItemRemoved(postPosition);
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {

                    }
                });
            }

            @Override
            public void onKeyMoved(String key, GeoLocation location) {

            }

            @Override
            public void onGeoQueryReady() {
                Toast.makeText(getActivity() , "onGeoQueryReady" , Toast.LENGTH_LONG).show();
            }

            @Override
            public void onGeoQueryError(DatabaseError error) {
                Toast.makeText(getActivity() , "onGeoQueryError" , Toast.LENGTH_LONG).show();
            }
        };
        //geoQueryToSearchPosts.addGeoQueryEventListener(geoQueryEventListener);
    }
}

}`

LocationChangedListener

Hi, thanks for this great library!

I would like to add the following method to GeoFire:

public void listenLocation(String key, LocationCallback callback) {
        DatabaseReference keyRef = this.getDatabaseRefForKey(key);
        LocationValueEventListener valueListener = new LocationValueEventListener(callback);
        keyRef.addValueEventListener(valueListener);
    }

its a tiny difference to GeoFire#getLocation(String key, LocationCallback callback);

I tried to extend GeoFire and add the new method.
Unfortunately getDatabaseRefForKey() is package private and databaseReference is private. Also, LocationValueEventListener is not visible.

Maybe you could add the classical listener method or change some visibilities.
Many thanks!

Math error in GeoHashQuery.java cause code to give unexpected exception

Hello, I'm new to submitting issues to GitHub, but this has to be fixed I think.

I was getting mad on trying to figure out why my app was giving me an Exception when I was setting the GeoQuery radius to a big number (>500'000), so I started debugging the code and found what it seems to me to be a math error.

The Exception that I get is :
java.lang.IllegalArgumentException: Precision of GeoHash must be larger than zero! at com.firebase.geofire.core.GeoHash.<init>(GeoHash.java:29)

The code I try to execute is:
someGeoQuery.setRadius(500000);
The lines that I think are wrong are: ( in file com.firebase.geofire.core.GeoHashQuery.java)

        int queryBits = Math.max(1, Utils.bitsForBoundingBox(location, radius));
        int geoHashPrecision = (int)(Math.ceil(queryBits/Base32Utils.BITS_PER_BASE32_CHAR));

In fact, queryBits and Base32Utils.BITS_PER_BASE32_CHAR , are both integer, so a division of that kind can only bring to an integer result, so why the need of the ceil?
I think this is an error, and it cause a consequentially wanted Exception.

The code has to be corrected to :

        **float** queryBits = Math.max(1, Utils.bitsForBoundingBox(location, radius));
        int geoHashPrecision = (int)(Math.ceil(queryBits/Base32Utils.BITS_PER_BASE32_CHAR));

The version that I'm using is:
'com.firebase:geofire-android:2.1.0'

Am I right?

Displaying GeoQueries in a ListView.

I have posted a question on displaying GeoQueries in a ListView. I have implemented a custom FirebaseListAdapter. Why isn't there any Android Example for GeoQueries in a ListView. I am new to Firebase I was using Parse before but now they have shutdown. My applicaton's domain is Geo Location base so please provide us with a GeoFire ListView example and help me solve the issue where I might be wrong. Here is my question on StackOverFlow.

New way to integrate geofire with existing data

With the late September update of firebase, it's now possible to order by descendants, which from what I see in the code was the reason you couldn't have geo data inside your existing data (couldn't order by the geohash).

It will completely change how GeoFire works so it should probably be 3.0, and i'm guessing the change will have to be on all 3 platforms too.

I'm just putting it out there to see if anyone's working on it.

Add geofire to existing data

Hi
I have a firebase of 10k records with lat and lng. I now want to use geofire and need to get the lat and lng to geofire 'format' (g,i(0,1).
But I have no clue on how to do that!

onKeyEntered() method not getting call even data available

When I pass longitude as positive value then it not calling onKeyEntered() method.
It directly call onGeoQueryReady() method even data available in radius.
When I pass longitude as negative value then it is calling onKeyEntered() method.

My code is as below,

private DatabaseReference firebaseRef = FirebaseDatabase.getInstance().getReferenceFromUrl("my_database_url");

private GeoFire geoFire = new GeoFire(firebaseRef.child("geofire"));

GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(23.022505, 72.5713621), 1000);

        geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
                @Override
                public void onKeyEntered(String key, GeoLocation location) {
                    Log.i(TAG, "onKeyEntered Key = " + key);
                    System.out.println(String.format("Key %s entered the search area at [%f,%f]", key, location.latitude, location.longitude));
                }
                @Override
                public void onKeyExited(String key) {
                    Log.i(TAG, "onKeyExited Key = " + key);
                    System.out.println(String.format("Key %s is no longer in the search area", key));
                }
                @Override
                public void onKeyMoved(String key, GeoLocation location) {
                    Log.i(TAG, "onKeyMoved Key = " + key);
                    System.out.println(String.format("Key %s moved within the search area to [%f,%f]", key, location.latitude, location.longitude));
                }
                @Override
                public void onGeoQueryReady() {
                    Log.i(TAG, "onGeoQueryReady");
                    System.out.println("All initial data has been loaded and events have been fired!");
                }
                @Override
                public void onGeoQueryError(DatabaseError error) {
                    Log.i(TAG, "onGeoQueryError DatabaseError = " + error.getMessage());
                    System.err.println("There was an error with this query: " + error);
                }
            });

My firebase data screen shot attached below.
screenshot from 2017-03-25 16-48-47

onKeyEntered() method not getting call even data available

When I pass longitude as positive value then it not calling onKeyEntered() method.
It directly call onGeoQueryReady() method even data available in radius.

When I pass longitude as negative value then it is calling onKeyEntered() method.

Include timestamp into Geolocation object.

It could be interesting for some apps to include a timestamp into a Geolocation object to do queries in real time. Could you planning to do this at some times. May be I can help.

java.lang.AbstractMethodError: abstract method not implemented

Process: com.firebase.sfvehicles, PID: 16873
java.lang.AbstractMethodError: abstract method not implemented
at com.firebase.client.android.AndroidPlatform.newRunLoop(AndroidPlatform.java)
at com.firebase.client.core.Context.ensureRunLoop(Context.java:219)
at com.firebase.client.core.Context.initServices(Context.java:106)
at com.firebase.client.core.Context.freeze(Context.java:87)
at com.firebase.client.core.RepoManager.getLocalRepo(RepoManager.java:55)
at com.firebase.client.core.RepoManager.getRepo(RepoManager.java:19)
at com.firebase.client.Firebase.(Firebase.java:182)
at com.firebase.client.Firebase.(Firebase.java:187)
at com.firebase.client.Firebase.(Firebase.java:165)
at com.firebase.sfvehicles.SFVehiclesActivity.onCreate(SFVehiclesActivity.java:56)
at android.app.Activity.performCreate(Activity.java:5584)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1093)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2405)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2500)
at android.app.ActivityThread.access$900(ActivityThread.java:171)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1309)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
at dalvik.system.NativeStart.main(Native Method)

[Major Refactor] Need to split geofire-android and geofire-java into two repos

When trying to set the setLocation on the GeoFire object runs into following issue at run time

No virtual method setValue(Ljava/lang/Object;Ljava/lang/Object;)Lcom/google/firebase/tasks/Task; in class Lcom/google/firebase/database/DatabaseReference; or its super classes (declaration of 'com.google.firebase.database.DatabaseReference' appears in  (apk file )

Using the GeoFire 2.0.0 SNAPSHOT version.
Firebase version: com.google.firebase:firebase-database:9.0.2

onGeoQueryReady never called

Hi

I have a really simple database with 3 location objects:
screen shot 2017-01-03 at 2 35 01 pm

My rules are the following:
screen shot 2017-01-03 at 2 36 08 pm

And I'm trying to obtain the bars within a radius. Currently all the bars are within the radius.
onKeyEntered gets called 3 times successfully but the call to onGeoQueryReady in never notified.

GeoFire geoFire = new GeoFire(mBarsLocationReference);
        final GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(latitude, longitude), RADIUS_KM);
        geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
      .........
}

Thanks

long delay getting onGeoQueryReady callback

Am regularly seeing relatively long delay (e.g. 5-10s....but in some cases significantly longer) before onGeoQueryReady callback is invoked. This is I believe causing issue when moving quickly around map for example i.e. where another query is made before previous one completes.....what is the recommended approach in general for handling new query while one is still in progress?

Query keys within an arbitrary shape?

This might be a stretch, but in addition to querying for keys within a radius, will it be possible (in the future perhaps) to query for keys within an arbitrary shape (possibly defined as a list of GeoLocations)?

E.g. usage: Check if a point is within a certain city (given that I know a list of GeoLocations that outlines the city).

Upgrade GeoFire to the 3.x.x Java SDK

Will GeoFire have to be updated now that firebase has changed some of their structure as well? Could you show the implementation of these changes in the README.md instructions?

Thanks!

getLocation onChangeListener

Is there a possibility to attach onChangeListener to geoLocation? Sure there is possibility to use for example

DatabaseReference ref = FirebaseDatabase.getInstance().getReference(path)
                .child(key)
                .child("l");

ref.addValueEventListener(...

but to have this functionality embedded in geofire would be nice.

Multiple inserts

Hey guys,
A common scenario using GeoFire is:

  1. Save the Geo to a Collection
  2. Grab the key (perhaps the object) and save it to another collection
  3. You're done.

So, the problem that arise is, we can't guarantee the consistency in Firebase, e.g. if some error occurs in any of the steps.
In this case, Firebase provides mDatabase.updateChildren(childUpdates);.
My question is, what is the best scenario to handle this common situation with GeoFire ?

I was thinking about maybe exposing the updates HashMap as in GeoFire:

Map<String, Object> updates = new HashMap<String, Object>();
        updates.put("g", geoHash.getGeoHashString());
        updates.put("l", Arrays.asList(location.latitude, location.longitude));

Or maybe creating another overloaded method receiving a HashMap, adding the updates to it and calling mDatabase.updateChildren(childUpdates);

Does it make sense ?

No ability to use GeoLocation in another class for input

I have a Source Class that stores GeoLocation

import com.firebase.geofire.GeoLocation;
import com.github.slugify.Slugify;

/**
 * Created by Alex Patterson on 6/2/17.
 */


public class Source {
    private String placeId;
    private String placeName;
    private String slugName;
    private GeoLocation geoLocation;
    private Object createDate;
    private String uid;
    public static final Slugify slg = new Slugify();

    public Source() {
        // empty default constructor, necessary for Firebase to be able to deserialize
    }
    public Source(String placeId,
                  String placeName,
                  String slugName,
                  GeoLocation geoLocation,
                  Object createDate,
                  String uid
    ) {
        this.placeId = placeId;
        this.placeName = placeName;
        this.slugName = slugName;
        this.geoLocation = geoLocation;
        this.createDate = createDate;
        this.uid = uid;
    }

    public Source(String placeId,
                  String placeName,
                  GeoLocation geoLocation,
                  Object createDate,
                  String uid
    ) {
        this.placeId = placeId;
        this.placeName = placeName;
        this.slugName = slg.slugify(placeName);
        this.geoLocation = geoLocation;
        this.createDate = createDate;
        this.uid = uid;
    }

    public String getPlaceId() {
        return placeId;
    }

    public String getPlaceName() {
        return placeName;
    }

    public String getSlugName() {
        return slugName;
    }

    public GeoLocation getGeoLocation() {
        return geoLocation;
    }

    public Object getCreateDate() {
        if (createDate == null) {
            return Long.valueOf(0);
        }
        return createDate;
    }

    public String getUid() {
        return uid;
    }
}

I can save using this class no problem

Source source = new Source(
        placeId,
        placeName,
        new GeoLocation(placeLatLng.latitude, placeLatLng.longitude),
        ServerValue.TIMESTAMP,
        FirebaseUtil.getCurrentUserId());
String newKey = FirebaseUtil.getBaseRef().child("sources").push().getKey();
FirebaseUtil.getBaseRef().child("sources").child(newKey).setValue(source);

However while reading back the class into the same object I get an error
E/UncaughtException: com.google.firebase.database.DatabaseException: Class com.firebase.geofire.GeoLocation is missing a constructor with no arguments

I would like to propose that we add a Default constructor with no arguments to this class.

org.apache.httpcomponents and httpclient warning

Getting this warning:
Warning:Dependency org.apache.httpcomponents:httpclient:4.0.1 is ignored for debug as it may be conflicting with the internal version provided by Android.
In case of problem, please repackage it with jarjar to change the class packages

Solved via:

compile 'com.firebase:firebase-client-android:2.3.1'
compile ('com.firebase:geofire:1.1.0'){
    exclude group: 'org.apache.httpcomponents', module: 'httpclient'
}

Does this justify a documentation change in the readme/projects?

Issues with Google App Engine Thread

So we are using Google App Engine as our primary backend and we are planning to call Firebase from our GAE instance for users' realtime location.
It seems like the GAE is denying GeoFire library because the library is initializing a Thread when calling GeoFire geoFire = new GeoFire(new Firebase(("address")));. So initializing Firebase object is throwing an exception.
Is there a work around for this problem?

Here is the stack trace:

[INFO] Jun 24, 2015 12:03:00 AM com.google.api.server.spi.SystemService invokeServiceMethod
[INFO] SEVERE: exception occurred while calling backed method
[INFO] java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "modifyThreadGroup")
[INFO]  at java.security.AccessControlContext.checkPermission(AccessControlContext.java:372)
[INFO]  at java.security.AccessController.checkPermission(AccessController.java:559)
[INFO]  at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
[INFO]  at com.google.appengine.tools.development.DevAppServerFactory$CustomSecurityManager.checkPermission(DevAppServerFactory.java:429)
[INFO]  at com.google.appengine.tools.development.DevAppServerFactory$CustomSecurityManager.checkAccess(DevAppServerFactory.java:454)
[INFO]  at java.lang.ThreadGroup.checkAccess(ThreadGroup.java:315)
[INFO]  at java.lang.Thread.init(Thread.java:391)
[INFO]  at java.lang.Thread.init(Thread.java:349)
[INFO]  at java.lang.Thread.<init>(Thread.java:675)
[INFO]  at java.util.concurrent.Executors$DefaultThreadFactory.newThread(Executors.java:572)
[INFO]  at com.firebase.client.utilities.DefaultRunLoop$FirebaseThreadFactory.newThread(DefaultRunLoop.java:20)
[INFO]  at java.util.concurrent.ThreadPoolExecutor$Worker.<init>(ThreadPoolExecutor.java:610)
[INFO]  at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:924)
[INFO]  at java.util.concurrent.ThreadPoolExecutor.ensurePrestart(ThreadPoolExecutor.java:1590)
[INFO]  at java.util.concurrent.ScheduledThreadPoolExecutor.delayedExecute(ScheduledThreadPoolExecutor.java:333)
[INFO]  at java.util.concurrent.ScheduledThreadPoolExecutor.schedule(ScheduledThreadPoolExecutor.java:530)
[INFO]  at java.util.concurrent.ScheduledThreadPoolExecutor.execute(ScheduledThreadPoolExecutor.java:619)
[INFO]  at com.firebase.client.utilities.DefaultRunLoop.scheduleNow(DefaultRunLoop.java:47)
[INFO]  at com.firebase.client.core.Repo.scheduleNow(Repo.java:191)
[INFO]  at com.firebase.client.core.Repo.<init>(Repo.java:67)
[INFO]  at com.firebase.client.core.RepoManager.getLocalRepo(RepoManager.java:64)
[INFO]  at com.firebase.client.core.RepoManager.getRepo(RepoManager.java:19)
[INFO]  at com.firebase.client.Firebase.<init>(Firebase.java:182)
[INFO]  at com.firebase.client.Firebase.<init>(Firebase.java:187)
[INFO]  at com.firebase.client.Firebase.<init>(Firebase.java:165)
[INFO]  at com.example.endpoint.UserEndpoint.setUserLocation(UserEndpoint.java:109)

Geofire query with Firebase adding duplicate objects to Arraylist

I'm not really sure if this is really where I should be putting this, but I've gotten no help thus far on Stackoverflow. Maybe you guys can help. Thank you.

Been stuck here for a bit, I've tried to used the Firebase UI FirebaseRecyclerAdapter, but it wont take multiple references for the keys generated by the GeoQuery. So i used a typical Array adapter. The problem is that whenever the object is updated/changed in Firebase, it creates duplicates of the object in the array. I've tried to use if(!arrayofcars.contains(car)), but it doesn't change as technically the objects are different. Here's a bit of the code..

    GeoFire geoFire = new GeoFire(mDatabaseReference.child("cars_location"));
     GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(userLat, userLong), 20);
        geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
        @Override
        public void onKeyEntered(String key, GeoLocation location) {

            Toast.makeText(CarHopActivity.this, "Key: " + key, Toast.LENGTH_SHORT).show();
            tempDataRef = FirebaseDatabase.getInstance().getReference("/cars/" + key);
            tempDataRef.addChildEventListener(new ChildEventListener() {
                @Override
                public void onChildAdded(DataSnapshot dataSnapshot, String s) {

                    Car car = dataSnapshot.getValue(Car.class);
                    Log.d(TAG, "this is the object"+ car.getCarName());
                    arrayOfCars.add(car);
                    nearestCars.notifyDataSetChanged();
                }

                @Override
                public void onChildChanged(DataSnapshot dataSnapshot, String s) {
                }

                @Override
                public void onChildRemoved(DataSnapshot dataSnapshot) {
                }

                @Override
                public void onChildMoved(DataSnapshot dataSnapshot, String s) {

                }

                @Override
                public void onCancelled(DatabaseError databaseError) {

                }
            });

and the object class...

public class Car {
    private String carName;
    private int carCount;
    private int carCap;
    private String carAddress;
    private String carPhotoURI;
    private String userId;

    public double getLatitude() {
            return latitude;
    }

    public void setLatitude(double latitude) {
        this.latitude = latitude;
    }

    public double getLongitude() {
        return longitude;
    }

    public void setLongitude(double longitude) {
            this.longitude = longitude;
    }

    private double latitude;
    private double longitude;

    public String getUserId() {
            return userId;
    }

    public void setUserId(String userId) {
            this.userId = userId;
    }


    public String getCarPhotoURI() {
            return carPhotoURI;
    }

    public void setCarPhotoURI(String carPhotoURI) {
             this.carPhotoURI = carPhotoURI;
    }

    public String getcarName() {
            return carName;
    }

    public void setCarName(String carName) {
            this.carName = carName;
    }

    public int getCarCount() {
            return carCount;
    }

    public void setCarCount(int carCount) {
            this.carCount = carCount;
    }

    public int getCarCap() {
             return carCap;
    }

    public void setCarCap(int carCap) {
            this.carCap = carCap;
    }

    public String getCarAddress() {
            return carAddress;
    }

    public void setCarAddress(String carAddress) {
            this.carAddress = carAddress;
    }
    public Car(String carName, int carCount, int carCap, String carAddress, String carPhotoURI, double                 latitude, double longitude, String userId) {
    this.carCap = carCap;
    this.carCount = carCount;
    this.carName = carName;
    this.carAddress = carAddress;
    this.carPhotoURI = carPhotoURI;
    this.latitude = latitude;
    this.longitude = longitude;
    this.userId = userId;

    }

Ability to use multi location updates with geofire

It would be a very good (probably ideal) way to do writes and updates if the data and location could be updated simultaneously, instead of writing the data, then writing location on success of data write, and reverting the operation all together incase of failure of either of the 2 writes.

Multi location updates is available in firebase, it could be a really good addition to geofire. Thoughts?

Update geofire-java dependencies

Is there any plan to make geofire-java support com.google.firebase:firebase-database instead of com.firebase:firebase-client-android?

geofire-2 DatabaseError.fromStatus

imported geofire-java classes (from geofire-2 branch) into my android project. I was unable to build.
in GeoFire.java:80 (https://github.com/firebase/geofire-java/blob/geofire-2/src/main/java/com/firebase/geofire/GeoFire.java)
changed from:
this.callback.onCancelled(DatabaseError.fromStatus(message));
to
this.callback.onCancelled(DatabaseError.fromException(new DatabaseException("message")));

I didnt see fromStatus(String) in:
https://firebase.google.com/docs/reference/android/com/google/firebase/database/DatabaseError.html#public-methods

It works to build but it was just a workaround to build. I'm not familiar enough yet with everything to offer a good answer/test.

Very excited to use the library, thanks for the work

Errors

When i debug the projetc appear the next errors:

Error:Error: File path too long on Windows, keep below 240 characters : C:\Users\xxx\Downloads\geofire-java-master\geofire-java-master\examples\SFVehicles\SF Vehicles\build\intermediates\exploded-aar\com.google.android.gms\play-services-base\9.0.2\res\drawable-xhdpi-v4\common_google_signin_btn_text_dark_pressed.9.png

Error:Execution failed for task ':SF Vehicles:mergeDebugResources'.

C:\Users\xxx\Downloads\geofire-java-master\geofire-java-master\examples\SFVehicles\SF Vehicles\build\intermediates\exploded-aar\com.google.android.gms\play-services-base\9.0.2\res\drawable-xhdpi-v4\common_google_signin_btn_text_dark_pressed.9.png: Error: File path too long on Windows, keep below 240 characters : C:\Users\xxx\Downloads\geofire-java-master\geofire-java-master\examples\SFVehicles\SF Vehicles\build\intermediates\exploded-aar\com.google.android.gms\play-services-base\9.0.2\res\drawable-xhdpi-v4\common_google_signin_btn_text_dark_pressed.9.png

queryAtLocation is not working

The lattitude and longitude is not being returned

GeoFire geoFire1 = new GeoFire(new Firebase("https://....../profile/"));
GeoQuery geoQuery = geoFire1.queryAtLocation(new GeoLocation(-37.920547, 145.130357), 0.6);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
@OverRide
public void onKeyEntered(String key, GeoLocation location) {
System.out.println(String.format("Key %s entered the search area at [%f,%f]", key, location.latitude, location.longitude));
}

                @Override
                public void onKeyExited(String key) {
                    System.out.println(String.format("Key %s is no longer in the search area", key));
                }

                @Override
                public void onKeyMoved(String key, GeoLocation location) {
                    System.out.println(String.format("Key %s moved within the search area to [%f,%f]", key, location.latitude, location.longitude));
                }

                @Override
                public void onGeoQueryReady() {
                    System.out.println("All initial data has been loaded and events have been fired!");
                }

                @Override
                public void onGeoQueryError(FirebaseError error) {
                    System.err.println("There was an error with this query: " + error);
                }
            });

screen shot 2016-05-22 at 12 07 09 am

GeoFire

I may be missing something. But has GeoFire been updated to work with the new configuration of Firebase?

Delay when .onKeyEntered/.onKeyExited is triggered

I'm trying to use Geofire to achieve geofencing functionality offered by the Google Awareness fence api

However I'm wondering what's the best way to achieve the equivalant of INITIAL_TRIGGER_DWELL flag, so onKeyEntered is triggered when the point of interest is already inside the radius for certain amount of time.

References:
GeofencingRequest
LocationFence

Rx for Geofire

Is there a Rx library for Geofire?
I'd like to be able to concurrently listen to my firebase data and my geofire locations. Would wrapping Geofire in Rx help or is there an alternative?

Reading geo-fire locations in gae does not work

I had a conversation with the firebase support and was asked to put my issue into this channel. He was able to replicate the issue with a condensed code sample of mine. He also said it might be related to #11.

My situation:
I have a google app engine running with java. I want to read and write locations with my app engine. Writing a location is working quiet well (but callback is not working). When I try to read locations from the firebase database I see an exception in my app engine log.

This is the exception:

Uncaught exception from servlet java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "modifyThreadGroup") at ...

this is my gradle build:

dependencies {
    appengineSdk 'com.google.appengine:appengine-java-sdk:1.9.40'
    compile 'com.google.firebase:firebase-server-sdk:[3.0.0,)'
    compile 'javax.servlet:servlet-api:2.5'
    compile 'com.firebase:geofire-java:2.0.0'
    compile 'com.google.appengine:appengine-api-1.0-sdk:1.9.40'
    compile 'org.apache.httpcomponents:httpclient:4.5.2'
}

this is the call from my java servlet which throws the exception:

DatabaseReference ref = FirebaseDatabase.getInstance().getReference("places/");
GeoFire geoFire = new GeoFire(ref);
geoFire.setLocation("firebase-hq", new GeoLocation(37.7853889, -122.4056973));
//geoFire.removeLocation("firebase-hq");

GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(37.7832, -122.4056), 0.6);

geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
    @Override
    public void onKeyEntered(String key, GeoLocation location) {
        System.out.println(String.format("Key %s entered the search area at [%f,%f]", key, location.latitude, location.longitude));
    }

    @Override
    public void onKeyExited(String key) {
        System.out.println(String.format("Key %s is no longer in the search area", key));
    }

    @Override
    public void onKeyMoved(String key, GeoLocation location) {
        System.out.println(String.format("Key %s moved within the search area to [%f,%f]", key, location.latitude, location.longitude));
    }

    @Override
    public void onGeoQueryReady() {
        System.out.println("All initial data has been loaded and events have been fired!");
    }

    @Override
    public void onGeoQueryError(DatabaseError error) {
        System.err.println("There was an error with this query: " + error);
    }
});

Comment from firebase-support:

It appears that this issue only affects geofire-java and not the Firebase SDK per se.

Kind regards,
Tino

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.