Android Question java.lang.IllegalArgumentException

Filippo

Expert
Licensed User
Hello,

With this class I can customize the lyrics of Label and Button, and it actually works very well.
In Google Report comes but from time to time this crash report.

Class clsTextResizer:
B4X:
Sub Class_Globals
    Private bmp As Bitmap
    Private cvs As Canvas

    Private stu As StringUtils
    Private dt As Float
    Private h, Height As Int
    Private w, Width As Int
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
    bmp.InitializeMutable(1dip, 1dip)
    cvs.Initialize2(bmp)
End Sub

#Region TextSize vom Label, EditText und Button ändern

'Der Parameter "Scale" bei Buttons nicht verwendet!
Public Sub SetTextSize(obj As View, txt As String, scale As Float, singleline As Boolean)
    'Log("SetTextSize: txt=" & txt & " :obj=" & obj)

    'WICHTIG! Die Width darf nicht weniger als null sein!
    If obj.Width < 1dip Then Return

    setSingleLine(obj, singleline)

    If obj Is Button Then
        Dim btn As Button = obj
        Height = btn.Height - 14dip
        Width = btn.Width - 10dip

        SetButtonTextSize(btn, txt)
    Else
        Dim lbl As Label = obj
        Height = lbl.Height * scale
        Width = lbl.Width - 5dip
        
        SetLabelTextSize(lbl, txt)
    End If
End Sub

'Sets the TextView to single line
Public Sub setSingleLine(TextView As View, SingleLine As Boolean)
    Dim jo = TextView As JavaObject
    jo.RunMethod("setSingleLine", Array As Object(SingleLine))
End Sub

Private Sub SetButtonTextSize(btn As Button, txt As String)   
    btn.TextSize = 6
    dt = btn.TextSize
    h = stu.MeasureMultilineTextHeight(btn, txt)
    w = cvs.MeasureStringWidth(txt, btn.Typeface, dt)
    Do While h <= Height
        dt = dt + 1
        btn.TextSize = dt
        h = stu.MeasureMultilineTextHeight(btn, txt)
        w = cvs.MeasureStringWidth(txt, btn.Typeface, dt)
        
        If w >= Width Or h > Height Then
            btn.TextSize = dt - 2
            Exit
        End If
    Loop
End Sub

Private Sub SetLabelTextSize(lbl As Label, txt As String)   
    lbl.TextSize = 6
    dt = lbl.TextSize
    h = stu.MeasureMultilineTextHeight(lbl, txt)
    w = cvs.MeasureStringWidth(txt, lbl.Typeface, dt)
    Do While h <= Height
        dt = dt + 1
        lbl.TextSize = dt
        h = stu.MeasureMultilineTextHeight(lbl, txt)
        w = cvs.MeasureStringWidth(txt, lbl.Typeface, dt)

'        Log(txt & ": w=" & w & " ;h=" & h)
'        Log(txt & ": Width=" & Width & " ;Height=" & Height)
    
        If w > Width Or h > Height Then
            lbl.TextSize = dt - 1
            Exit
        End If
    Loop
End Sub

#End Region

12. Okt. 09:06 in der App-Version 25
Samsung Galaxy J1 Ace (j1acevelte), Android 5.1
Bericht 1 von 2
java.lang.IllegalArgumentException
:
at android.text.Layout.<init> (Layout.java:142)
at android.text.StaticLayout.<init> (StaticLayout.java:107)
at android.text.StaticLayout.<init> (StaticLayout.java:93)
at android.text.StaticLayout.<init> (StaticLayout.java:71)
at android.text.StaticLayout.<init> (StaticLayout.java:51)
at anywheresoftware.b4a.objects.StringUtils.MeasureMultilineTextHeight (StringUtils.java:50)
at fg.MasterOfRegolarity.clstextresizer._vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv6 (clstextresizer.java:84)
at fg.MasterOfRegolarity.clstextresizer._vvvvvvvvvvvvvvvvvvvvv3 (clstextresizer.java:171)
at fg.MasterOfRegolarity.main._activity_create (main.java:525)
at java.lang.reflect.Method.invoke (Native Method)
at java.lang.reflect.Method.invoke (Method.java:372)
at anywheresoftware.b4a.BA.raiseEvent2 (BA.java:191)
at fg.MasterOfRegolarity.main.afterFirstLayout (main.java:104)
at fg.MasterOfRegolarity.main.access$000 (main.java:17)
at fg.MasterOfRegolarity.main$WaitForLayout.run (main.java:82)
at android.os.Handler.handleCallback (Handler.java:739)
at android.os.Handler.dispatchMessage (Handler.java:95)
at android.os.Looper.loop (Looper.java:145)
at android.app.ActivityThread.main (ActivityThread.java:6934)
at java.lang.reflect.Method.invoke (Native Method)
at java.lang.reflect.Method.invoke (Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1404)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1199)


