Reputation: 2959
I am saving the coordinates of the post posted by the users. I'm generating a push id and then using it to save both the data of the post and the geofire coordinates.
I want to show only those posts which are within 0.5 kms radius of them. I am using GeoFire
library for the same but I'm unable to achieve the task.
Here's how I'm generating the push id:
itemID = databaseReferenceRequests.push().getKey();
Here's how I'm using it to save geofire coordinates as well as the data of the posts:
geoFire.setLocation(itemID,
new GeoLocation(Double.parseDouble(currentLat.getText().toString()),
Double.parseDouble(currentLng.getText().toString())));
databaseReferenceRequests.child(itemID).setValue(hRequest);
It is getting saved like this:
The problem is that when I'm trying to fetch only those posts which are within 0.5 kms of my reach, it is not happening and all the posts whether near or far are getting retrieved.
Here's how I'm retrieving it:
public void retrieveHelpRequests() {
geoQuery = geoFire.queryAtLocation(new GeoLocation(currentLatDouble, currentLngDouble), 0.5);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
@Override
public void onKeyEntered(String key, GeoLocation location) {
databaseReference.child("help-requests").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, String> newRequest = (Map<String, String>) dataSnapshot.getValue();
imageUID = newRequest.get("imageUIDh");
homelessDescription = newRequest.get("homelessDescription");
currentLat = newRequest.get("currentLat");
currentLng = newRequest.get("currentLng");
postedBy = newRequest.get("postedBy");
postedAtTime = newRequest.get("postedAtTime");
postedOnDate = newRequest.get("postedOnDate");
utcFormatDateTime = newRequest.get("utcFormatDateTime");
String timeStr = utcFormatDateTime;
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = null;
try {
// error on line below
date = df.parse(timeStr);
} catch (ParseException e) {
e.printStackTrace();
}
df.setTimeZone(TimeZone.getDefault());
final String persisted = df.format(date);
// Parse string from DB - UTC timezone
Date parsed = null;
try {
parsed = df.parse(persisted);
} catch (ParseException e) {
e.printStackTrace();
}
// Now convert to whatever timezone for display purposes
final SimpleDateFormat displayFormat = new SimpleDateFormat("h:mm a");
displayFormat.setTimeZone(TimeZone.getDefault());
formattedTime = displayFormat.format(parsed);
prepareDataForRequests();
}
@Override
public void onCancelled(DatabaseError databaseError) {
Snackbar snackbar = Snackbar
.make(coordinatorLayout, databaseError.getMessage(), Snackbar.LENGTH_LONG);
snackbar.setDuration(Snackbar.LENGTH_SHORT);
snackbar.show();
// helpRequestsLoadingDialog.dismiss();
progressBarLoadingRequests.setVisibility(View.INVISIBLE);
}
});
databaseReference.child("help-requests").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(final DataSnapshot dataSnapshot) {
// adView.loadAd(request);
card_ads2.setVisibility(View.VISIBLE);
adView2.loadAd(request2);
if (snackbar != null) {
snackbar.dismiss();
}
progressBarLoadingRequests.setVisibility(View.INVISIBLE);
if (fastItemAdapter.getAdapterItemCount() == 0) {
emptyRVtext.setVisibility(View.VISIBLE);
emptyRVtexthh.setVisibility(View.VISIBLE);
card_ads2.setVisibility(View.INVISIBLE);
} else {
emptyRVtext.setVisibility(View.INVISIBLE);
emptyRVtexthh.setVisibility(View.INVISIBLE);
}
// progressBarLoadingRequests.setVisibility(View.INVISIBLE);
}
@Override
public void onCancelled(DatabaseError databaseError) {
Snackbar snackbar = Snackbar
.make(coordinatorLayout, databaseError.getMessage(), Snackbar.LENGTH_LONG);
snackbar.setDuration(Snackbar.LENGTH_SHORT);
snackbar.show();
// hRequestsLoadingDialog.dismiss();
progressBarLoadingRequests.setVisibility(View.INVISIBLE);
}
});
}
@Override
public void onKeyExited(String key) {
}
@Override
public void onKeyMoved(String key, GeoLocation location) {
}
@Override
public void onGeoQueryReady() {
}
@Override
public void onGeoQueryError(DatabaseError error) {
Toast.makeText(getBaseContext(), "Error retriving geoquery", Toast.LENGTH_SHORT).show();
}
});
}
Here's the error:
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
Please let me know how to retrieve only those posts which are within 0.5 kms of the user?
Upvotes: 5
Views: 4548
Reputation: 153
There is a way to find matches in Geo Query in Java also.. The code is very much similar to UI. Please look in the below link for working code snippet. https://youtu.be/M9d526OyG54 Searching for Driver:: 15th tutorial in Series.
Upvotes: 2
Reputation: 29
Not knowing much about this I can't help much, however looking at your code this extract, from the GeoFire 2.0 page here, gives a good outline in javascript (rather than java) of what you're looking for.
GeoFire’s real utility is shown by creating a GeoQuery. Say you are making an app for cyclists which shows the bicycle shops within a mile (1.609 kilometers) of a user’s current location. The first thing you need to do is add the bike shops you care about to GeoFire. Then, create a query centered at the user’s current location (let’s say they are at [37.4, -122.6]):
var geoQuery = geoFire.query({
center: [37.4, -122.6],
radius: 1.609 //kilometers
});
A query on its own is not very useful. However, GeoFire allows you to add callback functions which are fired when important query events happen. Since you want to display every bike shop which matches the query criteria, listen for the key_entered event. Every time a key (that is, a bike shop) enters the query, the callback you defined will get called with data about that location:
geoQuery.on("key_entered", function(key, location, distance) {
console.log("Bicycle shop " + key + " found at " + location + " (" + distance + " km away)");
});
It is important to realize that the key_entered event works like typical Firebase events. That is, it will be fired for every key in GeoFire which matches the query criteria, both keys which are already in GeoFire and those which are added at any point in the future. Thanks to Firebase, you receive these events in realtime.
GeoFire is smart about how it looks for keys within the query. It does not need to load all of the GeoFire data into memory. If your user is looking for bicycle shops in San Francisco, GeoFire will not load data for locations in New York only to realize that they are on the opposite side of the country. It only checks on locations which are actually nearby. This keeps your app light and responsive, regardless of how big your data set is.
If your user is biking around while looking for a shop to visit, it is possible that shops which were within a mile of them are now further away. To deal with this, GeoFire will fire the key_exited event for each key which leaves the query:
geoQuery.on("key_exited", function(key, location, distance) {
console.log("Bicycle shop " + key + " left query to " + location + " (" + distance + " km away)");
});
That is really all you need to make your app work.
The details available for Java appear to be sparser but for what you are trying to do this appears to be the thing:
GeoQuery geoQuery = geoFire.queryAtLocation(currentUserLocation, 1.6);
Reference here.
Upvotes: 1
Reputation: 7720
You just need to change the second parameter of queryAtLocation()
double radius = 0.5; // in km
geoQuery = geoFire.queryAtLocation(new GeoLocation(currentLatDouble, currentLngDouble), radius);
Are you sure that all items which are over 0.5km from the user are retrieved? Here's how to validate them
Location userLocation = new Location("userLocation");
userLocation.setLatitude(currentLatDouble);
userLocation.setLongitude(currentLngDouble);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
@Override
public void onKeyEntered(String key, GeoLocation location) {
Location itemLocation = new Location("itemLocation");
itemLocation.setLatitude(location.latitude);
itemLocation.setLongitude(location.longitude);
Log.d("distance to " + key" is", userLocation.distanceTo(itemLocation) + "");
}
Upvotes: 1