android - Google Maps Android API 性能极差

标签 android google-maps

我目前正在尝试编写一个使用标记在 map 上显示多个位置的应用程序。即使只使用一组相对“小”的标记(我已经看到人们想要绘制超过 100k 的 StackOverflow 问题),我的性能也很糟糕,我的 map 需要几秒钟才能移动。

我还有我的 GPU 分析的屏幕截图,我想知道是否有人能理解为什么这些调用如此之高:

Screenshot of GPU profiling on-screen

我尝试使用 DDMS 分析我的应用程序,但这似乎没有给我任何决定性的答案。

我使用的代码如下:

tab_map.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment xmlns:android="http://schemas.android.com/apk/res/android"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        class="com.google.android.gms.maps.SupportMapFragment"
        android:id="@+id/city_map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingTop="?attr/actionBarSize" />
</FrameLayout>

LocationFragment.java

/* a whole list of imports and package definition */

/**
 * Created by Ruben on 05-08-17.
 */

public class LocationsFragment extends Fragment
        implements OnMapReadyCallback {
    private static final String TAG = LocationsFragment.class.getSimpleName();

    private LocationsFragment instance;

    private City city;
    private List<Marker> markers;
    private List<Location> locations;

    private Target iconTarget;

    private GoogleMap map;
    private SupportMapFragment mapFragment;
    private BitmapDescriptor markerIcon;
    private Bitmap markerIconBitmap;

    private ApiService apiService;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.tab_map, null);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceStace) {
        super.onActivityCreated(savedInstanceStace);

        // Set up the view
        instance = this;

        mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.city_map);
        apiService = RestClient.getClient(getContext()).create(ApiService.class);
        city = getArguments().getParcelable("city");
        markers = new ArrayList<>();

        iconTarget = new Target() {
            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                markerIconBitmap = bitmap;
                updateMarkerIcons();
            }

            @Override
            public void onBitmapFailed(Drawable errorDrawable) {
            }

            @Override
            public void onPrepareLoad(Drawable placeHolderDrawable) {

            }
        };

        // Start async processes
        // Load Google map
        mapFragment.getMapAsync(this);

        // Load locations from API
        getLocations();

        // Load custom marker for city
        getCityMarker();

    }

    private void getCityMarker() {
        Picasso
                .with(getContext())
                .load(city.getMarker().getUrl())
                .resize(ScreenUtils.convertDIPToPixels(getContext(), 24), ScreenUtils.convertDIPToPixels(getContext(), 24))
                .into(iconTarget);
    }

    @Override
    public void onMapReady(GoogleMap map) {
        this.map = map;

        if(markerIconBitmap == null) {
            markerIcon = BitmapDescriptorFactory.fromAsset("default1.png");
        }else{
            markerIcon = BitmapDescriptorFactory.fromBitmap(markerIconBitmap);
        }

        if (ContextCompat.checkSelfPermission(this.getContext(), "ACCESS_FINE_LOCATION") == PackageManager.PERMISSION_GRANTED) {
            map.setMyLocationEnabled(true);
        } else {
            Toast.makeText(instance.getContext(), getString(R.string.no_location_permission), Toast.LENGTH_LONG).show();
        }

        map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(city.getCenter().getLat(), city.getCenter().getLong()), 12));

        setMarkers();
    }

    public void getLocations() {
        Call<LocationsResponse> call = apiService.getLocations(city.getId());
        call.enqueue(new Callback<LocationsResponse>() {
            @Override
            public void onResponse(Call<LocationsResponse> call, Response<LocationsResponse> response) {
                if(response.code() != 200) {
                    Toast.makeText(instance.getContext(), getString(R.string.retrieving_locations) + "1", Toast.LENGTH_LONG).show();
                    return;
                }

                Log.d(TAG, "Received locations: " + response.body().getLocations().size());
                locations = response.body().getLocations();

                setMarkers();
            }

            @Override
            public void onFailure(Call<LocationsResponse> call, Throwable t) {
                t.printStackTrace();
                Toast.makeText(instance.getContext(), getString(R.string.retrieving_locations) + "1", Toast.LENGTH_LONG).show();
            }
        });
    }

    public void setMarkers() {
        Log.d(TAG, "Calling setMarkers");
        if(map != null && locations != null) {
            // Remove all the old markers
            if(!markers.isEmpty()) {
                int numMarkers = markers.size();
                for(int i = 0; i < numMarkers; i++) {
                    markers.get(i).remove();
                }
                markers.clear();
            }

            // Create a new marker for each location
            int numLocations = locations.size();
            Log.d(TAG, "Setting markers for " + numLocations + " locations");
            for(int i = 0; i < numLocations; i++) {
                Location location = locations.get(i);
                markers.add(map.addMarker(
                    new MarkerOptions()
                        .position(new LatLng(location.getPosition().getLat(), location.getPosition().getLong()))
                        //.icon(markerIcon)
                        //.title(location.getName())
                        //.snippet(getString(R.string.location_marker_text, NumberFormat.getInstance().format(location.getStones())))
                ));
            }
        }
    }

    public void updateMarkerIcons() {
        Log.d(TAG, "Calling updateMarkerIcons");
        if(map != null && markerIconBitmap != null) {
            markerIcon = BitmapDescriptorFactory.fromBitmap(markerIconBitmap);
        }

        if(map != null && !markers.isEmpty()) {
            int numMarkers = markers.size();
            for(int i = 0; i < numMarkers; i++) {
                Marker marker = markers.get(i);
                //marker.setIcon(markerIcon);
            }
        }
    }

    @Override
    public void onDestroyView() {
        Picasso.with(this.getContext()).cancelRequest(iconTarget);

        mapFragment.onDestroyView();

        super.onDestroyView();
    }

    public void updateLocations() {
        if(locations != null) {
            getLocations();
        }
    }

    public void setCity(City city) {
        this.city = city;
        getCityMarker();
    }
}

