我從用戶那裏收到了不少OutOfMemoryError報告,每個報告都來自同一個包含MapView的Activity。我認爲這是一個孤立的例外,在我的應用程序中只有這一個地方,我無法弄清楚問題所在。任何人都可以給我一些關於爲何發生這種情況的指示?Android - 許多OutOfMemoryError異常僅在單個Activity中使用MapView
我已經刪除了這個問題的一些不必要的代碼,所以如果有人認爲這個問題可能在這個問題,我會發布它。
棧跟蹤
Stack Trace #1
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:677)
at com.google.android.maps.ZoomHelper.createSnapshot(ZoomHelper.java:444)
at com.google.android.maps.ZoomHelper.beginZoom(ZoomHelper.java:194)
at com.google.android.maps.MapView$2.onScaleBegin(MapView.java:371)
at android.view.ScaleGestureDetector.onTouchEvent(ScaleGestureDetector.java:216)
at com.google.android.maps.MapView.onTouchEvent(MapView.java:646)
at android.view.View.dispatchTouchEvent(View.java:3778)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:920)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:959)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:959)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:959)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1716)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1124)
at android.app.Activity.dispatchTouchEvent(Activity.java:2125)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1700)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1822)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:5068)
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:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)
Stack Trace #2
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
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.MapController.zoomOut(MapController.java:439)
at com.hookedroid.fishingcompanion.GoogleMaps$3.onClick(GoogleMaps.java:133)
at android.view.View.performClick(View.java:2405)
at android.view.View$PerformClick.run(View.java:8813)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4627)
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)
Stack Trace #3
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
at android.graphics.Bitmap.createBitmap(Bitmap.java:435)
at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340)
at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:488)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:462)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:323)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:346)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:372)
at com.hookedroid.fishingcompanion.maps.CrosshairOverlay.draw(CrosshairOverlay.java:32)
at com.google.android.maps.OverlayBundle.draw(OverlayBundle.java:45)
at com.google.android.maps.MapView.onDraw(MapView.java:494)
at android.view.View.draw(View.java:6742)
at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
at android.view.View.draw(View.java:6745)
at android.widget.FrameLayout.draw(FrameLayout.java:352)
at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
at android.view.View.draw(View.java:6745)
at android.widget.FrameLayout.draw(FrameLayout.java:352)
at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1913)
at android.view.ViewRoot.draw(ViewRoot.java:1407)
at android.view.ViewRoot.performTraversals(ViewRoot.java:1163)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1727)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4646)
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:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)
活動
public class GoogleMaps extends MapActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.googlemaps_layout);
intent = getIntent();
currentMode = intent.getIntExtra("MAP_MODE", 0);
initControls();
initMembers();
currentOverlayMode = prefs.getInt("map_viewmode", 0);
populateMap();
}
private void initMembers() {
mDbHelper = new FishingCompanionDB(this);
mDbHelper.open();
catchList = new ArrayList<FishEntry>();
prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefsEditor = prefs.edit();
}
private void initControls() {
mMaps = (MapView)findViewById(R.id.google_maps);
mMaps.setClickable(true);
mMaps.setLongClickable(true);
mapController = mMaps.getController();
mOverlayModeBtn = (Button)findViewById(R.id.googlemaps_overlay_btn);
mOverlayModeBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (currentOverlayMode < 1)
currentOverlayMode++;
else
currentOverlayMode = 0;
switch (currentOverlayMode) {
case OVERLAY_STREET:
mMaps.setSatellite(false);
mMaps.setStreetView(true);
prefsEditor.putInt("map_viewmode", OVERLAY_STREET);
break;
case OVERLAY_SAT:
mMaps.setStreetView(false);
mMaps.setSatellite(true);
prefsEditor.putInt("map_viewmode", OVERLAY_SAT);
break;
}
prefsEditor.commit();
mMaps.invalidate();
}
});
mZoomInBtn = (Button)findViewById(R.id.googlemaps_btn_zoomin);
mZoomInBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mapController.zoomIn();
}
});
mZoomOutBtn = (Button)findViewById(R.id.googlemaps_btn_zoomout);
mZoomOutBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mapController.zoomOut();
}
});
}
private void populateMap() {
overlays = mMaps.getOverlays();
overlays.clear();
overlays.add(new CrosshairOverlay(this, R.drawable.mapcenter));
mSelectPos = (Button)findViewById(R.id.googlemaps_select_location);
mSelectPos.setVisibility(View.VISIBLE);
mSelectPos.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
GeoPoint centerGp = mMaps.getMapCenter();
double lat = centerGp.getLatitudeE6()/1E6;
double lng = centerGp.getLongitudeE6()/1E6;
Intent i;
if (currentMode == SELECT_POS_WEATHER) {
i = new Intent(GoogleMaps.this, WeatherLookup.class);
i.putExtra("WEATHER_LAT", lat);
i.putExtra("WEATHER_LNG", lng);
}
else {
i = new Intent(GoogleMaps.this, AddLocation.class);
i.putExtra("LOCATION_LAT", lat);
i.putExtra("LOCATION_LNG", lng);
}
i.putExtra("MODE", 1);
startActivity(i);
finish();
}
});
mMaps.invalidate();
}
@Override
protected boolean isRouteDisplayed() {
return false;
}
}
十字線疊加
public class CrosshairOverlay extends Overlay {
private Context mContext;
private int resourceId;
public CrosshairOverlay(Context context, int resId) {
this.mContext = context;
this.resourceId = resId;
}
public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
super.draw(canvas, mapView, shadow);
GeoPoint centerGp = mapView.getMapCenter();
Projection projection = mapView.getProjection();
Point centerPoint = projection.toPixels(centerGp, null);
Paint p = new Paint();
Bitmap bmp = BitmapFactory.decodeResource(mContext.getResources(), resourceId);
canvas.drawBitmap(bmp, (centerPoint.x - (bmp.getWidth()/2)), (centerPoint.y - (bmp.getHeight()/2)), p);
return true;
}
}
DUMPSYS meminfo中
** MEMINFO in pid 25493 [com.hookedroid.fishingcompanion] **
native dalvik other total
size: 10036 7495 N/A 17531
allocated: 9955 3965 N/A 13920
free: 80 3530 N/A 3610
(Pss): 3717 1480 6703 11900
(shared dirty): 668 1512 8056 10236
(priv dirty): 3696 804 5024 9524
Objects
Views: 0 ViewRoots: 0
AppContexts: 0 Activities: 0
Assets: 3 AssetManagers: 3
Local Binders: 19 Proxy Binders: 21
Death Recipients: 1
OpenSSL Sockets: 0
SQL
heap: 527 MEMORY_USED: 527
PAGECACHE_OVERFLOW: 62 MALLOC_SIZE: 50
DATABASES
pgsz dbsz Lookaside(b) Dbname
1 16 260 FishingCompanion
1 18 63 google_analytics.db
您是否試圖通過轉儲hprof來分析內存使用情況,並使用內存分析器(如Eclipse Memory Analyzer)分析它?這應該讓你瞭解最大消費的位置,並讓你開始尋找什麼。 – momo
嘗試移動行: 位圖bmp = BitmapFactory.decodeResource(mContext.getResources(),resourceId); out of draw()方法,以便每次調用draw()(它通常是*)時不會重新創建位圖。 – tonys
我會嘗試兩種建議並回報。 – hooked82