It would be nice if someone might find the mistake.
 

Attachments

  • clstextresizer.java
    13 KB · Views: 117

Filippo

Expert
Licensed User
My guess (based on Android source code) is that lbl.Width < 0. Add some checks.
You mean that perhaps it might not yet been initialized?
 
Upvote 0

Filippo

Expert
Licensed User
Alright, thanks again.

I think that these checks should be enough now.

B4X:
'Der Parameter "Scale" bei Buttons nicht verwendet!
Public Sub SetTextSize(obj As View, txt As String, scale As Float, singleline As Boolean)
    'Log("SetTextSize: txt=" & txt & " :obj=" & obj)

    'WICHTIG! Object muss initialisiert sein!
    If Not(obj.IsInitialized) Then Return

    'WICHTIG! Die Width darf nicht weniger als null sein!
    If obj.Width < 10dip Then Return

    setSingleLine(obj, singleline)

    If obj Is Button Then
        Dim btn As Button = obj
        Height = btn.Height - 14dip
        Width = btn.Width - 10dip

        SetButtonTextSize(btn, txt)
    Else
        Dim lbl As Label = obj
        Height = lbl.Height * scale
        Width = lbl.Width - 5dip
        
        SetLabelTextSize(lbl, txt)
    End If
End Sub
 
Last edited:
Upvote 0

Filippo

Expert
Licensed User
Unfortunately, the last measures have not been enough. :(
After the implementation of crashlytics now these errors come.

upload_2018-10-26_7-29-40.png


upload_2018-10-26_7-34-23.png



Fatal Exception: java.lang.IllegalArgumentException: width and height must be > 0
at android.graphics.Bitmap.createBitmap(Bitmap.java:829)
at android.graphics.Bitmap.createBitmap(Bitmap.java:808)
at android.graphics.Bitmap.createBitmap(Bitmap.java:775)
at anywheresoftware.b4a.objects.drawable.CanvasWrapper$BitmapWrapper.InitializeMutable(CanvasWrapper.java:654)
at fg.MasterOfRegolarity.clstextresizer._initialize(clstextresizer.java:71)
at fg.MasterOfRegolarity.main._activity_create(main.java:504)
at java.lang.reflect.Method.invoke(Method.java)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:191)
at fg.MasterOfRegolarity.main.afterFirstLayout(main.java:104)
at fg.MasterOfRegolarity.main.access$000(main.java:17)
at fg.MasterOfRegolarity.main$WaitForLayout.run(main.java:82)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5421)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

Can that be the "1dpi" is too little?
B4X:
Public Sub Initialize
    bmp.InitializeMutable(1dip, 1dip)
    cvs.Initialize2(bmp)
End Sub
 
Upvote 0

Filippo

Expert
Licensed User
Yes. On very low end devices with a scale less than 1. I don't remember encountering this error in the past.

Better to use:
B4X:
bmp.InitializeMutable(1, 1) 'ignore
OK, thanks, I'll try.
 
Upvote 0

Filippo

Expert
Licensed User
Yes. On very low end devices with a scale less than 1. I don't remember encountering this error in the past.

Better to use:
B4X:
bmp.InitializeMutable(1, 1) 'ignore
Unfortunately, that was not enough. :(

Gerät
Marke: samsung
Modell: SM-A530F
Ausrichtung: Hochformat
Freier RAM: 1.07 GB
Freier Festplattenspeicher: 8.32 GB
Betriebssystem
Version: 8.0.0
Ausrichtung: Hochformat
Rooting durchgeführt: Nein


Fatal Exception: java.lang.IllegalArgumentException
Layout: -3 < 0
Fatal Exception: java.lang.IllegalArgumentException: Layout: -3 < 0
at android.text.Layout.<init>(Layout.java:221)
at android.text.StaticLayout.<init>(StaticLayout.java:493)
at android.text.StaticLayout.<init>(StaticLayout.java:479)
at android.text.StaticLayout.<init>(StaticLayout.java:457)
at android.text.StaticLayout.<init>(StaticLayout.java:437)
at anywheresoftware.b4a.objects.StringUtils.MeasureMultilineTextHeight(StringUtils.java:50)
at fg.MasterOfRegolarity.clstextresizer._vvvvvvvvvvvvvvvvvvvvvvvvvvvv6(clstextresizer.java:84)
at fg.MasterOfRegolarity.clstextresizer._vvvvvvvvvvvvvvvvvvvvv4(clstextresizer.java:174)
at fg.MasterOfRegolarity.main._activity_create(main.java:525)
at java.lang.reflect.Method.invoke(Method.java)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:191)
at fg.MasterOfRegolarity.main.afterFirstLayout(main.java:104)
at fg.MasterOfRegolarity.main.access$000(main.java:17)
at fg.MasterOfRegolarity.main$WaitForLayout.run(main.java:82)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

