Java 通过firebase获得附近的android用户

Java 通过firebase获得附近的android用户,java,android,firebase,geofire,Java,Android,Firebase,Geofire,我正在使用firebase实时数据库为两个应用程序存储两种类型的用户,用户A将使用应用程序A更新其信息等,用户B将使用应用程序B搜索其需要服务的附近用户A。我已经成功地从应用程序A上传了用户A的信息,即使使用geofire定位,现在我需要的是显示应用程序B中附近的用户A列表。请帮助回答有关最佳方法/实践的问题,如果这不是最佳方法,欢迎提出建议。。。。。谢谢 public class MainActivity extends AppCompatActivity implements Locatio

我正在使用firebase实时数据库为两个应用程序存储两种类型的用户,用户A将使用应用程序A更新其信息等,用户B将使用应用程序B搜索其需要服务的附近用户A。我已经成功地从应用程序A上传了用户A的信息,即使使用geofire定位,现在我需要的是显示应用程序B中附近的用户A列表。请帮助回答有关最佳方法/实践的问题,如果这不是最佳方法,欢迎提出建议。。。。。谢谢

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的
addValueEventListener
方法放置在
addQueryEventListener
中,并将
onKeyEntered
方法返回的字符串键作为我的数据库引用中路径的一部分传递给他们

类似这样的东西

  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);

              }

我现在唯一的问题是,如果有很多用户,这种方法是否有效?

对于任何认为这种方法有用的人,我将firebase的
addValueEventListener
方法放置在
addQueryEventListener
中,并将
onKeyEntered
方法返回的字符串键作为我的数据库引用中的路径

类似这样的东西

  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);

              }

我唯一的问题是,如果有很多用户,这种方法是否有效?

这实际上很有用。GeoFire实际上是在服务器端使用查询,这意味着它比在本地比较值更快。话虽如此,如果您想让查询速度更快,还应该在Firebase实时数据库规则上为您的数据编制索引,以便使查询速度更快,例如使用
“.indexOn”:[“location”]
,其中location有两个子项,纬度和长度这实际上很有用。GeoFire实际上是在服务器端使用查询,这意味着它比在本地比较值更快。话虽如此,如果您想让查询速度更快,还应该在Firebase实时数据库规则上为您的数据编制索引,以便使查询速度更快,例如使用
“.indexOn”:[“location”]
,其中location有两个子项,纬度和长度