2013-02-07 2 views
2

업데이트 (2.8.2013) : 비트 맵의 ​​레슨을 위해 Geobits에 감사드립니다! PNG가 압축 된 형식 (DOH의 순간 중 하나)이라고 생각하지 않았습니다. DAndroid (젤리 전용) - MapActivity 오버레이가 메모리 부족 오류를 일으킴

결국 Android와 Jelly Bean의 이전 버전 간에는 여전히 문제가 있지만 여기에 내 ICS 전화의 힙과 JellyBean 에뮬레이터의 ICS = ICS = < 똑같은 앱, 똑같은 이미지의 경우 6MB, JB => 22MB!

(< 6메가바이트 힙을 사용하여 ICS) :
https://docs.google.com/file/d/0B7GW5mJ5fr3XSTFYWU54VjdUTEk/edit?usp=sharing

(JB 같은 응용 프로그램 - 아래 하나 - 사용> 22메가바이트) :
https://docs.google.com/file/d/0B7GW5mJ5fr3XUGlCdHNMUGJJVFE/edit?usp=sharing

그래서 문제는 남아 ... 무엇입니까 JBoss가 아닌 OOM 조건을 방지하기 위해 이전 버전이 있습니까? 그리고 Tone 해상도를 낮추지 않고 Jelly Bean에서 이것을 어떻게 커버 할 수 있습니까? (JBoss에서 OOM을 피하려면 픽셀 화 된 오버레이로 이동해야합니다)?


MapActivity와 큰 비트 맵 오버레이의 Jelly Bean 관련 문제가 있습니다. Jelly Bean으로 첫 번째 실행에서 힙을 볼 때 ~ 6MB를 차지하는 ICS에 비해 22MB 이상 차지합니다. 비트 맵 크기가 커지면 각 실행마다 비트 맵의 ​​크기에 따라 OOM 오류가 발생하거나 크기가 큰 힙이 생깁니다.

APP 설명 (이 샘플 응용 프로그램은 무엇을)

아래에있는 내 원래의 응용 프로그램은 ... 내가 문제를 복제하고 간단한 코드를 유지하기 위해 아래의 코드로 완전한 기능을 응용 프로그램을했습니다되지 않습니다; 이것은 부모 활동 (Start.java) 및 하위 활동 (MainActivity.java)이있는 응용 프로그램입니다. Start.java는 MainActivity.java를로드하는 버튼이있는 화면입니다 (시간을 절약 할 수있었습니다.).

MainActivity.java는지도를로드하고 하나의 큰 오버레이를 포함합니다. 내 오버레이는 김프에서 필터를 추가 한 GoogleMaps의 NY 일부의 클립으로 다른 점을 알 수 있습니다. 이 오버레이는 "topLeft"GeoPoint와 "bottomRight"GeoPoint에 의해지도에 "고정"되어지도를 확대 할 때 확대됩니다.

비트 맵 크기가 ~ 7MB이므로 ... JellyBean에서 3x (힙은 ~ 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을 시도했습니다

확인할 사항) ... 그것을 나는 오버레이 작게 시도했습니다 2) 드로어 블 폴더 (-ldpi, -mdpi, -hdpi, -xhdpi)의 모든 비트 맵을 넣어 시도 떨어져 OOM 충돌에서 벗어나지 만 여전히 3 배로드 ... 그리고 내 다른 더 복잡한 애플 리케이션이 다른 작은 이미지를 가지고 있기 때문에 이것은 해결책이 아니다 3) 나는 "res/drawable"폴더를 만들고 비트 맵을 넣는 것을 시도했다. MainActivity.jav의 첫 번째로드에서 충돌이 발생합니다. a - 3 배 이상을로드하는 것 같습니다. 4) onDestroy() 메소드에 bitmap.recycle() 추가 - OOM 오류에서이 샘플 응용 프로그램을 유지하지만 언급 한대로 3x MB를 수정해야합니다. 가장.

프로젝트 이름 - 아카이브 TestMapOverlayJB 전체 코드 ZIP - https://docs.google.com/file/d/0B7GW5mJ5fr3XY3h1MmFuREpoaDA/edit?usp=sharing

매니페스트 (마이너스 내 MAP 키는 당신이 당신의 자신을 추가해야합니다)

<?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 :

,210
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

답변

1

문제는 비트 맵이 ~ 7MB 크기가 아니라 PNG 크기가 얼마나 큰지입니다. 16bpp 색상 공간으로 작업하지 않는 한 압축되어 있습니다. 귀하의 이미지는 2800x1324이므로 일반적인 ARGB_8888 형식을 가정하면 압축되지 않은 상태에서 최대 15MB를 차지합니다. 압축 해제 된 비트 맵에 대해 PNG가로드하려면 7을, 압축되지 않은 비트 맵에 대해서는 15를 ... 22로 설정합니다. 따라서 이미지를 메모리로 압축 해제하는 동안 모든 이미지가 사용됩니다.

OOM 오류 (작은 비트 맵, 재활용)를 없애고 시도했지만 "3x"문제를 수정하지 않은 몇 가지 사항을 언급했습니다. Bitmap.Config.RGB_565을 사용하여 이미지를로드 해보십시오. 품질을 희생시키면서 메모리를 절약해야합니다 (약 15MB 정도만 사용해야합니다). 그러나 그 외에는 시도한 것과는 별개로 할 수 없습니다.

+1

당신이 락! 정보 주셔서 감사합니다 ...하지만 다음 질문은 4.0.3 또는 2.2 (그 두 실제 전화가 내가 가진)와 어떤 문제가 없어 왜 그들은 큰 일을 ... – Jed

+1

나는 그것이 주로에 의한 것 같아요. 3D 가속의 사용. 만약 당신이 주위에 방법을 찾을 수 없다면, 당신은 manifest에서'largeHeap'을 가능하게하려고 시도 할 것입니다. 일반적으로 Google에서 권장하지는 않지만 앱에서 절대적으로 필요한 경우 아무 것도없는 것보다 좋습니다. – Geobits

+1

다시 고맙습니다. 그래픽에 대해 배울 점이 많습니다! 수업을 가져 주셔서 감사합니다. – Jed