upload_2018-10-27_19-53-30.png


upload_2018-10-27_19-54-8.png
 
Upvote 0

Filippo

Expert
Licensed User
You need to debug your code and make sure never to call MeasureMultilineTextHeight with width or height < 10.
The problem is that I can not reproduce the error on my test devices.

That should have worked with this code already, right?

B4X:
    'WICHTIG! Die Width darf nicht weniger als null sein!
    If obj.Width < 10dip Then Return

B4X:
'Der Parameter "Scale" bei Buttons nicht verwendet!
Public Sub SetTextSize(obj As View, txt As String, scale As Float, singleline As Boolean)
    'Log("SetTextSize: txt=" & txt & " :obj=" & obj)

    'WICHTIG! Object muss initialisiert sein!
    If Not(obj.IsInitialized) Then Return

    'WICHTIG! Die Width darf nicht weniger als null sein!
    If obj.Width < 10dip Then Return

    setSingleLine(obj, singleline)

    If obj Is Button Then
        Dim btn As Button = obj
        Height = btn.Height - 14dip
        Width = btn.Width - 10dip

        SetButtonTextSize(btn, txt)
    Else
        Dim lbl As Label = obj
        Height = lbl.Height * scale
        Width = lbl.Width - 5dip
        
        SetLabelTextSize(lbl, txt)
    End If
End Sub
 
Upvote 0

Filippo

Expert
Licensed User
The code is not the same. Where is the "while" loop?
That's still the same code from the top.
I just changed "bmp.InitializeMutable (1, 1) 'ignore", I did not want to be so petty. :p

B4X:
Sub Class_Globals
   Private bmp As Bitmap
   Private cvs As Canvas

   Private stu As StringUtils
   Private dt As Float
   Private h, Height As Int
   Private w, Width As Int
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
   bmp.InitializeMutable(2, 2) 'ignore
   cvs.Initialize2(bmp)
End Sub

#Region TextSize vom Label, EditText und Button ändern

'Der Parameter "Scale" bei Buttons nicht verwendet!
Public Sub SetTextSize(obj As View, txt As String, scale As Float, singleline As Boolean)
   'Log("SetTextSize: txt=" & txt & " :obj=" & obj)

   'WICHTIG! Object muss initialisiert sein!
   If Not(obj.IsInitialized) Then Return

   'WICHTIG! Die Width darf nicht weniger als 10dip sein!
   If obj.Width < 10dip Then Return

   setSingleLine(obj, singleline)

   If obj Is Button Then
       Dim btn As Button = obj
       Height = btn.Height - 14dip
       Width = btn.Width - 10dip

       SetButtonTextSize(btn, txt)
   Else
       Dim lbl As Label = obj
       Height = lbl.Height * scale
       Width = lbl.Width - 5dip
       
       SetLabelTextSize(lbl, txt)
   End If
End Sub

'Sets the TextView to single line
Public Sub setSingleLine(TextView As View, SingleLine As Boolean)
   Dim jo = TextView As JavaObject
   jo.RunMethod("setSingleLine", Array As Object(SingleLine))
End Sub

Private Sub SetButtonTextSize(btn As Button, txt As String)   
   btn.TextSize = 6
   dt = btn.TextSize
   h = stu.MeasureMultilineTextHeight(btn, txt)
   w = cvs.MeasureStringWidth(txt, btn.Typeface, dt)
   Do While h <= Height
       dt = dt + 1
       btn.TextSize = dt
       h = stu.MeasureMultilineTextHeight(btn, txt)
       w = cvs.MeasureStringWidth(txt, btn.Typeface, dt)
       
       If w >= Width Or h > Height Then
           btn.TextSize = dt - 2
           Exit
       End If
   Loop
End Sub

Private Sub SetLabelTextSize(lbl As Label, txt As String)   
   lbl.TextSize = 6
   dt = lbl.TextSize
   h = stu.MeasureMultilineTextHeight(lbl, txt)
   w = cvs.MeasureStringWidth(txt, lbl.Typeface, dt)
   Do While h <= Height
       dt = dt + 1
       lbl.TextSize = dt
       h = stu.MeasureMultilineTextHeight(lbl, txt)
       w = cvs.MeasureStringWidth(txt, lbl.Typeface, dt)

