在没有Google地图参考的情况下创建标记(Google地图标记)对象

时间:2018-04-16 22:55:47

标签: java android google-maps

我知道周围有类似的问题,但我无法找到一个可靠的答案,这是我的问题:我有没有办法让没有谷歌地图参考的标记存储在ArrayList(或任何其他存储),然后只需将它们添加到我的地图?

背景: 我有一个应用程序,目前有大约3,500个标记。每个标记还有一个与之关联的数据(布尔数组存储每个标记的数据,用于根据用户交互使它们可见/不可见)。目前,我使用扩展AsyncTask的类获取这些标记的位置和数据。加载完成后,我使用主线程上的这些数据创建我的标记。但是,这需要一些时间,并且在创建标记并将其添加到地图时冻结UI。我想在后台以某种方式做到这一点。

到目前为止我尝试了什么: 我创建了另一个扩展AsyncTask的类,它传递了我的LocationData和我的Google Map对象。但是当我尝试在Async类中创建标记时出现错误。我收到运行时错误,说我需要在UI线程上执行此操作。

  

java.lang.RuntimeException:执行时发生错误   doInBackground()

     

引起:com.google.maps.api.android.lib6.common.apiexception.c:不   在主线程上

我还考虑过在后台制作MarkerOptions对象,然后用它在主线程中创建标记;但是,我无法在MarkerOption中添加标签,需要将其添加到标记中。在这种情况下,我需要在主线程中再次浏览所有这些,只是为了添加标签,我觉得这不会为我节省太多时间/资源。

如何创建这些标记并附加其标记而不阻止UI,我们将不胜感激任何建议/帮助?

提前致谢。

以下是我的一些代码:

LocationLoader类 (BinLocation是我的Location类,每个对象都有布尔变量(标记标记)和LatLng)     公共类LocationLoader扩展AsyncTaskLoader> {

    private String TAG = LocationLoader.class.getName();
    String[] fileNameArray;

    //ArrayLists
    private ArrayList<BinLocation> mBinLocationArrayList = new ArrayList<>();

    public LocationLoader(Context context, String... fileNames){
        super(context);
        //get the file names that was passed in
        fileNameArray = fileNames;
    }//LocationLoader

    @Override
    protected void onStartLoading() {
        Log.v(TAG, "onStartLoading called");
        forceLoad();
    }//onStartLoading

    @Override
    public ArrayList<BinLocation> loadInBackground() {
        Log.v(TAG, "loadInBackground called");
        String path = "/storage/emulated/0/";
        File file;
        String output = "";

        //Read data from file
        for (int i = 0; i < fileNameArray.length; i++) {
            file = new File(path + fileNameArray[i]);
            try (Scanner scanner = new Scanner(file)) {
                //first line of the text, containing the location and version
                output = scanner.nextLine();
                String prefix = (output.split(":"))[0];
                String line;
                while (scanner.hasNextLine()) {
                    line = scanner.nextLine();
                    String inputArray[] = line.split(",");
                    BinLocation binLocation = new BinLocation(
                            prefix + "-" + inputArray[0],
                            Double.parseDouble(inputArray[1]),
                            Double.parseDouble(inputArray[2]),
                            Integer.parseInt(inputArray[3].trim()),
                            Integer.parseInt(inputArray[4].trim()),
                            Integer.parseInt(inputArray[5].trim()),
                            Integer.parseInt(inputArray[6].trim()));
                    mBinLocationArrayList.add(binLocation);
                }//while
            } catch (Exception e) {
                Log.e(TAG, "File read error: ", e);
            }
        }//for
        Log.v(TAG, "readLocation finished");
        Log.v(TAG, "ArrayList size: " + mBinLocationArrayList.size());
        return mBinLocationArrayList;
    }//loadInBackground
}//LocationLoader class

这是我的MarkerLoader类(我试过这个并得到了doInBackground()错误)。此外,现在没有代码可以将数据添加到标记中,但是在将其添加到地图后它就会在循环中出现问题。

public class MarkerLoader extends AsyncTaskLoader<ArrayList<Marker>> {

    private GoogleMap map;

    private ArrayList<Marker> mMarkerArrayList = new ArrayList<>();

    private ArrayList<MyLocation> mBinLocationArrayList = new ArrayList<>();

    public MarkerLoader (Context context, GoogleMap map, ArrayList<BinLocation> binLocationArrayList) {
        super(context);
        this.map = map;
        this.mBinLocationArrayList = binLocationArrayList;

    }//MarkerLoader

    @Override
    protected void onStartLoading() {
        Log.v(TAG, "onStartLoading called");
        forceLoad();
    }//onStartLoading

    @Override
    public ArrayList<Marker> loadInBackground() {
        Log.v(TAG, "loadInBackground called");
        Marker marker;
        for (BinLocation binLocation : mMyLocationArrayList) {
            marker = map.addMarker(new MarkerOptions()
            .position(binLocation.getPosition()));
            mMarkerArrayList.add(marker);
        }
        Log.v(TAG, "loadInBackground finished, with: " + mMarkerArrayList.size());


        return mMarkerArrayList;
    }
}

这是主Activity中的辅助函数(populateMap()),它生成标记并将它们保存在ArrayList中

private void populateMap() {
    if (!checkMapReady() || !mMapIsEmpty) {
        return;
    }//if Map Not ready

//Initialize ArrayList
mMarkerArrayList = new ArrayList<>();

/**
 * This part uses the loop to go through each MyLocation object in the ArrayList, extract
 * all the data, and set the markers
 */

//Check to make sure the BinLocation ArrayList is not empty otherwise we will crash
if (mBinLocationArrayList.isEmpty()) {
    Log.w(TAG, "populateMap() terminated, mBinLocationArrayList empty");
    return;
}//if BinLocation empty

//Safety check to clear the map before populating it
mMap.clear();

//create a markerMyLocation object
Marker mMaker;
//This goes through the ArrayList for every MyLocation object and sets up the markerMyLocation
for (BinLocation binLocation : mBinLocationArrayList) {
    //get boolean values
    boolean[] booleanValues = {binLocation.getGarbage(), binLocation.getContainer(),
            binLocation.getPaper(), binLocation.getCompost()};

    //Set different icon
    switch (markerIconPreference) {
        case "customIcon":
            //custom icon
            //Decide what icon to use
            if (booleanValues[0] && !booleanValues[1] && !booleanValues[2] && !booleanValues[3]) {
                //Make a new MarkerOptions object to add the data
                //garbage markers
                mMaker = mMap.addMarker(new MarkerOptions()
                        .title(binLocation.getId())
                        .position(binLocation.getPosition())
                        .icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_garbage))
                        .visible(garbageVisible));

            } else {
                //Make a new MarkerOptions object to add the data
                //recycling markers
                mMaker = mMap.addMarker(new MarkerOptions()
                        .title(binLocation.getId())
                        .position(binLocation.getPosition())
                        .icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_recycling))
                        .visible(recyclingVisible));
            }
            //Add our boolean array as an object to our markerMyLocation
            mMaker.setTag(booleanValues);
            //Add the markerMyLocation to the ArrayList
            mMarkerArrayList.add(mMaker);
            break;
        case "coloredTeardrop":
            //teardrop icon
            //Decide what icon to use
            if (booleanValues[0] && !booleanValues[1] && !booleanValues[2] && !booleanValues[3]) {
                //Make a new MarkerOptions object to add the data
                //garbage markers
                mMaker = mMap.addMarker(new MarkerOptions()
                        .title(binLocation.getId())
                        .position(binLocation.getPosition())
                        .visible(garbageVisible));
            } else {
                //Make a new MarkerOptions object to add the data
                //recycling markers
                mMaker = mMap.addMarker(new MarkerOptions()
                        .title(binLocation.getId())
                        .position(binLocation.getPosition())
                        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN))
                        .visible(recyclingVisible));
            }
            //Add our boolean array as an object to our markerMyLocation
            mMaker.setTag(booleanValues);
            //Add the markerMyLocation to the ArrayList
            mMarkerArrayList.add(mMaker);
            break;
    }//switch
}//for
//disable the progress bar
mProgressBar.setVisibility(View.GONE);
//De-activate the CountDown timer since the map is ready
mCountDownTimer.cancel();
//set the boolean to false
mMapIsEmpty = false;

Log.v(TAG, "populateMap finished. Markers: " + mMarkerArrayList.size());
}//populateMap

这是onMapReady函数

public void onMapReady(GoogleMap map) {
    Log.v(TAG, "onMapReady called");
    mMap = map;

    //Setup on map loaded
    mMap.setOnMapLoadedCallback(this);

    //Check to see if the map is empty and the location array list is not empty and then call populateMap
    if (mMapIsEmpty && !mBinLocationArrayList.isEmpty()) {
        populateMap();
    }//if map empty

//set bounds
mMap.setLatLngBoundsForCameraTarget(GREATER_VANCOUVER_BOUND);
//Set min zoom level to match the bound
mMap.setMinZoomPreference(10.0f);

//disable map toolbar
UiSettings mUiSettings = mMap.getUiSettings();
mUiSettings.setMapToolbarEnabled(false);

//Set listeners
mMap.setOnMarkerClickListener(this);
mMap.setOnInfoWindowCloseListener(this);
mMap.setOnInfoWindowClickListener(this);

// Setting our custom info window, passing out helper method
mMap.setInfoWindowAdapter(new CustomInfoWindowAdapter());

//Here we check for permission and setup the map accordingly
if (!checkLocationPermission()) {
    //Permission is not granted, log, and use the default location
    Log.v(TAG, "No location permission");
    //setup default map
    defaultMapSetup();
} else {
    Log.v(TAG, "Location permission granted");
    //Enable my location and initialize the map there
    mMap.setMyLocationEnabled(true);

    //Setup the map
    locationMapSetup();
}//if -permission
}//onMapReady

1 个答案:

答案 0 :(得分:0)

尝试在另一个线程中创建标记

const response = function*() {
    yield takeEvery(action => (action.type === "CLIENT_RESPONSE" && !action.error), handleResponse);
}