Google API MapView OutOfMemoryError问题

时间:2011-02-21 12:43:40

标签: android google-maps out-of-memory

我在我的Android应用程序中使用Google API MapView,我发现当我滚动并缩放地图时,它经常会遇到此错误。它们往往很快发生(使用地图20秒)所以我相信这将是一个问题。下面是我的堆栈跟踪。我正在研发具有24MB内存容量的HTC Desire。

我可以采取哪些措施或设置来降低这些错误的频率?

java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    at android.graphics.Bitmap.nativeCreate(Native Method)
    at android.graphics.Bitmap.createBitmap(Bitmap.java:574)
    at com.google.android.maps.ZoomHelper.createSnapshot(ZoomHelper.java:444)
    at com.google.android.maps.ZoomHelper.doZoom(ZoomHelper.java:151)
    at com.google.android.maps.ZoomHelper.doZoom(ZoomHelper.java:140)
    at com.google.android.maps.MapView.doZoom(MapView.java:1478)
    at com.google.android.maps.MapView.doZoom(MapView.java:1487)
    at com.google.android.maps.MapView$6.onZoom(MapView.java:1442)
    at android.widget.ZoomButtonsController$3.onClick(ZoomButtonsController.java:268)
    at android.view.View.performClick(View.java:2408)
    at android.view.View$PerformClick.run(View.java:8817)
    at android.os.Handler.handleCallback(Handler.java:587)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:144)
    at android.app.ActivityThread.main(ActivityThread.java:4937)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:521)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    at dalvik.system.NativeStart.main(Native Method)


debug.heap native: allocated 10.63MB of 11.01MB (385.98KB free)
debug.memory: allocated: 17.95MB of 24.00MB (13.50MB free)

这是我的叠加层。我有大约50个项目,显示一个96x96的png图像,有一些透明度(文件大小为6KB)。

public class StationItemizedOverlay extends ItemizedOverlay<OverlayItem>
{
    private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
    private ArrayList<Location> locations = new ArrayList<Location>();


    private Context mContext;

    public StationItemizedOverlay(Drawable defaultMarker, Context context)
    {
        super(boundCenterBottom(defaultMarker));
        this.mContext = context;
    }

    /**
     * Add a range of locations to this overlay
     * 
     * @param locations The locations to add
     */
    public void addRange(List<Location> locations)
    {
        for (Location l : locations)
        {
            addOne(l);
        }
        populate();
    }

    /**
     * Add a location to this overlay
     * 
     * @param location The location
     */
    public void add(Location location)
    {
        addOne(location);
        populate();
    }

    /**
     * Remove a location from this overlay
     * @param location The location to remove
     */
    public void remove(Location location)
    {
        int position = locations.indexOf(location);

        if (position >= 0)
        {
            mOverlays.remove(position);
            locations.remove(position);
            populate();
        }
    }

    private void addOne(Location location)
    {
        locations.add(location);
        int lat = location.getMicroLatitude();
        int lon = location.getMicroLongitude();
        GeoPoint point = new GeoPoint(lat, lon);
        OverlayItem item = new OverlayItem(point, location.getRealName(), location.getRealName());
        mOverlays.add(item);
    }

    @Override
    protected boolean onTap(int index)
    {
        OverlayItem item = mOverlays.get(index);
        AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
        dialog.setTitle(item.getTitle());
        dialog.setMessage(item.getSnippet());
        dialog.show();
        return true;
    }

    @Override
    protected OverlayItem createItem(int i)
    {
        return mOverlays.get(i);
    }

    @Override
    public int size()
    {
        return mOverlays.size();
    }

}

这是我的MapActivityClass

public class StationFinder extends MapActivity
{
    IUIInterface dataInterface = UIInterfaceFactory.getInterface();

    MapView mapView;

    List<Overlay> mapOverlays;
    Drawable drawable;
    StationItemizedOverlay trainItemizedOverlay;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ui_station_finder);

        mapView = (MapView) findViewById(R.id.stationFinderUI_mapview);
        mapView.setBuiltInZoomControls(true);

        mapOverlays = mapView.getOverlays();
        drawable = getResources().getDrawable(R.drawable.dash_train_btn_default);
        trainItemizedOverlay = new StationItemizedOverlay(drawable, this);

        myMapController = mapView.getController();
        myMapController.setZoom(8); // zoom level selected from google map .com

        // center this location on northern ireland
        centerLocation(Settings.getNorthernIrelandCenter().getGeoPoint());

        mapOverlays.add(trainItemizedOverlay);

        // add data to the adapters only whenever the data is loaded
        if (!dataInterface.isDataLoaded())
        {
            // data is not loaded
            // so make a listener for the data loaded event
            dataLoadedListener = new IEventListener()
            {
                public void action(Object optionalData)
                {
                    // the event has been triggered
                    // register this function to run in the UI thread of the application
                    runOnUiThread(new Runnable()
                    {
                        public void run()
                        {
                            dataLoaded();
                        }
                    });
                }
            };
            // register the listener for data loaded events
            dataInterface.registerDataLoaded(dataLoadedListener);
            // call the data loaded function now incase the data has since been loaded by 
            // the application between registering for the event
            if (dataInterface.isDataLoaded())
            {
                dataLoaded();
            }
        }
        else
        {
            // data already loaded so run immediately
            dataLoaded();
        }



    }

    IEventListener dataLoadedListener = null;
    boolean isDataLoaded = false;

    private void dataLoaded()
    {
        // make sure this function is only called once
        if (isDataLoaded)
            return;
        isDataLoaded = true;

        // IMPORTANT STUFF GOES HERE



        trainItemizedOverlay.addRange(dataInterface.getAllLocations());


        // clean up the data load listener
        if (dataLoadedListener != null)
        {
            dataInterface.removeDataLoaded(dataLoadedListener);
            dataLoadedListener = null;
        }
    }

    private MapController myMapController;

    private void centerLocation(GeoPoint center)
    {
        myMapController.animateTo(center);

        myMapController.setCenter(center);
    };


    @Override
    protected boolean isRouteDisplayed()
    {
        return false;
    }

2 个答案:

答案 0 :(得分:1)

奇怪的是这个问题已经停止了。不确定目前为什么,虽然我最好的猜测是我做的其他一些内存优化使得更大的内存块可用于地图绘制

答案 1 :(得分:0)

这必定是由于您必须使用大量叠加层以及具有较大尺寸且无可绘制重复性的图像的单个叠加层。虽然我们可以更好地回答您是否在此处发布代码...