получение ближайших пользователей Android с помощью firebase

я использую базу данных firebase в реальном времени для хранения двух типов пользователей для двух приложений, пользователи A будут использовать приложение A для обновления своей информации и т. д., а пользователи B будут использовать приложение B для поиска ближайших пользователей A, от которых им нужны их услуги. Мне удалось загрузить информацию о пользователе A из приложения A, даже с указанием местоположения с помощью geofire, теперь мне нужно показать список пользователей A внутри приложения B, которые находятся поблизости. пожалуйста, помогите с ответами о лучших способах/практиках, и если это не лучший метод, тогда предложения приветствуются..... спасибо

public class MainActivity extends AppCompatActivity implements LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,Home.OnFragmentInteractionListener
{
    public static String userId;

    public static final int MY_REQUEST_PERMISSION_LOCATION = 1;
    private long UPDATE_INTERVAL = 10 * 1000;  /* 10 secs */
    private long FASTEST_INTERVAL = 2000; /* 2 sec */

    private static final String TAG_HOME = "home";
    private static final String TAG_MY_PREF = "my__preferences";
    private static final String TAG_NOTIFICATIONS = "notifications";
    private static final String TAG_SETTINGS = "settings";
    public static String CURRENT_TAG = TAG_HOME;
    private String [] activityTitles;
    SharedPreferences sharedPreferences;
    String name;
    String imageURI;
    private boolean shouldLoadHomeFragOnBackPress = true;
    private Handler mHandler;
    Toolbar toolbar;
    DrawerLayout drawer;
    NavigationView navigationView;
    private View navHeader;
    private static int navItemIndex = 0;
    private ImageView imgProfile;
    private TextView txtName, txtEmail;
    private DatabaseReference mDatabase;
    GoogleApiClient mGoogleApiClient;
    private boolean isPermissionGranted = false;
    private LocationRequest mLocationRequest;
    public double lat, lng;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        toolbar = (Toolbar) findViewById (R.id.toolbar);
        setSupportActionBar(toolbar);
        mHandler = new Handler ();

        mGoogleApiClient = new GoogleApiClient . Builder (this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this).build();

        activityTitles = getResources().getStringArray(R.array.nav_item_activity_titles);

        drawer = (DrawerLayout) findViewById (R.id.drawer_layout);

        navigationView = (NavigationView) findViewById (R.id.nav_view);
        navHeader = navigationView.getHeaderView(0);
        txtName = (TextView) navHeader . findViewById (R.id.username);

        imgProfile = (ImageView) navHeader . findViewById (R.id.smallProfile);
        setUpNavigationView();
        if (savedInstanceState == null) {
            navItemIndex = 0;
            CURRENT_TAG = TAG_HOME;
            loadHomeFragment();
        }
        sharedPreferences = getSharedPreferences(UserData, Context.MODE_PRIVATE);

        name = sharedPreferences.getString(full_name, null);
        imageURI = sharedPreferences.getString(imagesrc, null);

