2

更新 (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

4

1 に答える 1

1

問題は、ビットマップが最大 7MB ではなく、PNG がどれだけ大きいかということです。圧縮されています (16bpp 色空間で作業している場合を除く)。画像は 2800x1324 であるため、通常の ARGB_8888 形式を想定すると、非圧縮で最大 15MB を占めるはずです。PNG を読み込むには 7、圧縮されていないビットマップには 15 を加えます... 22 になります。したがって、画像をメモリに解凍している間、そのすべてを使用することになります。

OOMエラー(ビットマップの縮小、リサイクル)を取り除くために試したいくつかのことについて言及しましたが、「3x」の問題は修正されませんでした。Bitmap.Config.RGB_565を使用して画像を読み込んでみることができます。これにより、品質を犠牲にしてメモリを節約できます (合計で約 15MB しか使用しないはずです)。

于 2013-02-07T22:15:55.633 に答える