Получение списка пользователей только в пределах 3 миль с помощью Geofire - PullRequest
0 голосов
/ 20 января 2020

Я пытаюсь получить только список пользователей, которые находятся в пределах 3 миль от текущего местоположения пользователей. Я использую RecyclelerView для отображения списка пользователей, я также использую Geofire для запроса ключей и использую Firebase для хранения своих пользователей. Когда я пытаюсь получить только список пользователей, которые находятся в пределах 3 миль, мне выдаются все пользователи, включая тех, кто не находится в пределах 3 миль. Может кто-нибудь, пожалуйста, помогите мне исправить это. Ниже мой код. Заранее спасибо

MainClass Для извлечения данных

@Override
public void onSuccess(Location location) {

    Double latitude=location.getLatitude();
    Double longitude=location.getLongitude();

    Geocoder geocoder=new Geocoder(NewsFeedActivity.this, Locale.getDefault());


     firebaseDatabase=FirebaseDatabase.getInstance().getReference("Users");
    GeoFire geoFire=new GeoFire(firebaseDatabase.child("locals"));


    final GeoQuery geoQuery=geoFire.queryAtLocation(new GeoLocation(latitude,longitude),3);

    geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
        @Override
        public void onKeyEntered(final String key, GeoLocation location) {

            firebaseDatabase.addValueEventListener(new ValueEventListener() {


                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    list=new ArrayList<Users>();

                    for(DataSnapshot dataSnapshot1:dataSnapshot.getChildren()){
                        Users my=dataSnapshot1.getValue(My.class);
                        list.add(my);

                    }

                adapter=new MyAdapter(MainActivity.this,list);
                            recycler.setAdapter(adapter);


                    adapter=new MyAdapter(MainActivity.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) {

            System.err.println("There was an error with this query: " + error);


        }
    });

Класс адаптера для реселлера ViewView

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

    Context context;
    private ArrayList<UserInformation> users;



    public MyAdapter(Context c,ArrayList<UserInformation> u){

        context=c;
        users=u;

    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.cardview,parent,false));
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.user_name.setText(users.get(position).getBusinessname());
        holder.address.setText(users.get(position).getAddress());


    }

    @Override
    public int getItemCount() {
        return users.size();
    }


    class MyViewHolder extends RecyclerView.ViewHolder{


        TextView user_name,address;
        public MyViewHolder(@NonNull View itemView) {
            super(itemView);

            user_name=(TextView)itemView.findViewById(R.id.user_name);
            address=(TextView)itemView.findViewById(R.id.user_address);
        }
    }
}


     //Users Class

    public class Users {

    public String usersname;
    public String address;
    public String phonenumber;

    public Users(String usersname, String address, String phonenumber) {
        this.usersname = usersname;
        this.address = address;
        this.phonenumber = phonenumber;
    }

    public Users(){

    }

    public String getBusinessname() {
        return usersname;
    }

    public void setBusinessname(String businessname) {
        this.usersname = usersname;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhonenumber() {
        return phonenumber;
    }

    public void setPhonenumber(String phonenumber) {
        this.phonenumber = phonenumber;
    }
}

Ответы [ 3 ]

2 голосов
/ 20 января 2020

Ваш гео-запрос правильно ищет ключи в пределах 3 километров от заданного местоположения:

firebaseDatabase=FirebaseDatabase.getInstance().getReference("Users");
GeoFire geoFire=new GeoFire(firebaseDatabase.child("locals"));

final GeoQuery geoQuery=geoFire.queryAtLocation(new GeoLocation(latitude,longitude),3);

Но затем, когда GeoFire находит ключ в этом диапазоне и вызывает onKeyEntered, вы добавляете ValueEventListener к весь узел Users:

geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
    @Override
    public void onKeyEntered(final String key, GeoLocation location) {
        firebaseDatabase.addValueEventListener(new ValueEventListener() {

Таким образом, для каждого ключа в пределах диапазона геоквери вы загружаете всех пользователей. Если в диапазоне несколько ключей, вы загружаете всех пользователей для каждого ключа и каждый раз создаете адаптер. В лучшем случае это грязно и расточительно, но я думаю, что в этом случае и ваш код не выполняет то, что вы хотите.

Лучше всего предположить, что каждый ключ в гео-запросе идентифицирует узел в Users, и вы хотите загружать этот пользовательский узел каждый раз, когда вызывается ваш метод onKeyEntered. Таким образом, когда в пределах диапазона геоквери существует несколько ключей, вы загружаете каждого пользователя в этом диапазоне по одному.

Если это так, вам понадобится этот слушатель внутри onKeyEntered:

firebaseDatabase.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        Users my=dataSnapshot.getValue(My.class);
        list.add(my);
        adapter.notifyDataSetChanged();
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        throw databaseError.toException(); // never ignore possible errors
    }
});

Некоторые из изменений, которые я сделал здесь:

  • Вместо загрузки всех пользователей, это загружает одного пользователя для каждого ключа, который находится (или входит) в диапазон геоквери.
  • Используйте addListenerForSingleValueEvent вместо непрерывного слушателя. Таким образом, вы получаете данные для пользователя только один раз, вместо того, чтобы постоянно добавлять все больше и больше слушателей.
  • Позвоните adapter.notifyDataSetChanged(); вместо создания нового адаптера для каждого ключа, попадающего в диапазон геоквери.

Что вам еще нужно сделать:

  • Инициализировать адаптер только один раз, за пределами onKeyEntered, передав ему list.

Затем, когда срабатывает onKeyEntered и вы загружаете данные этого пользователя, вы добавляете их в list и сообщаете адаптеру, что ему нужно перекрасить с adapter.notifyDataSetChanged().

0 голосов
/ 21 января 2020

Я решил это с помощью ответов Фрэнка Ван Пуффелена. Вот что я сделал

public void onKeyEntered(final String key, GeoLocation location) {

                    firebaseDatabase.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
                        @Override
                        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                                Users my=dataSnapshot.getValue(Users.class);
                                list.add(my);
                             adapter=new MyAdapter(MainActivity.this,list);
                             recycler.setAdapter(adapter);

                            }
0 голосов
/ 20 января 2020

Вы можете указать центр и радиус несколькими способами . Вот один из способов:

var geoQuery = geoFire.query({
  center: [10.38, 2.41],
  radius: 10.5
});

Обратите внимание, что радиус указан в километрах.

...