        upload();
        Glide.with(MainActivity.this).load(Uri.parse(imageURI)).into(imgProfile);
        loadNavHeader();
    }

    public void loadNavHeader() {

        txtName.setText(name);
    }

    private void loadHomeFragment() {
        selectNavMenu();
        // set toolbar title
        setToolbarTitle();

        // if user select the current navigation menu again, don't do anything
        // just close the navigation drawer
        if (getSupportFragmentManager().findFragmentByTag(CURRENT_TAG) != null) {
            drawer.closeDrawers();

            // show or hide the fab button
            return;
        }
        Runnable mPendingRunnable = new Runnable() {
            @Override
            public void run() {
                // update the main content by replacing fragments
                Fragment fragment = getHomeFragment ();
                FragmentTransaction fragmentTransaction = getSupportFragmentManager ().beginTransaction();
                fragmentTransaction.setCustomAnimations(android.R.anim.fade_in,
                        android.R.anim.fade_out);
                fragmentTransaction.replace(R.id.frame, fragment, CURRENT_TAG);
                fragmentTransaction.commitAllowingStateLoss();
            }
        };
        if (mPendingRunnable != null) {
            mHandler.post(mPendingRunnable);
        }
        //Closing drawer on item click
        drawer.closeDrawers();

        // refresh toolbar menu
        invalidateOptionsMenu();
    }

    private void upload() {
        userId = sharedPreferences.getString("UID", null);
        String username = sharedPreferences . getString (full_name, null);
        String photoUri = sharedPreferences . getString (imagesrc, null);

        mDatabase = FirebaseDatabase.getInstance().getReference("users/B");
        mDatabase.child(userId).child("name").setValue(username);
        mDatabase.child(userId).child("imageuri").setValue(photoUri);

    }

    @Override
    public void onStart() {
        super.onStart();

        mGoogleApiClient.connect();
    }
    @Override
    public void onStop() {
        super.onStop();
        if (isPermissionGranted) {
            mGoogleApiClient.disconnect();
        }
    }
    public void onPause() {
        if (isPermissionGranted)
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        super.onPause();
    }
    public void onResume() {
        if (isPermissionGranted) {
            if (mGoogleApiClient.isConnected())
                startLocationUpdates();
        }
        super.onResume();
    }

    private Fragment getHomeFragment() {
        switch(navItemIndex) {
            case 0:
            // home
            Home home = new Home();
            return home;
            case 1:
            //subjects
            MYPref myPref = new MYPref();
            return myPref;
            case 2:
            //
            NotificationFragment notificationsFragment = new NotificationFragment();
            return notificationsFragment;

            case 3:

            Settings settings = new Settings();
            return settings;


            default:
            return new Home ();
        }
    }
    private void setToolbarTitle() {
        getSupportActionBar().setTitle(activityTitles[navItemIndex]);
    }
    private void selectNavMenu() {
        navigationView.getMenu().getItem(navItemIndex).setChecked(true);
    }



    private void setUpNavigationView() {
        //Setting Navigation View Item Selected Listener to handle the item click of the navigation menu
        navigationView.setNavigationItemSelectedListener(new NavigationView . OnNavigationItemSelectedListener () {

            // This method will trigger on item Click of navigation menu
            @Override
            public boolean onNavigationItemSelected(MenuItem menuItem) {

                //Check to see which item was being clicked and perform appropriate action
                switch(menuItem.getItemId()) {
                    //Replacing the main content with ContentFragment Which is our Inbox View;
                    case R . id . nav_home :
                    navItemIndex = 0;
                    CURRENT_TAG = TAG_HOME;
                    break;
                    case R . id . nav_my_subjects :
                    navItemIndex = 1;
                    CURRENT_TAG = TAG_MY_PREF;
                    break;
                    case R . id . nav_notification :
                    navItemIndex = 2;
                    CURRENT_TAG = TAG_NOTIFICATIONS;
                    break;
                    case R . id . nav_settings :
                    navItemIndex = 3;
                    CURRENT_TAG = TAG_SETTINGS;
                    break;
                    case R . id . nav_logout :
                    LoginManager.getInstance().logOut();
                    FirebaseAuth.getInstance().signOut();
                    Intent i = new Intent(MainActivity.this, LoginActivity.class);
                    startActivity(i);

                    finish();
                    default:
                    navItemIndex = 0;
                }

                //Checking if the item is in checked state or not, if not make it in checked state
                if (menuItem.isChecked()) {
                    menuItem.setChecked(false);
                } else {
                    menuItem.setChecked(true);
                }
                menuItem.setChecked(true);

                loadHomeFragment();

                return true;
            }
        });


        ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {

            @Override
            public void onDrawerClosed(View drawerView) {
                // Code here will be triggered once the drawer closes as we dont want anything to happen so we leave this blank
                super.onDrawerClosed(drawerView);
            }

            @Override
            public void onDrawerOpened(View drawerView) {
                // Code here will be triggered once the drawer open as we dont want anything to happen so we leave this blank
                super.onDrawerOpened(drawerView);
            }
        };

        //Setting the actionbarToggle to drawer layout
        drawer.setDrawerListener(actionBarDrawerToggle);

        //calling sync state is necessary or else your hamburger icon wont show up
        actionBarDrawerToggle.syncState();
    }

    @Override
    public void onBackPressed() {
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawers();
            return;
        }

        // This code loads home fragment when back key is pressed
        // when user is in other fragment than home
        if (shouldLoadHomeFragOnBackPress) {
            // checking if user is on other navigation menu
            // rather than home
            if (navItemIndex != 0) {
                navItemIndex = 0;
                CURRENT_TAG = TAG_HOME;
                loadHomeFragment();
                return;
            }
        }
        super.onBackPressed();
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                requestPermissions(new String []{ Manifest.permission.ACCESS_COARSE_LOCATION }, MY_REQUEST_PERMISSION_LOCATION);
            }
            return;
        }

        Location mCurrentLocation = LocationServices . FusedLocationApi . getLastLocation (mGoogleApiClient);
        // Note that this can be NULL if last location isn't already known.
        if (mCurrentLocation != null) {
            // Print current location if not null
            Log.d("DEBUG", "current location: " + mCurrentLocation.toString());

            mDatabase = FirebaseDatabase.getInstance().getReference("users/B");
            GeoFire gf = new GeoFire(mDatabase.child(userId));
            gf.setLocation("location", new GeoLocation (mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude()));
            lat = mCurrentLocation.getLatitude();
            lng = mCurrentLocation.getLongitude();
        }
        // Begin polling for new location updates.
        startLocationUpdates();
    }

    @Override
    public void onConnectionSuspended(int i) {
        if (i == CAUSE_SERVICE_DISCONNECTED) {
            Toast.makeText(this, "Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
        } else if (i == CAUSE_NETWORK_LOST) {
            Toast.makeText(this, "Network lost. Please re-connect.", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

    }

    @Override
    public void onLocationChanged(Location location) {
        String msg = "Updated Location: "+
        Double.toString(location.getLatitude()) + "," +
                Double.toString(location.getLongitude());
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();

    }
    protected void startLocationUpdates() {
        // Create the location request
        mLocationRequest = LocationRequest.create()
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                .setInterval(UPDATE_INTERVAL)
                .setFastestInterval(FASTEST_INTERVAL);
        // Request location updates

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                requestPermissions(new String []{ Manifest.permission.ACCESS_COARSE_LOCATION }, MY_REQUEST_PERMISSION_LOCATION);
            }
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
            return;
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch(requestCode) {
            case MY_REQUEST_PERMISSION_LOCATION :
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                isPermissionGranted = true;
            } else {
                isPermissionGranted = false;
            }
        }
    }

    @Override
    public void onFragmentInteraction() {
    }
}

