如何使用 firebase 为用户检索附近的面包店
How can I retrieve nearby bakeries to users using firebase
我知道这个问题已经被问了一遍又一遍,但我似乎得不到一个好的答案。我正在尝试根据用户位置检索数据。例如,假设我的数据库有一个面包店列表。每个面包店都有一个地址、经度和纬度、邮政编码、城市、州。现在我想向客户展示所有的面包店,但只有他们所在区域附近的面包店,比方说 5 英里外,我将如何去做。过去几天我一直在寻找答案,但似乎没有任何效果。我什至试过 this answer I saw on Stack overflow and its not working. Someone please please please help me with this. Below is my code
//这个页面是用户注册后自动保存经纬度的地方,也是保存Geohash等的地方
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
@Override
public void onSuccess(final Location location) {
// Got last known location. In some rare situations this can be null.
if (location != null) {
// Logic to handle location object
Double latittude = location.getLatitude();
Double longitude = location.getLongitude();
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference("Users");
DatabaseReference update = rootRef.child(uid);
GeoFire geoFire=new GeoFire(rootRef);
geoFire.setLocation("latandlong", new GeoLocation(location.getLatitude(), location.getLongitude()), new GeoFire.CompletionListener() {
@Override
public void onComplete(String key, DatabaseError 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!");
}
}
});
geoFire.getLocation("latandlong", 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));
// save longitude and latitude to db
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference update = rootRef.child("Users").child(uid);
Double longi = location.longitude;
Double lat = location.latitude;
update.child("latandlong").setValue(location.latitude+ "," +location.longitude);
//update.child("longitude").setValue(longi);
//update.child("latitude").setValue(lat);
} 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);
}
});
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_news_feed);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
menuItem=(MenuItem)findViewById(R.id.item_sign_in);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
recycler=findViewById(R.id.recyclerView);
recycler.setLayoutManager(new LinearLayoutManager(this));
final DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
mFusedLocationClient.getLastLocation().addOnSuccessListener(new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
Double lat=location.getLatitude();
Double longi=location.getLongitude();
firebaseDatabase=FirebaseDatabase.getInstance().getReference("Users");
GeoFire geoFire=new GeoFire(firebaseDatabase.child("latandlong"));
GeoQuery geoQuery=geoFire.queryAtLocation(new GeoLocation(lat,longi),5);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
@Override
public void onKeyEntered(String key, GeoLocation location) {
firebaseDatabase.child(key).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
list=new ArrayList<UserInformation>();
for(DataSnapshot dataSnapshot1:dataSnapshot.getChildren()){
UserInformation uuu=dataSnapshot1.getValue(UserInformation.class);
list.add(uuu);
}
}
adapter=new MyAdapter(NewsFeedActivity.this,list);
recycler.setAdapter(adapter);
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
@Override
public void onKeyExited(String key) {
}
@Override
public void onKeyMoved(String key, GeoLocation location) {
}
@Override
public void onGeoQueryReady() {
}
@Override
public void onGeoQueryError(DatabaseError error) {
}
});
}
});
首先,您需要检查该位置的数据是否已添加到 geofire。
您可以在将面包店数据添加到 firebase 时添加该数据,如下所示
geoFire.setLocation("your key", new GeoLocation(37.7853889, -122.4056973));
Geofire 查询方法以公里而不是英里为单位计算距离,因此您必须将 5 英里转换为公里。
GeoQuery geoQuery=geoFire.queryAtLocation(new GeoLocation(lat,longi),5); //distance in km
这是初始化 GeoFire 的方式:
firebaseDatabase=FirebaseDatabase.getInstance().getReference("Users");
GeoFire geoFire=new GeoFire(firebaseDatabase.child("latandlong"));
这意味着在您的数据库中,您应该有一个节点 /Users/latandlong
, 在 下,您有一个带有 geohash 和 lat/lon 的节点对于您要跟踪的每个键。所以:
Users: {
latandlong: {
"IEvLcwll....SQkbp2": {
g: "..."
l: { 0: ..., 1: ... }
}
}
}
此结构与您共享的屏幕截图中的不同,因为您缺少 key 级别:"IEvLcwll....SQkbp2"
。这解释了为什么您在 geoFire
上触发的任何地理查询都找不到任何键。
我强烈建议阅读 GeoFire 文档:
- 如何 initialize the GeoFire object,您通常希望将其指向顶级节点。
- 然后set the location data for a specific key,会成为你上一步设置的顶级节点下的子节点
只有正确完成这两个步骤后,您才能execute a geoquery against the data。
我知道这个问题已经被问了一遍又一遍,但我似乎得不到一个好的答案。我正在尝试根据用户位置检索数据。例如,假设我的数据库有一个面包店列表。每个面包店都有一个地址、经度和纬度、邮政编码、城市、州。现在我想向客户展示所有的面包店,但只有他们所在区域附近的面包店,比方说 5 英里外,我将如何去做。过去几天我一直在寻找答案,但似乎没有任何效果。我什至试过 this answer I saw on Stack overflow and its not working. Someone please please please help me with this. Below is my code
//这个页面是用户注册后自动保存经纬度的地方,也是保存Geohash等的地方
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
@Override
public void onSuccess(final Location location) {
// Got last known location. In some rare situations this can be null.
if (location != null) {
// Logic to handle location object
Double latittude = location.getLatitude();
Double longitude = location.getLongitude();
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference("Users");
DatabaseReference update = rootRef.child(uid);
GeoFire geoFire=new GeoFire(rootRef);
geoFire.setLocation("latandlong", new GeoLocation(location.getLatitude(), location.getLongitude()), new GeoFire.CompletionListener() {
@Override
public void onComplete(String key, DatabaseError 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!");
}
}
});
geoFire.getLocation("latandlong", 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));
// save longitude and latitude to db
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference update = rootRef.child("Users").child(uid);
Double longi = location.longitude;
Double lat = location.latitude;
update.child("latandlong").setValue(location.latitude+ "," +location.longitude);
//update.child("longitude").setValue(longi);
//update.child("latitude").setValue(lat);
} 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);
}
});
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_news_feed);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
menuItem=(MenuItem)findViewById(R.id.item_sign_in);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
recycler=findViewById(R.id.recyclerView);
recycler.setLayoutManager(new LinearLayoutManager(this));
final DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
mFusedLocationClient.getLastLocation().addOnSuccessListener(new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
Double lat=location.getLatitude();
Double longi=location.getLongitude();
firebaseDatabase=FirebaseDatabase.getInstance().getReference("Users");
GeoFire geoFire=new GeoFire(firebaseDatabase.child("latandlong"));
GeoQuery geoQuery=geoFire.queryAtLocation(new GeoLocation(lat,longi),5);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
@Override
public void onKeyEntered(String key, GeoLocation location) {
firebaseDatabase.child(key).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
list=new ArrayList<UserInformation>();
for(DataSnapshot dataSnapshot1:dataSnapshot.getChildren()){
UserInformation uuu=dataSnapshot1.getValue(UserInformation.class);
list.add(uuu);
}
}
adapter=new MyAdapter(NewsFeedActivity.this,list);
recycler.setAdapter(adapter);
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
@Override
public void onKeyExited(String key) {
}
@Override
public void onKeyMoved(String key, GeoLocation location) {
}
@Override
public void onGeoQueryReady() {
}
@Override
public void onGeoQueryError(DatabaseError error) {
}
});
}
});
首先,您需要检查该位置的数据是否已添加到 geofire。 您可以在将面包店数据添加到 firebase 时添加该数据,如下所示
geoFire.setLocation("your key", new GeoLocation(37.7853889, -122.4056973));
Geofire 查询方法以公里而不是英里为单位计算距离,因此您必须将 5 英里转换为公里。
GeoQuery geoQuery=geoFire.queryAtLocation(new GeoLocation(lat,longi),5); //distance in km
这是初始化 GeoFire 的方式:
firebaseDatabase=FirebaseDatabase.getInstance().getReference("Users");
GeoFire geoFire=new GeoFire(firebaseDatabase.child("latandlong"));
这意味着在您的数据库中,您应该有一个节点 /Users/latandlong
, 在 下,您有一个带有 geohash 和 lat/lon 的节点对于您要跟踪的每个键。所以:
Users: {
latandlong: {
"IEvLcwll....SQkbp2": {
g: "..."
l: { 0: ..., 1: ... }
}
}
}
此结构与您共享的屏幕截图中的不同,因为您缺少 key 级别:"IEvLcwll....SQkbp2"
。这解释了为什么您在 geoFire
上触发的任何地理查询都找不到任何键。
我强烈建议阅读 GeoFire 文档:
- 如何 initialize the GeoFire object,您通常希望将其指向顶级节点。
- 然后set the location data for a specific key,会成为你上一步设置的顶级节点下的子节点
只有正确完成这两个步骤后,您才能execute a geoquery against the data。