如您所见,我取消了一些为标记设置 .snippet.icon 的行的注释,因为我怀疑这可能是问题所在。遗憾的是,这似乎不是问题所在。

使用断点,我试图确认我设置/编辑标记的函数都没有在它们应该被调用之后被调用,我发现这绝对不是这种情况。设置标记后,不会在此文件中执行其他代码。我的所有其他 Activity 似乎都运行良好,因此我开始相信这是与 Google map 相关的问题。值得注意的是,当我离开标记时,即不再处于屏幕边界内时,性能还不错,滚动看起来很流畅。

最佳答案

很抱歉回答晚了,您可能已经找到了解决方案,但它可能会对其他人有所帮助。

你有没有考虑过Clusters

你遇到的问题是它需要大量资源来渲染 map 上的所有这些标记,并且每次你的 View 移动时 api 都会重新渲染。

当很多引脚非常靠近时,您无法真正区分它们。默认情况下,集群会根据 map 上的缩放比例对它们进行分组,以优化渲染和可视化。 如果默认行为或外观不符合您的口味,您可以轻松覆盖它。

希望我有所帮助。

关于android - Google Maps Android API 性能极差,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45527939/

相关文章:

Android Fragments - 多个 Activity 还是一个?

android - On Activity 结果未调用且未找到错误源

java - Java 文件中的安全 key ,如来自黑客的 API key 等

android setOnInfoWindowClickListener - 传递更多值

android - 试图捕捉音量 onKeyLongPress() 不工作

java - Android 中无需登录的 Firebase OTP 验证

javascript - 如何更改谷歌地图绘图管理器工具栏工具提示?

javascript - 使用 JQuery 获取 Google Maps 对象的实例

javascript - 通过 jQuery 访问 Google map 变量

ios - 如何使位置自动完成文本框 Swift ios 8