моя база данных firebase


person omar A.R    schedule 01.07.2017    source источник


Ответы (1)


Для тех, кто найдет это полезным, мне удалось сделать это, поместив addValueEventListenermethod firebase в addQueryEventListener и передав ключ String, возвращаемый onKeyEnteredmethod, как часть пути в моей ссылке на базу данных,

что-то вроде этого

  temp2=FirebaseDatabase.getInstance().getReference("users/A");
  GeoFire geofire=new GeoFire(temp2.child("A_location"));
  GeoQuery geoQuery=geofire.queryAtLocation(new GeoLocation(lat,lng),10);

  geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
      @Override
      public void onKeyEntered(String key, GeoLocation location) {
          temp2.child(key).addValueEventListener(new ValueEventListener() {
              @Override
              public void onDataChange(DataSnapshot dataSnapshot) {


                  Person person1 = dataSnapshot.getValue(Person.class);

                  String name = person1.getName();
                  String imageUri = person1.getImageUri();
                  System.out.print(name + "   " + imageUri);
                  Toast.makeText(getActivity(),name,Toast.LENGTH_LONG).show();

                  personList.add(new Person(name, imageUri));

                  RVAdapter adapter=new RVAdapter(getActivity(),personList);
                  rv.setAdapter(adapter);

              }

Мой единственный вопрос: эффективен ли этот метод при большом количестве пользователей?

person omar A.R    schedule 03.07.2017
comment
Это на самом деле полезно. GeoFire на самом деле использует запросы на стороне сервера, что означает, что это быстрее, чем локальное сравнение значений. При этом, если вы хотите сделать это еще быстрее, вы также должны индексировать свои данные в правилах базы данных Firebase Realtime, чтобы сделать запрос еще быстрее, например. используя ".indexOn": ["location"] , где location имеет 2 дочерних элемента, широту и долготу - person James Ele; 20.12.2020