更新 (2.8.2013): Bitmaps のレッスンについて Geobits に感謝します! PNG が圧縮形式だとは思いませんでした (DOH の瞬間の 1 つ) :D
最後に、古いバージョンの Android と Jelly Bean の間にはまだ問題があります... これは、私の ICS フォンのヒープと JellyBean エミュレーターのスクリーン ショットです... ICS = <6MB、JB = >22MBまったく同じアプリ、まったく同じ画像で!
(6MB 未満のヒープを使用する ICS):
https://docs.google.com/file/d/0B7GW5mJ5fr3XSTFYWU54VjdUTEk/edit?usp=sharing
(JB と同じアプリ - 以下のアプリ - 22MB 以上を使用):
https://docs.google.com/file/d/0B7GW5mJ5fr3XUGlCdHNMUGJJVFE/edit?usp=sharing
そこで疑問が残ります...古いバージョンは、JB がそうではない OOM 状態を防ぐために何をしているのでしょうか? そして、解像度を1トンも下げずにJelly Beanでこれをカバーするにはどうすればよいですか(JBでOOMを回避するには、非常にピクセル化されたオーバーレイに移行する必要があります)?
MapActivity と大きなビットマップ オーバーレイで Jelly Bean 固有の問題が発生しています。Jelly Bean の最初の実行でヒープを見ると、ICS が 6 MB を占めるのに対し、Jelly Bean は 22 MB 以上を占めています。ビットマップが大きくなった後の実行ごとに、ビットマップのサイズに応じて、OOM エラーが発生するか、ヒープが非常に大きくなります。
アプリの説明 (このサンプル アプリの機能)
以下は私のオリジナルのアプリではありません...問題を再現し、コードをシンプルに保つために、以下のコードで完全に機能するアプリを作成しました。これは、親アクティビティ (Start.java) と子アクティビティ (MainActivity.java) を持つアプリケーションです。Start.java は、MainActivity.java をロードするボタンを備えた単なる画面です (私は時間を無駄にしませんでした;)。
MainActivity.java はマップをロードし、1 つの大きなオーバーレイを持ちます。私のオーバーレイは、GIMP でフィルターを追加した GoogleMaps の NY の一部のクリップで、異なることがわかります。このオーバーレイは、「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 )
私が試したことしかし、それでも 3 倍ロードされます...そして、私の他のより複雑なアプリには他の小さな画像があるため、これは解決策ではありません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>
Start.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);
}
}
start.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>
activity_main.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