【问题标题】:How to retrieve posts that are within 0.5 kms of my reach?如何检索距离我 0.5 公里范围内的帖子?
【发布时间】:2016-07-15 06:27:05
【问题描述】:

我正在保存用户发布的帖子的坐标。我正在生成一个推送 ID,然后使用它来保存帖子的数据和地火坐标。

我只想显示那些在它们半径 0.5 公里内的帖子。我正在使用 GeoFire 库,但我无法完成任务。

这是我生成推送 ID 的方式:

itemID = databaseReferenceRequests.push().getKey();

这是我使用它来保存地理坐标以及帖子数据的方法:

geoFire.setLocation(itemID, 
        new GeoLocation(Double.parseDouble(currentLat.getText().toString()), 
        Double.parseDouble(currentLng.getText().toString())));

databaseReferenceRequests.child(itemID).setValue(hRequest);

它是这样保存的:

问题是,当我尝试仅获取距离我 0.5 公里范围内的帖子时,它并没有发生,并且所有帖子(无论是近还是远)都被检索到。

这是我检索它的方式:

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

        }

这是错误:

java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference

请告诉我如何只检索用户 0.5 公里以内的帖子?

【问题讨论】:

  • the post posted by the users。哪些用户?哪个网站?
  • @greenapps 我应用的用户..

标签: android firebase firebase-realtime-database geofire


【解决方案1】:

还有一种方法可以在 Java 中的 Geo Query 中查找匹配项。 代码与 UI 非常相似。 请在下面的链接中查看工作代码 sn-p。 https://youtu.be/M9d526OyG54 搜索驱动程序:: 系列中的第 15 篇教程。

【讨论】:

    【解决方案2】:

    你只需要更改queryAtLocation()的第二个参数

    double radius = 0.5; // in km
    geoQuery = geoFire.queryAtLocation(new GeoLocation(currentLatDouble, currentLngDouble), radius);
    

    您确定检索到所有距离用户超过 0.5 公里的项目吗? 以下是验证它们的方法

    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) + "");
        }
    

    【讨论】:

    • 对不起,我忘了更改那个参数。在我的原始代码中设置为 0.5。它仍然没有检索到!
    • 您确定所有距离用户 0.5 公里以上的项目都被检索到了吗?查看我更新的答案以了解如何验证它们
    • 不,兄弟。我无法实现我想要的。我正在写一个问题。你能从头开始编码吗?问题是“假设我在某个地方看到了一种稀有物种。我上传了它以及它的当前位置坐标。现在我想要的是我只想要那些在该稀有物种的地点半径 0.5 公里范围内的用户看到应该看到我发布的那个帖子。不是应用程序的每个用户,只有那些在那个位置 0.5 公里范围内的用户。我希望你能得到我的问题。请使用解决上述问题的代码编辑您的答案。谢谢! :)
    • 我不确定您的问题是什么,我一直在为我的项目使用 GeoFire,它工作正常。根据您的示例,保存稀有物种位置可以拨打geoFire.setLocation(),要获取稀有物种请拨打geoFire.queryAtLocation()queryAtLocation 方法的第一个参数是你用户的位置,所以你需要使用位置提供者来获取他们的位置,第二个参数是以公里为单位的半径。 GeoFire 将仅返回第一个参数提供的用户位置半径范围内的地点。
    • 我认为您需要为错误创建一个新问题,这已经超出了主题。它是否适用于您“检索 0.5 公里内的帖子”?你必须解释你真正的问题是什么并简化你的代码,你的代码很混乱。 how to ask a good question
    【解决方案3】:

    对此我知之甚少,我帮不上什么忙,但是查看您的代码,从 GeoFire 2.0 页面here 中提取的这段代码在 javascript(而不是 java)中给出了您正在寻找的内容的一个很好的概述.

    GeoFire 的真正实用性通过创建 GeoQuery 来展示。假设您正在为骑自行车的人制作一个应用程序,它会显示用户当前位置一英里(1.609 公里)内的自行车商店。您需要做的第一件事是将您关心的自行车商店添加到 GeoFire。然后,创建一个以用户当前位置为中心的查询(假设他们在 [37.4, -122.6]):

    var geoQuery = geoFire.query({
      center: [37.4, -122.6],
      radius: 1.609 //kilometers
    });
    

    单独的查询并不是很有用。但是,GeoFire 允许您添加在发生重要查询事件时触发的回调函数。由于您要显示与查询条件匹配的每个自行车商店,因此请侦听 key_entered 事件。每次一个键(即自行车商店)进入查询时,您定义的回调将被调用,并带有关于该位置的数据:

    geoQuery.on("key_entered", function(key, location, distance) {
      console.log("Bicycle shop " + key + " found at " + location + " (" + distance + " km away)");
    });
    

    重要的是要认识到 key_entered 事件的工作方式与典型的 Firebase 事件类似。也就是说,它将为 GeoFire 中与查询条件匹配的每个键触发,包括 GeoFire 中已经存在的键和将来任何时候添加的键。感谢 Firebase,您可以实时收到这些事件。

    GeoFire 很聪明地知道如何在查询中查找键。它不需要将所有 GeoFire 数据加载到内存中。如果您的用户正在寻找旧金山的自行车商店,GeoFire 将不会加载纽约位置的数据,只会意识到它们位于该国的另一边。它只检查实际附近的位置。无论您的数据集有多大,这都能让您的应用保持轻便和响应迅速。

    如果您的用户在寻找要参观的商店时骑自行车四处走动,那么距离他们一英里以内的商店现在可能更远了。为了解决这个问题,GeoFire 将为离开查询的每个键触发 key_exited 事件:

    geoQuery.on("key_exited", function(key, location, distance) {
      console.log("Bicycle shop " + key + " left query to " + location + " (" + distance + " km away)");
    });
    

    这就是使您的应用正常运行所需的全部内容。

    可用于 Java 的详细信息似乎较少,但对于您尝试执行的操作而言,这似乎是问题:

    GeoQuery geoQuery = geoFire.queryAtLocation(currentUserLocation, 1.6);
    

    参考here

    【讨论】:

    • 您的答案在javascript 中有代码。你能告诉我准确的java 代码吗?
    • 希望我补充的对你有所帮助,Java 的关注度似乎比较低,可能是我没找对地方。
    • Firebase geofire-js:如何获取静态(固定)位置附近的键列表:stackoverflow.com/questions/43632746/…
    猜你喜欢
    • 1970-01-01
    • 2015-07-18
    • 1970-01-01
    • 2016-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-10
    相关资源
    最近更新 更多