2013-02-07 69 views
2

更新(2.8.2013):感謝您在Gemap中學習Bitmap課程!我沒有想到PNG是一種壓縮格式(DOH時刻之一):DAndroid(僅限Jelly Bean) - MapActivity Overlay會導致內存不足錯誤

最後,儘管老版本的Android和Jelly Bean之間仍然存在問題......下面是一個屏幕截圖堆在我的ICS手機和一個在果凍豆模擬器... 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條件?我怎樣在Jelly Bean中覆蓋這個,而不降低TON的分辨率(爲了避免在JB中使用OOM,我必須去掉像素化的覆蓋圖)?


我在使用MapActivity和大型位圖疊加層時遇到了Jelly Bean特定問題。在第一輪看Jelly Bean時,堆佔用了22MB,而ICS佔用了大約6MB。在增長後的每次運行中,根據你的位圖的大小,它會給你一個OOM錯誤或者只是有一個超大的堆。

APP DESCRIPTION(此示例應用程序做什麼)

下面是不是我原來的應用程序......我做了下面的代碼複製的問題,並保持代碼的簡潔的全功能應用此;這是一個具有父活動(Start.java)和子活動(MainActivity.java)的應用程序。 Start.java只是一個帶有加載MainActivity.java的按鈕的屏幕(我不惜時間花費);

MainActivity.java將加載地圖並有一個大的覆蓋。我的覆蓋圖是來自GoogleMaps的紐約州的一部分剪輯,我在GIMP中添加了一個篩選器,因此您可以告訴它不同。然後通過「topLeft」GeoPoint和「bottomRight」GeoPoint將此疊加層「固定」到地圖上,以便在縮放地圖時縮放。

位圖大小約爲7MB ......所以看起來JellyBean的加載速度是3x(Heap是〜22MB)。看着堆,我看到它開始在8MB,然後迅速移動到16MB的012MB22MB。它也位於「res/drawable-nodpi」文件夾中。

我看到了以前的版本&這一問題的「修復」是把位圖的「繪製-nodpi」這就是爲什麼住在這裏,但豆形軟糖這多工又回來了(老問題鏈接: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的第一次加載時崩潰一個 - 似乎加載超過3倍) 4)在onDestroy()方法中增加了一個bitmap.recycle() - 這確實使這個示例應用程序不受OOM錯誤的影響,但如前所述,這是需要修復的3倍數據塊最。

項目名稱 - 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

回答

1

問題是,你的位圖不是~7MB大,你的PNG有多大。它被壓縮(除非你使用16bpp色彩空間)。你的圖像是2800x1324,所以假設一個正常的ARGB_8888格式,它應該佔用約15MB的未壓縮。 7爲PNG加載,加上15爲未壓縮的位圖...來到22.因此,在這段時間內它將圖像解壓縮到內存中,它將使用所有這些。

你提到了幾個你試過的東西,擺脫了OOM錯誤(較小的位圖,回收),但沒有解決「3x」問題。您可以嘗試使用Bitmap.Config.RGB_565加載圖像。這應該以犧牲質量爲代價節省一些內存(應該只使用總共大約15MB),但除此之外,除了你嘗試過的東西之外你不能做很多事情。

+1

你搖滾!感謝您的信息...但接下來的問題是爲什麼這不會有任何問題與4.0.3或2.2(這是我的兩個實際的手機),他們工作很好... – Jed

+1

我認爲這主要是由於使用3D加速無處不在。如果你根本找不到解決方法,你可以嘗試在清單中啓用'largeHeap'。一般不建議谷歌,但如果你的應用程序絕對需要它,總比沒有好。 – Geobits

+1

再次,謝謝!我正在學習我有很多要學習圖形的知識!感謝您的教訓! – Jed

相關問題