我的 UI 使用带距离矩阵的 AsyncTask 和 google 地图被阻止

My UI is blocked using AsyncTask with distancematrix and google Maps

我正在使用 google 地图来显示一些标记。标记是从数据库下载的,同时,我从 google api 获取用户当前位置与我从数据库中获取的标记之间的距离矩阵。

我的问题是我是用 .get 做的,阻塞了我的 ui(我读过 .get 阻塞了 ui:

dataFromAsyncTask = testAsyncTask.get();

现在,我试图在不阻挡 ui 的情况下做同样的事情,但我无法同时或以一种好的方式获得此标记的距离。

感谢您的帮助。

这是我的旧代码和错误代码.get:

 for (City city : listCity.getData()) {
        geoPoint = city.getLocation();
    nameBeach = city.getName();

    if (geoPoint == null) {

    } else {
        latitude = String.valueOf(geoPoint.getLatitude());
        longitude = String.valueOf(geoPoint.getLongitude());

        startRetrievenDistanceAndDuration();

        try {
            dataFromAsyncTask = testAsyncTask.get();
        } catch (InterruptedException i) {

        } catch (ExecutionException e) {
        }

        mMap.addMarker(new MarkerOptions().position(new LatLng(geoPoint.getLatitude(), geoPoint.getLongitude()))
                .title(nameCity)
                .snippet(dataFromAsyncTask)
                .icon(BitmapDescriptorFactory.defaultMarker()));
    }
}

startRetrievenDistanceAndDuration 方法:

private void startRetrievenDistanceAndDuration() {
final String url;

testAsyncTask = new DistanceBetweenLocations(new FragmentCallback() {

    @Override
    public void onTaskDone(String result) {

    }
});
url = "https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + currentLatitude + "," + currentlongitude + "&destinations=" + latitude + "," + longitude + "&key=xxx";
testAsyncTask.execute(new String[]{url});
}
public interface FragmentCallback {
    public void onTaskDone(String result);

AsyncTask class:

        @Override
        protected String doInBackground(String... params) {
            HttpURLConnection urlConnection = null;
            URL url = null;
            StringBuilder result = null;
            String duration = "";
            String distance = "";

            try {
                url=new URL(params[0]);
            }catch (MalformedURLException m){

            }
            try {
                urlConnection = (HttpURLConnection) url.openConnection();
            }catch (IOException e){}

            try {
                InputStream in = new BufferedInputStream(urlConnection.getInputStream());
                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                result = new StringBuilder();
                String line;
                while((line = reader.readLine()) != null) {
                    result.append(line);
                }
            }catch (IOException e){

            } finally {
                urlConnection.disconnect();
            }

            try {
                JSONObject jsonObject = new JSONObject(result.toString());
                JSONArray jsonArray = jsonObject.getJSONArray("rows");
                JSONObject object_rows = jsonArray.getJSONObject(0);
                JSONArray jsonArrayElements = object_rows.getJSONArray("elements");
                JSONObject  object_elements = jsonArrayElements.getJSONObject(0);
                JSONObject object_duration = object_elements.getJSONObject("duration");
                JSONObject object_distance = object_elements.getJSONObject("distance");

                duration = object_duration.getString("text");
                distance = object_distance.getString("text");

            } catch (JSONException e) {
                e.printStackTrace();
            }

            return distance + ", " + duration;

        }

        @Override
        protected void onPostExecute(String result) {
            mFragmentCallback.onTaskDone(result);
        }
}

我正在尝试这样做,但我只显示列表的最后一个标记:

循环调用方法:

startRetrievenDistanceAndDuration();

然后在 onTaskDone 中尝试放置标记,但只得到我列表中的最后一个标记

@Override
            public void onTaskDone(String result) {
                mMap.addMarker(new MarkerOptions().position(new LatLng(geoPoint.getLatitude(), geoPoint.getLongitude()))
                        .title(nameBeach)
                        .snippet(result)
                        .icon(BitmapDescriptorFactory.defaultMarker()));

            }

更改后更新:(仍然不起作用) 我可以在 Asynctask 中解析数据并在 onPostExecute 中发送它,但我只得到一个值,而不是我拥有的 9 个值....

主要ACTIVITY:

DistanceBetweenLocations task = new DistanceBetweenLocations(mlatituDouble, mlongitudeDouble){
                    @Override
                    protected void onPostExecute(HashMap<String, String> result) {
                        super.onPostExecute(result);

                        String name = result.get("beachName");
                        String distance = result.get("distance");
                        String duration = result.get("duration");
                        String latitue = result.get("latitude");
                        String longitude = result.get("longitude");

                        Double mlatituDouble = Double.parseDouble(latitue);
                        Double mlongitudeDouble = Double.parseDouble(longitude);


                        if (mMap == null) {

                            mMap = ((SupportMapFragment) getFragmentManager().findFragmentById(R.id.mapView))
                                    .getMap();

                                Toast.makeText(getActivity(), "mMap NO null", Toast.LENGTH_SHORT).show();
                                mMap.addMarker(new MarkerOptions().position(new LatLng(mlatituDouble, mlongitudeDouble))
                                        .title(name)
                                        .snippet(distance + " " + duration)
                                        .icon(BitmapDescriptorFactory.defaultMarker()));
                        }
                    }
                };

                task.execute();

异步任务CLASS:.

public class DistanceBetweenLocations extends AsyncTask<String, String, HashMap<String, String>> {

    Double currentLatitude;
    Double currentlongitude;
    public BeachMap beachMap;
    public BackendlessCollection<Beach> dataBeach;
    public GoogleMap mMap;
    String latitude;
    String longitude;
    HashMap<String, String> map;

    public DistanceBetweenLocations(Double currentLatitude, Double currentlongitude){
        this.currentLatitude = currentLatitude;
        this.currentlongitude = currentlongitude;
    }

    @Override
    protected HashMap<String, String> doInBackground(String... params) {

        dataBeach = beachMap.listBeach;

        for (Beach city : dataBeach.getData()) {
            GeoPoint geoPoint = city.getLocation();
            String nameBeach = city.getName();

            if (geoPoint == null) {

            } else {
                latitude = String.valueOf(geoPoint.getLatitude());
                longitude = String.valueOf(geoPoint.getLongitude());

                HttpURLConnection urlConnection = null;
                URL url = null;
                StringBuilder result = null;
                String duration = "";
                String distance = "";

                try {
                    url = new URL("https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + currentLatitude + "," + currentlongitude + "&destinations=" + latitude + "," + longitude + "&key=xxxx");
                } catch (MalformedURLException m) {

                }
                try {
                    urlConnection = (HttpURLConnection) url.openConnection();
                } catch (IOException e) {
                }

                try {
                    InputStream in = new BufferedInputStream(urlConnection.getInputStream());
                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                    result = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        result.append(line);
                    }
                } catch (IOException e) {

                } finally {
                    urlConnection.disconnect();
                }

                try {
                    JSONObject jsonObject = new JSONObject(result.toString());
                    JSONArray jsonArray = jsonObject.getJSONArray("rows");
                    JSONObject object_rows = jsonArray.getJSONObject(0);
                    JSONArray jsonArrayElements = object_rows.getJSONArray("elements");
                    JSONObject object_elements = jsonArrayElements.getJSONObject(0);
                    JSONObject object_duration = object_elements.getJSONObject("duration");
                    JSONObject object_distance = object_elements.getJSONObject("distance");

                    duration = object_duration.getString("text");
                    distance = object_distance.getString("text");


                    map = new HashMap<String, String>();
                    map.put("beachName", nameBeach);
                    map.put("distance", distance);
                    map.put("duration", duration);
                    map.put("latitude", latitude);
                    map.put("longitude", longitude);


                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }
        return map;
    }

}

我不太确定你想做什么,但我认为你已经把它弄得更复杂了。

据我了解,您有一个 City 对象列表,您使用它们构建一些 URL,从中检索用于构建 MarkerOptions 对象的 JSON 对象.

您可以像这样使用 AsyncTask 来做到这一点:

public class Task extends AsyncTask<City, Void, Markers> {

    String currentLatitude;
    String currentlongitude;

    public Task(String currentLatitude, String currentlongitude){
        this.currentLatitude = currentLatitude;
        this.currentlongitude = currentlongitude;
    }

    @Override
    protected String doInBackground(City... cities) {
        final Markers mMap = ...;
        for (City city : cities) {
            GeoPoint geoPoint = city.getLocation();
            String nameBeach = city.getName();

            if (geoPoint != null) {
                String latitude = String.valueOf(geoPoint.getLatitude());
                String longitude = String.valueOf(geoPoint.getLongitude());

                HttpURLConnection urlConnection = null;
                BufferedReader reader = null;
                try {
                    URL url = new URL("https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + currentLatitude + "," + currentlongitude + "&destinations=" + latitude + "," + longitude + "&key=xxx";);
                    urlConnection = (HttpURLConnection) url.openConnection();
                    reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
                    StringBuilder result = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        result.append(line);
                    }
                    JSONObject jsonObject = new JSONObject(result.toString()).getJSONArray("rows").getJSONObject(0).getJSONArray("elements").getJSONObject(0);
                    String duration = jsonObject.getJSONObject("duration").getString("text");
                    String distance = jsonObject.getJSONObject("distance").getString("text");

                    mMap.addMarker(new MarkerOptions().position(new LatLng(geoPoint.getLatitude(), geoPoint.getLongitude()))
                            .title(nameBeach)
                            .snippet(distance + ", " + duration)
                            .icon(BitmapDescriptorFactory.defaultMarker()));
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if(reader!=null){
                        try {
                            reader.close();
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                    if (urlConnection != null) {
                        try {
                            urlConnection.disconnect();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }

        return mMap;
    }
}

这里是你如何使用这个任务。

public class Login extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(...);
        Task task = new Task(currentLatitude, currentlongitude){
            @Override
            protected void onPostExecute(Markers markers) {
                super.onPostExecute(markers);
                //This runs on the UI thread and "markers" is the "mMap" object that was create on the background thread.
            }
        };
        List<City> cities = ....
        task.execute(cities.toArray(new City[cities.size()]));
    }
}

想法是您需要在 AsyncTaskdoInBackground(...) 方法中执行所有长的 运行 操作。此外,您不需要创建其他对象来处理 AsyncTask 响应,您可以在您创建任务的 class 中覆盖任务的 onPostExecute(...)

我会用你最后的代码("UPDATED AFTER CHANGES"),好吗?

如果我做对了,您的 DistanceBetweenLocations 结果将是海滩地理定位数据列表。因此,在 doInBackground 中 for 循环的每次迭代中,您都在替换 "map" 变量的值,这就是您的问题。

要解决您的问题,您可以使用 HashMap 列表或 Pojo 列表,如下所示:

public class BeachPojo {
    private String beachName;
    private String distance;
    private String duration;
    private String latitude;
    private String longitude;

    public String getBeachName() {
        return beachName;
    }

    public void setBeachName(String beachName) {
        this.beachName = beachName;
    }

    public String getDistance() {
        return distance;
    }

    public void setDistance(String distance) {
        this.distance = distance;
    }

    public String getDuration() {
        return duration;
    }

    public void setDuration(String duration) {
        this.duration = duration;
    }

    public String getLatitude() {
        return latitude;
    }

    public void setLatitude(String latitude) {
        this.latitude = latitude;
    }

    public String getLongitude() {
        return longitude;
    }

    public void setLongitude(String longitude) {
        this.longitude = longitude;
    }
}

使用 Pojo,你的 AsyncTask 将是这样的:

public class DistanceBetweenLocations extends AsyncTask<String, String, List<BeachPojo>> {

    Double currentLatitude;
    Double currentlongitude;
    public BeachMap beachMap;
    public BackendlessCollection<Beach> dataBeach;
    public GoogleMap mMap;
    String latitude;
    String longitude;


    public DistanceBetweenLocations(Double currentLatitude, Double currentlongitude){
        this.currentLatitude = currentLatitude;
        this.currentlongitude = currentlongitude;
    }

    @Override
    protected List<BeachPojo> doInBackground(String... params) {
        List<BeachPojo> list = new ArrayList<BeachPojo>();
        BeachPojo pojo;

        dataBeach = beachMap.listBeach;

        for (Beach city : dataBeach.getData()) {
            GeoPoint geoPoint = city.getLocation();
            String nameBeach = city.getName();

            if (geoPoint == null) {
            } else {
                latitude = String.valueOf(geoPoint.getLatitude());
                longitude = String.valueOf(geoPoint.getLongitude());

                HttpURLConnection urlConnection = null;
                URL url = null;
                StringBuilder result = null;
                String duration = "";
                String distance = "";

                try {
                    url = new URL("https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + currentLatitude + "," + currentlongitude + "&destinations=" + latitude + "," + longitude + "&key=xxxx");
                } catch (MalformedURLException m) {

                }

                try {
                    urlConnection = (HttpURLConnection) url.openConnection();
                } catch (IOException e) {
                }

                try {
                    InputStream in = new BufferedInputStream(urlConnection.getInputStream());
                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                    result = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        result.append(line);
                    }
                } catch (IOException e) {

                } finally {
                    urlConnection.disconnect();
                }

                try {
                    JSONObject jsonObject = new JSONObject(result.toString());
                    JSONArray jsonArray = jsonObject.getJSONArray("rows");
                    JSONObject object_rows = jsonArray.getJSONObject(0);
                    JSONArray jsonArrayElements = object_rows.getJSONArray("elements");
                    JSONObject object_elements = jsonArrayElements.getJSONObject(0);
                    JSONObject object_duration = object_elements.getJSONObject("duration");
                    JSONObject object_distance = object_elements.getJSONObject("distance");

                    duration = object_duration.getString("text");
                    distance = object_distance.getString("text");

                    pojo = new BeachPojo();
                    pojo.setBeachName(nameBeach);
                    pojo.setDistance(distance);
                    pojo.setDuration(duration);
                    pojo.setLatitude(latitude);
                    pojo.setLongitude(longitude);

                    list.add(pojo);

                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }
        return list;
    }
}

现在您有一个要迭代的列表。我已经为这个目标稍微调整了代码:

DistanceBetweenLocations task = new DistanceBetweenLocations(mlatituDouble, mlongitudeDouble){
    @Override
    protected void onPostExecute(List<BeachPojo> result) {
        super.onPostExecute(result);

        if (mMap == null) {
            mMap = ((SupportMapFragment) getFragmentManager().findFragmentById(R.id.mapView))
                    .getMap();
        }

        Double beachLatitude;
        Double beachLongitude;

        for (BeachPojo pojo : result) {
            beachLatitude = Double.parseDouble(pojo.getLatitude());
            beachLongitude = Double.parseDouble(pojo.getLongitude());

            mMap.addMarker(new MarkerOptions().position(new LatLng(beachLatitude, beachLongitude))
                .title(pojo.getBeachName())
                .snippet(pojo.getDistance() + " " + pojo.getDuration())
                .icon(BitmapDescriptorFactory.defaultMarker()));
        }
    }
};

task.execute();

我希望您理解从 AsyncTask 返回列表并在 onPostExecute 方法上循环遍历结果的想法。

注意:这是在不知道真正代码的情况下实现的,请根据实际情况进行调整。