Android: программно освободить ресурсы памяти растрового изображения

У меня есть диалог, в котором пользователи могут свободно рисовать внутри диалогового окна.

Диалог расширяет представление, а область рисования создается

bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); 

Тем не менее, чертеж не нужно сохранять, и когда пользователь закрывает диалоговое окно и снова открывает его, его предыдущий чертеж не требуется хранить и перерисовывать с нуля.

Подробные коды:

DoodleView:

  // DoodleView constructor initializes the DoodleView public DoodleView(Context context, AttributeSet attrs) { super(context, attrs); // pass context to View's constructor paintScreen = new Paint(); // used to display bitmap onto screen // set the initial display settings for the painted line paintLine = new Paint(); paintLine.setAntiAlias(true); // smooth edges of drawn line paintLine.setColor(Color.BLACK); // default color is black paintLine.setStyle(Paint.Style.STROKE); // solid line paintLine.setStrokeWidth(25); // set the default line width paintLine.setStrokeCap(Paint.Cap.ROUND); // rounded line ends pathMap = new HashMap<Integer, Path>(); previousPointMap = new HashMap<Integer, Point>(); } // end DoodleView constructor // Method onSizeChanged creates BitMap and Canvas after app displays @Override public void onSizeChanged(int w, int h, int oldW, int oldH) { bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); bitmapCanvas = new Canvas(bitmap); bitmap.eraseColor(Color.parseColor("#80FFFFFF")); // erase the BitMap with white } // end method onSizeChanged // clear the painting public void recycling() { bitmap.recycle(); } 

Письменная доска:

 public void write_board () { writing_dialog = new Dialog(Apple.this, android.R.style.Theme_Translucent_NoTitleBar); WindowManager.LayoutParams lp = writing_dialog.getWindow().getAttributes(); lp.dimAmount = 0.5f; writing_dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); Window window = writing_dialog.getWindow(); window.setGravity(Gravity.CENTER); writing_dialog.setContentView(R.layout.alert_drawing_pad); writing_dialog.setCancelable(true); writing_dialog.show(); writing_dialog.setVolumeControlStream(AudioManager.STREAM_MUSIC); doodleView = (DoodleView) writing_dialog.findViewById(R.id.doodleView); alert_close.setOnClickListener(new OnClickListener() { public void onClick(View v) { writing_dialog.dismiss(); doodleView.recycling(); return; } }); 

Вопрос:

Я обнаружил, что после открытия диалога несколько раз (от 7 до 8 раз с использованием Samsung Note2), диалог будет отставать в течение нескольких секунд, а телефон без ответа, а затем еще раз нажать несколько раз позже, диалог может появиться снова, и все будет ОК.

Логарифм в данный момент сообщает E/OpenGLRenderer(25296): Out of memory!

И он продолжается, не повесив какое-то время.

Тем не менее, если в дальнейшем нажать на чертежную доску, это приведет к серьезной ошибке памяти, и на этот раз система зависает.

 FATAL EXCEPTION: main java.lang.OutOfMemoryError at android.graphics.Bitmap.nativeCreate(Native Method) at android.graphics.Bitmap.createBitmap(Bitmap.java:726) at android.graphics.Bitmap.createBitmap(Bitmap.java:703) at android.graphics.Bitmap.createBitmap(Bitmap.java:670) at com.abc.abc.DoodleView.onSizeChanged(DoodleView.java:60) at android.view.View.sizeChange(View.java:15326) at android.view.View.setFrame(View.java:15290) at android.view.View.layout(View.java:15201) at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1076) at android.view.View.layout(View.java:15204) at android.view.ViewGroup.layout(ViewGroup.java:4793) at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1076) at android.view.View.layout(View.java:15204) at android.view.ViewGroup.layout(ViewGroup.java:4793) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:15204) at android.view.ViewGroup.layout(ViewGroup.java:4793) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1677) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1531) at android.widget.LinearLayout.onLayout(LinearLayout.java:1440) at android.view.View.layout(View.java:15204) at android.view.ViewGroup.layout(ViewGroup.java:4793) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:15204) at android.view.ViewGroup.layout(ViewGroup.java:4793) at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2263) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2009) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1251) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6379) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:791) at android.view.Choreographer.doCallbacks(Choreographer.java:591) at android.view.Choreographer.doFrame(Choreographer.java:561) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:777) at android.os.Handler.handleCallback(Handler.java:730) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5493) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:525) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025) at dalvik.system.NativeStart.main(Native Method) 

Я исследовал и добавил
bitmap.recycle(); Когда пользователь закрывает диалог. Но он по-прежнему сообщает о той же ошибке.

Есть ли способ распоряжаться растровым изображением всякий раз, когда пользователь закрывает диалог?

Благодаря!

Вы должны вызвать это при отключении вашего диалога

 bitmap.recycle(); bitmap = null; 

bitmap.recycle(); Выпускает встроенную кучу, которая используется в растровых изображениях. И установка его на нуль – это помочь GC быстро собрать вашу ссылку.

Сначала аннулируем ссылку, которую холст или любой другой объект должен растроить

 if (bitmapCanvas != null) { bitmapCanvas.setBitmap(null); bitmapCanvas = null; } 

Вторичные растровые ресурсы

 if (bitmap != null) { bitmap.recycle(); bitmap = null; } 

Если необходимо, в-третьих, сохраните растровое изображение как WeakReference

 WeakReference<Bitmap> bitmap; if (bitmap != null) { bitmap.get().recycle(); bitmap.clear(); bitmap= null; } 

Похоже, в памяти должно быть только одно растровое изображение. Несколько мыслей.

Во-первых, при переработке растрового изображения его значение равно null, а также значение canvas равно null. Если это не решит проблему, мне будет интересно увидеть код, который вы используете, чтобы на самом деле рисовать линии. Также получение дампа кучи после вызова диалогового окна и его закрытия покажет вам, какие объекты все еще находятся в памяти, и вы можете быстро отследить, что держится за растровое изображение, и это любопытное удовольствие 🙂

Этот пост – отличное начало при расследовании кучи кучи, если вы этого еще не сделали.

ОБНОВИТЬ

Чтобы установить холст в значение null, вы можете сделать что-то вроде этого

 public void recycling() { bitmap.recycle(); bitmap = null; bitmapCanvas = null; } 

Однако при ближайшем рассмотрении вашего кода я вижу, что вы каждый раз создаете новый диалог, а затем отклоняете диалог. Это не освободит диалог из памяти. Попробуйте обновить код, чтобы вы только инициализировали диалог, если он равен нулю.

 public void write_board () { if(writing_dialog == null){ writing_dialog = new Dialog(Apple.this, android.R.style.Theme_Translucent_NoTitleBar); WindowManager.LayoutParams lp = writing_dialog.getWindow().getAttributes(); lp.dimAmount = 0.5f; writing_dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); Window window = writing_dialog.getWindow(); window.setGravity(Gravity.CENTER); writing_dialog.setContentView(R.layout.alert_drawing_pad); writing_dialog.setCancelable(true); writing_dialog.setVolumeControlStream(AudioManager.STREAM_MUSIC); } //now do stuff with your dialog writing_dialog.show(); doodleView = (DoodleView) writing_dialog.findViewById(R.id.doodleView); 

Растровая память выдает довольно распространенную проблему. Попробуйте некоторые из решений этой темы

Странная проблема с памятью при загрузке изображения в объект Bitmap