更新(2.8.2013):感谢 Geobits 的位图课程!我不认为 PNG 是一种压缩格式(那些 DOH 时刻之一):D
最后,虽然旧版本的 Android 和 Jelly Bean 之间仍然存在问题...这是我的 ICS 手机上的堆屏幕截图和 JellyBean 模拟器上的屏幕截图...ICS = <6MB,JB = >22MB对于完全相同的应用程序,完全相同的图像!
(ICS 使用 <6MB 堆):
https ://docs.google.com/file/d/0B7GW5mJ5fr3XSTFYWU54VjdUTEk/edit?usp=sharing
(JB 相同的应用程序 - 下面的一个 - 使用 >22MB):
https ://docs.google.com/file/d/0B7GW5mJ5fr3XUGlCdHNMUGJJVFE/edit?usp=sharing
所以问题仍然存在……旧版本在做什么来防止 JB 没有的 OOM 条件?以及如何在不降低分辨率的情况下在 Jelly Bean 中覆盖这一点(我必须深入到非常像素化的叠加层以避免 JB 中的 OOM)?
我遇到了 MapActivity 和大型位图覆盖的 Jelly Bean 特定问题。当查看第一次运行 Jelly Bean 时的堆占用超过 22MB 时,与占用约 6MB 的 ICS 相比。在它增长后的每次运行中,根据你的位图的大小,它会给你一个 OOM 错误或者只是有一个超大的堆。
应用程序描述(此示例应用程序的作用)
下面这不是我的原始应用程序...我制作了一个功能齐全的应用程序,下面的代码可以复制问题并保持代码简单;这是一个具有父活动 (Start.java) 和子活动 (MainActivity.java) 的应用程序。Start.java 只是一个带有按钮的屏幕,它将加载 MainActivity.java(我在时间上不遗余力;)。
MainActivity.java 将加载地图并有一个大的覆盖。我的叠加层是来自 GoogleMaps 的纽约部分剪辑,我在 GIMP 中添加了一个过滤器,因此您可以看出它不同。然后,此叠加层由“topLeft”GeoPoint 和“bottomRight”GeoPoint “固定”到地图,因此当您在地图上缩放时它会缩放。
位图大约 7MB 大......所以看起来 JellyBean 将它加载了 3 倍(堆大约为 22MB)。看着堆,我看到它从 8MB 开始,然后迅速移动到 16MB 和 22MB。它也位于“res/drawable-nodpi”文件夹中。
我在以前的版本中看到了这个问题,“修复”是将位图放在“drawable-nodpi”中,这就是它存在的原因,但是对于 JellyBean,这种多重加载又回来了(旧问题链接:https://stackoverflow. com/questions/13906037/android-mapactivity-overlay-bitmap-not-relasing-memory-when-finish-executes)
我尝试过的事情 1) 尝试将位图放在所有可绘制文件夹中(-ldpi、-mdpi、-hdpi、-xhdpi) 2) 我尝试过使覆盖更小......它确实远离 OOM 崩溃但是仍然加载 3 倍……由于我的其他更复杂的应用程序有其他更小的图像,这不是解决方案 3)我尝试创建一个“res/drawable”文件夹并将位图放入其中,它在第一次加载时崩溃MainActivity.java - 似乎加载超过 3x) 4) 在 onDestroy() 方法中添加了 bitmap.recycle() - 这确实使此示例应用程序免受 OOM 错误但如上所述,我需要占用 3x MB修复最多。
项目名称 - TestMapOverlayJB 完整代码 ZIP 存档(减去我的 MAP 密钥 - 您需要添加自己的) https://docs.google.com/file/d/0B7GW5mJ5fr3XY3h1MmFuREpoaDA/edit?usp=sharing
显现
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testmapoverlayjb"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.INTERNET"/>
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="16" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<uses-library android:name="com.google.android.maps"/>
<activity
android:name=".Start"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity" />
<activity android:name=".MyBaseImageOverlay" />
</application>
</manifest>
启动.java:
package com.example.testmapoverlayjb;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class Start extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.start);
Button buttonMainMenuSettings = (Button) findViewById(R.id.buttonNY);
buttonMainMenuSettings.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
Intent myIntent = new Intent(Start.this, MainActivity.class);
startActivity(myIntent);
}
catch (ActivityNotFoundException e) {
Toast.makeText(getBaseContext(), "Activity Not Found", Toast.LENGTH_SHORT).show();
}
}});
}
}
MainActivity.java:
package com.example.testmapoverlayjb;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import android.os.Bundle;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.Menu;
public class MainActivity extends MapActivity {
Bitmap bitmapMapOverlay;
MyBaseImageOverlay baseLargeOverlay;
MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
GeoPoint topLeft = new GeoPoint((int)40723714, (int)-74029412);
GeoPoint bottomRight = new GeoPoint((int)40704522, (int)-73976011);
bitmapMapOverlay = BitmapFactory.decodeResource(getResources(), R.drawable.ny_base1);
baseLargeOverlay = new MyBaseImageOverlay(topLeft, bottomRight, bitmapMapOverlay);
mapView.getOverlays().add(baseLargeOverlay);
MapController mapController = mapView.getController();
mapController.setZoom(16);
mapController.setCenter(new GeoPoint((int)40715029,(int)-74001975));
mapView.setSatellite(true);
mapView.setStreetView(false);
mapView.postInvalidate();
}
@Override
protected boolean isRouteDisplayed() {
return false;
}
@Override
protected void onDestroy() {
bitmapMapOverlay.recycle();
baseLargeOverlay = null;
mapView = null;
super.onDestroy();
}
}
MyBaseImageOverlay.java:
package com.example.testmapoverlayjb;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
public class MyBaseImageOverlay extends Overlay {
private Bitmap baseBitmap;
GeoPoint topLeft;
GeoPoint bottomRight;
public MyBaseImageOverlay(GeoPoint topL, GeoPoint bottomR, Bitmap bmp) {
baseBitmap = bmp;
topLeft = topL;
bottomRight = bottomR;
}
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
if(shadow) {
return;
}
super.draw(canvas, mapView, shadow);
// convert bitmap's bounding box into pixels
Point top_left = new Point();
mapView.getProjection().toPixels(topLeft, top_left);
Point bottom_right = new Point();
mapView.getProjection().toPixels(bottomRight, bottom_right);
// Prepare two rectangles (pixels)
Rect src = new Rect( 0,0,baseBitmap.getWidth() - 1, baseBitmap.getHeight() - 1 );
Rect dst = new Rect( top_left.x, top_left.y, bottom_right.x,bottom_right.y );
// draw bitmap
canvas.drawBitmap(baseBitmap, src, dst, null);
}
}
开始.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/buttonNY"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:text="NY" />
</RelativeLayout>
活动主.xml:
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
android:apiKey="YOUR_MAP_KEY_HERE"
/>
叠加位图: https ://docs.google.com/file/d/0B7GW5mJ5fr3XZFdWYnVBUW45bWM/edit?usp=sharing