'       Log(txt & ": w=" & w & " ;h=" & h)
'       Log(txt & ": Width=" & Width & " ;Height=" & Height)
   
       If w > Width Or h > Height Then
           lbl.TextSize = dt - 1
           Exit
       End If
   Loop
End Sub

#End Region
 
Upvote 0

Filippo

Expert
Licensed User
There is a bug in this code:
B4X:
 If obj.Width < 10dip Then Return

   setSingleLine(obj, singleline)

   If obj Is Button Then
       Dim btn As Button = obj
       Height = btn.Height - 14dip 'it can be any value here
       Width = btn.Width - 10dip 'it can be 0 here.
That should have no impact normal, right?
The variable can become negative, but in this operational nothing should make.

B4X:
        If w > Width Or h > Height Then
            lbl.TextSize = dt - 1
            Exit
        End If

But I will change it anyway.
B4X:
'Der Parameter "Scale" bei Buttons nicht verwendet!
Public Sub SetTextSize(obj As View, txt As String, scale As Float, singleline As Boolean)
   'Log("SetTextSize: txt=" & txt & " :obj=" & obj)

   'WICHTIG! Object muss initialisiert sein!
   If Not(obj.IsInitialized) Then Return

   'WICHTIG! Die Width darf nicht weniger als 10dip sein!
   If obj.Width < 10dip Then Return

   setSingleLine(obj, singleline)

   If obj Is Button Then
       Dim btn As Button = obj
       Height = btn.Height
       Width = btn.Width
       If btn.Height > 14dip Then Height = btn.Height - 14dip
       If btn.Width > 10dip Then Width = btn.Width - 10dip

       SetButtonTextSize(btn, txt)
   Else
       Dim lbl As Label = obj
       Height = lbl.Height * scale
       Width = lbl.Width
       If btn.Width > 5dip Then Width = lbl.Width - 5dip
       
       SetLabelTextSize(lbl, txt)
   End If
End Sub
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
That should have no impact normal, right?
This bug will cause your app to crash.

If obj.width = 11dip and you substract 10dip from it then the width will be 1dip. This is too small (as the padding is also subtracted).

You should make sure to never call MeasureMultilineTextHeight with very small width or height.
 
Upvote 0

Filippo

Expert
Licensed User
This bug will cause your app to crash.

If obj.width = 11dip and you substract 10dip from it then the width will be 1dip. This is too small (as the padding is also subtracted).

You should make sure to never call MeasureMultilineTextHeight with very small width or height.
I apologize, but I do not change the view size, I only change the variables "Height" and "Width" for the IF query.

This ensures the view is not smaller than 10dip.
B4X:
   'WICHTIG! Die Width darf nicht weniger als 10dip sein!
   If obj.Width < 10dip Then Return

and here it should not matter if the variable "Width" or "Height" is smaller than 10dip.
B4X:
Private Sub SetLabelTextSize(lbl As Label, txt As String)   
   lbl.TextSize = 6
   dt = lbl.TextSize
   h = stu.MeasureMultilineTextHeight(lbl, txt)
   w = cvs.MeasureStringWidth(txt, lbl.Typeface, dt)
   Do While h <= Height
       dt = dt + 1
       lbl.TextSize = dt
       h = stu.MeasureMultilineTextHeight(lbl, txt)
       w = cvs.MeasureStringWidth(txt, lbl.Typeface, dt)

'       Log(txt & ": w=" & w & " ;h=" & h)
'       Log(txt & ": Width=" & Width & " ;Height=" & Height)
  
       If w > Width Or h > Height Then
           lbl.TextSize = dt - 1
           Exit
       End If
   Loop
End Sub
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
I now understand. Why have you added these two variables? They don't seem to do anything useful.

Now for the correct answer:
The code of MeasureMultilineTextHeight subtracts the left and right paddings.

In the material theme the paddings of buttons are:
B4X:
Dim p() As Int = Button1.Padding
Log((p(0) + p(2)) / GetDeviceLayoutValues.Scale) '23dip

This means that your check is not good enough for buttons. Either set the padding to 0, 0, 0, 0 or make sure that buttons width is 30dip+.
 
Upvote 0

Filippo

Expert
Licensed User
Now for the correct answer:
The code of MeasureMultilineTextHeight subtracts the left and right paddings.

In the material theme the paddings of buttons are:
Code:
Dim p() As Int = Button1.Padding
Log((p(0) + p(2)) / GetDeviceLayoutValues.Scale) '23dip
This means that your check is not good enough for buttons. Either set the padding to 0, 0, 0, 0 or make sure that buttons width is 30dip+.
Thanks, now I understand it better. ;)

Why have you added these two variables? They don't seem to do anything useful.
I have added this so that view size is not changed.
 
Upvote 0
Top