How to free memory in Android application

opsl63-2
opsl63-2 used Ask the Experts™
on
Hi,

I'm working on an Android application and I have a complex layout in which I want to overlay several ImageViews (using it as layers).

Here is the code of my layout :
 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="fill_parent" 
	android:layout_height="fill_parent"
	android:gravity="center_horizontal"
	android:background="@drawable/bg_repeat"
	android:id="@+id/cuisson_layout">
		<ImageView android:id="@+id/bulle"
			android:gravity="top"
			android:layout_width="fill_parent" 
			android:layout_height="103dp"
			android:src="@drawable/bulle_abc"/>
		<ImageView android:id="@+id/fond" 
			android:gravity="top"
			android:layout_width="fill_parent" 
			android:layout_height="308dp"
			android:src="@drawable/fond_rond"
			android:layout_below="@id/bulle"/>
		<ImageView android:id="@+id/separations" 
			android:gravity="top"
			android:layout_width="fill_parent" 
			android:layout_height="308dp"
			android:layout_below="@id/bulle"/>
		<ImageView android:id="@+id/pictos" 
			android:gravity="top"
			android:layout_width="fill_parent" 
			android:layout_height="308dp"
			android:layout_below="@id/bulle"/>
		<ImageView android:id="@+id/rond_vert" 
			android:gravity="top"
			android:layout_width="fill_parent" 
			android:layout_height="308dp"
			android:layout_below="@id/bulle"/>
		<ImageView android:id="@+id/masque" 
			android:gravity="top"
			android:layout_width="fill_parent" 
			android:layout_height="308dp"
			android:layout_below="@id/bulle"/>
		<ImageView android:id="@+id/bouton" 
			android:gravity="top"
			android:layout_width="fill_parent" 
			android:layout_height="308dp"
			android:layout_below="@id/bulle"/>
		<TextView android:id="@+id/timer" 
			android:gravity="center"
			android:layout_width="fill_parent" 
			android:layout_height="308dp"
			android:layout_below="@id/bulle"
			android:textSize="25dp"
			android:textColor="#fff"
			android:textStyle="bold"/>
		<ImageView android:id="@+id/conseil" 
			android:gravity="top"
			android:layout_width="fill_parent" 
			android:layout_height="308dp"
			android:layout_below="@id/bulle"/>
		<ImageView android:id="@+id/curseur" 
			android:gravity="top"
			android:layout_width="fill_parent" 
			android:layout_height="308dp"
			android:layout_below="@id/bulle"/>
		<ImageView android:id="@+id/message"
			android:gravity="top"
			android:layout_width="fill_parent" 
			android:layout_height="109dp"
			android:src="@drawable/message_bas_a"
			android:layout_below="@id/fond"/>
</RelativeLayout>

Open in new window


I use a many fonctions like this one to change sources of imageViews :
private void display3E()
    {
    	bulle.setImageResource(R.drawable.bulle_e);
    	bouton.setImageResource(R.drawable.bt_check);
    	conseil.setImageResource(R.drawable.conseil_e);
    	separations.setImageResource(R.drawable.separations);
    	rondVert.setImageResource(R.drawable.rond_vert);
    	messageBas.setImageResource(R.drawable.message_bas_e);
    	masque.setImageResource(0);
    	timer.setText("");
    }

Open in new window


But i'm getting memory allocation issues. Here is the log :
10-16 14:16:40.008: ERROR/dalvikvm-heap(737): 662400-byte external allocation too large for this process.
10-16 14:16:40.008: ERROR/GraphicsJNI(737): VM won't let us allocate 662400 bytes
10-16 14:16:40.008: DEBUG/AndroidRuntime(737): Shutting down VM
10-16 14:16:40.008: WARN/dalvikvm(737): threadid=1: thread exiting with uncaught exception (group=0x4001d7f0)
10-16 14:16:40.018: ERROR/AndroidRuntime(737): FATAL EXCEPTION: main
10-16 14:16:40.018: ERROR/AndroidRuntime(737): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.graphics.Bitmap.nativeCreate(Native Method)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.graphics.Bitmap.createBitmap(Bitmap.java:435)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:488)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:462)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:323)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.content.res.Resources.loadDrawable(Resources.java:1709)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.content.res.Resources.getDrawable(Resources.java:581)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.widget.ImageView.resolveUri(ImageView.java:489)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.widget.ImageView.setImageResource(ImageView.java:274)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at com.overscan.myapp.CuissonActivity.display3C(CuissonActivity.java:592)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at com.overscan.myapp.CuissonActivity.access$9(CuissonActivity.java:584)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at com.overscan.myapp.CuissonActivity$2.handleMessage(CuissonActivity.java:295)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.os.Handler.dispatchMessage(Handler.java:99)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.os.Looper.loop(Looper.java:123)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at android.app.ActivityThread.main(ActivityThread.java:4627)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at java.lang.reflect.Method.invokeNative(Native Method)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at java.lang.reflect.Method.invoke(Method.java:521)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
10-16 14:16:40.018: ERROR/AndroidRuntime(737):     at dalvik.system.NativeStart.main(Native Method)
10-16 14:16:40.038: WARN/ActivityManager(92):   Force finishing activity com.overscan.myapp/.CuissonActivity

Open in new window


I use png images (because I need transparency).
The weight of all png displayed at the same time in a layout is about 200Ko.
Is there a better way to manage a layout like mine ?
Is there a way to free memory from unused bitmaps ?

Thanks for your help.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Commented:
I would say do not load all of your images in your layout.  I would each image location with src=@+id/variable instead of @drawable/image and then set the resource/image in code as you need it.  If this is not really clear I can try to get you a code snippet.  I have done this sort of thing and even though I have 20+ images available I only have 4 displayed at a time and reuse the same layout.xml  You have to run through the code when the activity is loaded to set default images to be displayed, but this keeps the actual drawables from being declared in your layout.

It also seems that many of your image views do not define a 'src'  This may or may not be a problem.  As said above I alway define a source even if it is a +id and not a drawable.

I hope this helps.

Author

Commented:
I didn't know that we could use a @+id/variable in the src attribute of an imageview.
Is this id has to be the same id as the imageview id ?
I would really appreciate an example snippet if you have one.
I will try to remove all @drawable from my layout.

Thanks for your help.
Commented:
Sorry for the delay.

Basically you know how you do not put the text in the XML layout?  You create a string and tent reference the string by ID?  You do the same for the graphic, but you set it from in the code.

Here is the entry in the layout XML:
<ImageView  
    android:id="@+id/back_image"
>

Here is a sample of some code I am using to update a Widget.  You will need to change what and how you are updating, but you can see how I reference the graphic resource (R.id.back_image) and then set it to the graphic (R.drawable.clock_modern_2_face) stored in the variable 'face':

Intent intent = new Intent(context, Tabs.class);
          intent.setData(ContentUris.withAppendedId(Uri.EMPTY,mAppWidgetId));
            intent.putExtra("face", face); //Variable that holds my graphic like face = R.drawable.clock_modern_2_face
          PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
          RemoteViews remoteView = new RemoteViews(context.getPackageName(), layout); // I am working with Widgets here, so ignore that I am using RemoteViews
          remoteView.setImageViewResource(R.id.back_image, face);

you also may need to set defaults for the graphics when you activity loads so it looks nice before user choices or program logic makes the first graphical change.

HTH

Commented:
Please let me know how these tips worked for you.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial