在 Android 上使用 Algolia 获取我的位置与获取的记录位置之间的距离

Get the distance between my position and the fetched record's location with Algolia on Android

我正在使用 Algolia 的 InstantSearch Android 库。这是我的 Query:

searcher.setQuery(new Query().setAroundLatLng(new AbstractQuery.LatLng(lat, lng)).setAroundRadius(5000)).

如何显示获取的记录与我当前位置之间的距离?

创建一个名为 CalculateDistanceTime 的新 class 并粘贴以下代码:

import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;

import com.google.android.gms.maps.model.LatLng;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

class CalculateDistanceTime {

    private taskCompleteListener mTaskListener;
    private Context mContext;


    CalculateDistanceTime(Context context) {
        mContext = context;
    }

    void setLoadListener(taskCompleteListener taskListener) {
        mTaskListener = taskListener;
    }


    void getDirectionsUrl(LatLng origin, LatLng dest) {

        // Origin of route
        String str_origin = "origin=" + origin.latitude + "," + origin.longitude;

        // Destination of route
        String str_dest = "destination=" + dest.latitude + "," + dest.longitude;


        // Sensor enabled
        String sensor = "sensor=false";

        // Building the parameters to the web service
        String parameters = str_origin + "&" + str_dest + "&" + sensor;

        // Output format
        String output = "json";

        // Building the url to the web service
        String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters;


        DownloadTask downloadTask = new DownloadTask();

        // Start downloading json data from Google Directions API

        downloadTask.execute(url);
    }

    private String downloadUrl(String strUrl) throws IOException {
        String data = "";
        HttpURLConnection urlConnection;
        URL url = new URL(strUrl);

        // Creating an http connection to communicate with url
        urlConnection = (HttpURLConnection) url.openConnection();

        // Connecting to url
        urlConnection.connect();

        // Reading data from url
        try (InputStream iStream = urlConnection.getInputStream()) {
            BufferedReader br = new BufferedReader(new InputStreamReader(iStream));

            StringBuilder sb = new StringBuilder();

            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }

            data = sb.toString();

            br.close();

        } catch (Exception e) {
            Log.d("Excp. while downloading", e.toString());
        } finally {
            urlConnection.disconnect();
        }
        return data;
    }


    interface taskCompleteListener {
        void taskCompleted(String[] time_distance);
    }

    private class DownloadTask extends AsyncTask<String, Void, String> {

        // Downloading data in non-ui thread
        @Override
        protected String doInBackground(String... url) {

            // For storing data from web service
            String data = "";

            try {
                // Fetching the data from web service
                data = downloadUrl(url[0]);
            } catch (Exception e) {
                Log.d("Background Task", e.toString());
            }
            return data;
        }

        // Executes in UI thread, after the execution of
        // doInBackground()
        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);

            ParserTask parserTask = new ParserTask();

            // Invokes the thread for parsing the JSON data
            parserTask.execute(result);

        }
    }

    private class ParserTask extends AsyncTask<String, Integer, List<HashMap<String, String>>> {

        // Parsing the data in non-ui thread
        @Override
        protected List<HashMap<String, String>> doInBackground(String... jsonData) {

            JSONObject jObject;
            List<HashMap<String, String>> routes = null;

            try {
                jObject = new JSONObject(jsonData[0]);
                DistanceTimeParser parser = new DistanceTimeParser();

                // Starts parsing data
                routes = parser.parse(jObject);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return routes;
        }

        // Executes in UI thread, after the parsing process
        @Override
        protected void onPostExecute(List<HashMap<String, String>> result) {

            String duration_distance = "";


            if (result.size() < 1) {
                Log.e("Error : ", "No Points found");
                return;
            }


            String[] date_dist = new String[2];

            // Traversing through all the routes
            for (int i = 0; i < result.size(); i++) {

                // Fetching i-th route
                HashMap<String, String> tmpData = result.get(i);
                Set<String> key = tmpData.keySet();
                Iterator it = key.iterator();
                while (it.hasNext()) {
                    String hmKey = (String) it.next();
                    duration_distance = tmpData.get(hmKey);

                    System.out.println("Key: " + hmKey + " & Data: " + duration_distance);

                    it.remove(); // avoids a ConcurrentModificationException
                }

                date_dist[i] = duration_distance;
            }

            mTaskListener.taskCompleted(date_dist);
        }
    }
}

然后在任何你想显示距离和时间的地方使用下面的代码。 创建一个全局变量,CalculateDistanceTime distance_task; 然后,使用此代码

                    distance_task.getDirectionsUrl(latLng1, latLng2);
                    distance_task.setLoadListener(new CalculateDistanceTime.taskCompleteListener() {
                        @Override
                        public void taskCompleted(String[] time_distance) {
                            v1.setVisibility(View.VISIBLE);
                            text1.setText(time_distance[0]); //Distance
                            text2.setText(time_distance[1]); //Time
                        }
                    });

看,这里的text1和text2是两个textview,分别用来显示距离和时间。

还有,主要是看这里的class调用,distance_task.getDirectionsUrl(latLng1, latLng2);,这里 latLng1 是源,latLng2 是目标,你应该提供这两个 latLng 才能工作。

实际上,您可以在搜索查询中添加参数 getRankingInfo=true,从而在每次命中的响应中找到距离。

我不熟悉 InstantSearch Android,但如果您可以访问原始响应,请查看您的记录中的 _rankingInfo.matchedGeoLocation.distance

{
  [...] // your record fields
  "_rankingInfo": {
    "nbTypos": 0,
    "firstMatchedWord": 0,
    "proximityDistance": 0,
    "userScore": 11,
    "geoDistance": 468,
    "geoPrecision": 1,
    "nbExactWords": 1,
    "words": 1,
    "filters": 0,
    "matchedGeoLocation": {
      "lat": 48.86,
      "lng": 2.3443,
      "distance": 468
    }
  }
}

https://www.algolia.com/doc/guides/searching/geo-search/?language=rails#identifying-the-matching-geo-search-with-rankinginfo

基于@Raphi 的出色回答,以下是使用 InstantSearch Android 显示距离的方法:您只需编写一个 自定义命中 View.

  • 创建 Custom hit view: here a specialized TextView implementing AlgoliaHitView
  • onUpdateView 中,获得 Raphi 推荐的 _rankingInfo.matchedGeoLocation.distance
  • 在您的视图中使用此值,例如 setText(distance + " meters away.")