Android Question Java InLIne Code memory error

Smee

Well-Known Member
Licensed User
Longtime User
Hi,
I am using the excellent code by @Johan Schoeman to create a circular image of a head shot. I am getting an error after only about 6 additions. I am actually refreshing the whole screen rather than just adding views so I suspect that this is the cause but I cannot eliminate the problem. The screen is refreshed because the activity gets called after being sent to the background. This is the error

Error occurred on line: 171 (Main)
java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:131)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:710)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:339)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:249)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:139)
at anywheresoftware.b4a.BA$2.run(BA.java:360)
at anywheresoftware.b4a.BA.setActivityPaused(BA.java:432)
at aus.anyfcsapp.joe.main$ResumeMessage.run(main.java:306)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5602)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.OutOfMemoryError
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:928)
at android.graphics.Bitmap.createBitmap(Bitmap.java:901)
at android.graphics.Bitmap.createBitmap(Bitmap.java:868)
at aus.anyfcsapp.joe.main.getRoundBitmap(main.java:1238)
... 23 more

B4X:
        If File.Exists(File.DirAssets,msgTitle & ".png") Then
            bmpName = LoadBitmapSample(File.DirAssets, msgTitle & ".png", 200dip, 200dip)
        Else
            bmpName = LoadBitmapSample(File.DirAssets, "Smiley.png", 200dip, 200dip)
        End If
       
        Log(msgTitle & bmpName)
        bmpName = nativeMe.RunMethod("getRoundBitmap",Array(bmpName))
[code/]

Can anyone shed any light on how to fix this?

Many Thanks
 

JordiCP

Expert
Licensed User
Longtime User
You should only perform this operation once, regardless how often your screen is refreshed
Declare bmpName as a process global var.
B4X:
Sub Process_Globals
   Dim bmpName as Bitmap
End Sub

Sub Activity_Create
   If FirstTime=True then
     If File.Exists(File.DirAssets,msgTitle & ".png") Then
       bmpName = LoadBitmapSample(File.DirAssets, msgTitle & ".png", 200dip, 200dip)
     Else
       bmpName = LoadBitmapSample(File.DirAssets, "Smiley.png", 200dip, 200dip)
     End If
     Log(msgTitle & bmpName)
     bmpName = nativeMe.RunMethod("getRoundBitmap",Array(bmpName))
      
   End If
   '...
End Sub

Anyway, this should not happen and possibly something else is "eating" your memory somewhere else.

I have downloaded @Johan Schoeman 's code and this function returns a 1000x1000 bitmap, which is about 4MBytes. The code seems totally correct, and the 1000x1000 size itself is not the cause...but perhaps if you are calling it several times from other places, then it can be an issue.

Try with the solution above, and changing the lines in the inline Java part to get a smaller bitmap
B4X:
  public static Bitmap getRoundBitmap(Bitmap scaleBitmapImage) {
     int targetWidth = 400;      //1000;   <--- just play with these 2 lines, since you don't need such a big bitmap.
     int targetHeight = 400;     //1000;
     Bitmap targetBitmap = Bitmap.createBitmap(targetWidth, targetHeight,
         Bitmap.Config.ARGB_8888);
     //....
 
Upvote 0

Smee

Well-Known Member
Licensed User
Longtime User
Thanks very much for your quick reply Jordi, I cannot put the code in activity create because it is part of a loop. that is to say the image name changes many times and is in a custom listview. the smiley.png is a default if the correct png does not exist. I will play around with that code and see what happens
 
Upvote 0

Smee

Well-Known Member
Licensed User
Longtime User
That change has certainly allowed me to add more panels and images to the list but is there a way to re-initialise each time i make a new call?
You are right, I missed it.

Anyway, how many images are you using?

I would envisage no more than 100 and they are only thumbnails really so memory should not be a problem
 
Upvote 0

JordiCP

Expert
Licensed User
Longtime User
I would envisage no more than 100 and they are only thumbnails really so memory should not be a problem
Consider that even if your images on screen are just thumbnails, the bitmap that you were creating was 1000x1000x4 = 4MBytes. Then the container view just scales it down to be shown on screen, but each bitmap still uses all that memory.

So, for each device, if the thumbnail size is for instance 100dip, I would do (modifying a bit the Java code)
B4X:
  Dim w as int = 100dip   'or whatever is the thumbnail size
  Dim h as int = 100dip   'or whatever
  '....
   bmpName = nativeMe.RunMethod("getRoundBitmap",Array(bmpName,w,h))
  ' ...

#if JAVA
//...
'slightly modify Johan's code signature
public static Bitmap getRoundBitmap(Bitmap scaleBitmapImage, int targetWidth, int targetHeight ) {
   // targetWidth and targetHeight are no more local variables, but passed as parameters.
   Bitmap targetBitmap = Bitmap.createBitmap(targetWidth, targetHeight,Bitmap.Config.ARGB_8888);
   //....
}
#End if

Also, if the smiley is used more than once, I would create it just once at the beginning and then assign the same bitmap to all the views that need a smiley
 
Upvote 0

eps

Expert
Licensed User
Longtime User
What are the dimensions of the thumbnails? This is the key to memory usage in Android with bitmaps.

The name of the image can be the same - surely you just place it in the CustomListView and then place the next one.

We'd need to see a little more code if this doesn't work for you....
 
Upvote 0

Smee

Well-Known Member
Licensed User
Longtime User
[QUOTE="
Also, if the smiley is used more than once, I would create it just once at the beginning and then assign the same bitmap to all the views that need a smiley[/QUOTE]

Thanks jordi for all that help, I will be implementing those suggestions
 
Upvote 0

Smee

Well-Known Member
Licensed User
Longtime User
they would probably average about 200x200 each
 
Upvote 0

eps

Expert
Licensed User
Longtime User
I use something like this to populate a ListView, so similar...

B4X:
   For i = 0 To Cursor2.RowCount - 1

      Cursor2.Position = i

      TempPNG = LoadBitmapSample(File.DirAssets, Cursor2.GetInt("series_no") & "_logo.png",128,128)

      ListView2.AddTwoLinesAndBitmap(Cursor2.GetString("series"), "", TempPNG)       

    Next
 
Upvote 0

Smee

Well-Known Member
Licensed User
Longtime User
Yes mine is almost the same except for tempPNG mine is called bmpName but the logic is the same
 
Upvote 0

Smee

Well-Known Member
Licensed User
Longtime User
Also said:
That has given me an idea with all the other bitmaps. Thanks very much guys. Sometimes it's hard to see the forest for the trees
 
Upvote 0

eps

Expert
Licensed User
Longtime User
It seems counter-intuitive - everything your brain is telling you is wrong sometimes is right when developing for Android!! I really struggled with the memory use of bitmaps!!
 
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…