创建没有谷歌地图参考的标记(谷歌地图标记)对象

Posted

技术标签:

【中文标题】创建没有谷歌地图参考的标记(谷歌地图标记)对象【英文标题】:Creating Marker (Google Map Markers) object without Google Map reference 【发布时间】:2018-09-26 18:57:25 【问题描述】:

我知道周围有类似的问题,但我无法找到可靠的答案,这是我的问题:有什么方法可以在没有 Google Map 参考的情况下将标记存储在 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

【问题讨论】:

这没有帮助,显示一些你的代码。 @GhulamMoinulQuadir 我在问题中添加了一些代码。 只需添加有限数量的标记并启动一个合理的计时器并重复直到全部添加。 @Andy 我不认为这是一个好的解决方案。它可能会在未来产生更多问题。标记的数量是随时间不断增加的动态数字。 (数据库不断更新)。 【参考方案1】:

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

YourActivity.this.runOnUiThread(new Runnable()
 public void run()
//paste your code here.
);

【讨论】:

我添加了onMapReady @Houde:你的意思是我应该使用这段代码用 MainActivity 中的标记填充我的地图吗?因为我不能在 MarkerLoader 中使用 runOnThread 我的意思是使用 asynctask 是个坏主意,女巫是简单的网络操作,不需要下载大量数据,而不是你不需要使用它来管理你的代码以传递标记列表以适当的方式并在 MainActivity 中使用 runOnThread。 看看这个***.com/questions/12797550/… 另一种方法medium.com/@yossisegev/…希望对您有所帮助。

以上是关于创建没有谷歌地图参考的标记(谷歌地图标记)对象的主要内容,如果未能解决你的问题,请参考以下文章

Android 谷歌地图标记禁用导航选项

自动调整缩放以适应谷歌地图中的所有标记

带有 3D 标记的 Android 谷歌地图?

如何快速隐藏谷歌地图标记

我的搜索没有在谷歌地图中显示他们的标记有啥问题?

怎么在谷歌地图上做标记呀