Android Question libGDX: Assetmanager with ScreenManager

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
Does anyone have a short example of using the AssetManager to async load resources for an application that is also using a screen manager to handle multiple screens?

Per the AssetManager example program, in the main "LG_Create" block I initialize the screen manager and create a couple of screens, then I initialize and queue up the AssetManager.

In the LG_Render block I Return immediately if the AssetManager .Update method returns true.

In my screen _Show() blocks I create objects using assets, which throws an error indicating that the assets have not been loaded yet.

I have not been able to figure out how prevent the screen manager from invoking the show method before the async load finishes, so obviously I'm doing something wrong, or in the incorrect order.

Any suggestions would be most welcome.
 

Informatix

Expert
Licensed User
Longtime User
If you set a screen as the current screen before your assets are loaded, then it's normal. You probably don't even pass in LG_Render. Solution: either you load the assets in the Render event of your screen, or you load your assets in the main Render event and, only once finished, you display your screen.
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
I'm still not sure I understand...

I'm trying to just load the assets once, at the start of the activity. For example, here's my attempt at joining your multi-screen and assetmanager examples:
B4X:
Sub Process_Globals

End Sub

Sub Globals
    Dim lGdx As LibGDX
    Dim Surface As View
    Dim GL As lgGL
    Dim AM As lgAssetManager
    Dim Stage(2) As lgScn2DStage
    Dim Table(2) As lgScn2DTable
   
    Dim lGdx_ScrMgr As lgScreenManager
    Dim lGdx_Screen(2) As lgScreen
   
    Dim foComicFont As lgBitmapFont
    Dim lblScore As lgScn2DLabel
   
    Dim flTouchDown As Long
   
   
    Private panLoading As Panel
    ' ---- layLoading 
    Private lblLoadingHead As Label
    Private pgbLoading As ProgressBar
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Initializes libGDX
    Dim Config As lgConfiguration
    Config.useGL20 = True
    Config.useAccelerometer = False
    Config.useCompass = False
    Config.useWakelock = True
    Config.maxSimultaneousSounds = 6
    'Creates the LibGDX surface
    Surface = lGdx.InitializeView2(Config, "LG")
    Activity.AddView(Surface, 0,  0, 100%x, 100%y)
   
    'Create our loading screen   
    panLoading.Initialize("")
    Dim poCD As ColorDrawable
    poCD.Initialize(Colors.Black, 0)
    Activity.AddView(panLoading, 0, 0, 100%x, 100%y)
    panLoading.LoadLayout("layLoading")
    panLoading.Color = Colors.Black
    panLoading.Background = poCD
    panLoading.BringToFront
End Sub

Sub Activity_Resume
    'Informs libGDX of Resume events
    If lGdx.IsInitialized Then lGdx.Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    'Informs libGDX of Pause events
    If lGdx.IsInitialized Then lGdx.Pause
End Sub

Sub LG_Create
    lGdx.CallSubUI("Show_Loading", Null)
 
    'Initializes the asset manager
    AM.Initialize("AM")

    'Adds a few assets to the loading queue of the asset manager
    AM.TiledMapLoader = AM.MAPLOADER_TMX
    AM.Load("maps/map_001.tmx", AM.TYPE_TiledMap)
    AM.Load("fonts/comic2.fnt", AM.TYPE_BitmapFont)
    AM.Load("audio/mus_main.ogg", AM.TYPE_Music)
    AM.Load("audio/ding.ogg", AM.TYPE_Sound)
    AM.Load("parts/explode_02.p", AM.TYPE_ParticleEffect)

    '  Setup the screen manager
    lGdx_ScrMgr.Initialize(lGdx)
    lGdx_Screen(0) = lGdx_ScrMgr.AddScreen("LGS0")
    lGdx_Screen(1) = lGdx_ScrMgr.AddScreen("LGS1")
    lGdx_ScrMgr.CurrentScreen = lGdx_Screen(0)
End Sub

Sub LG_Resize(Width As Int, Height As Int)

End Sub

Sub LG_Render
    'Loads the assets asynchronously
    If AM.Update Then
        lGdx.CallSubUI("Update_Loading", AM.Progress)
        Return
    Else
        lGdx.CallSubUI("Hide_Loading", Null)
    End If
End Sub

Sub LG_Pause

End Sub

Sub LG_Resume

End Sub

Sub LG_Dispose
    AM.dispose
End Sub


Sub AM_Error(FileName As String, Class As Object, Message As String)
    LogColor("- libGDX AssetManager ERROR !!! ---", Colors.Red)
    LogColor("    FileName = " & FileName, Colors.Red)
    LogColor("    Class = " & Class, Colors.Red)
    LogColor("    Message = " & Message, Colors.Red)
    LogColor("- libGDX AssetManager ERROR !!! ---", Colors.Red)
End Sub

Private Sub Show_Loading(dummy As Object)
    pgbLoading.Progress = 0
    panLoading.Visible = True
    DoEvents
End Sub

Private Sub Update_Loading(Progress As Float)
    pgbLoading.Progress = (Progress * 100)
    DoEvents
End Sub

Private Sub Hide_Loading(Dummy As Object)
    If panLoading.Visible = False Then
        Return
    End If

    pgbLoading.Progress = 100
    DoEvents
    panLoading.Visible = False
End Sub


#Region Screen 0
'-------------------------------------------------------------------------------------
' SCREEN 0 (first screen)
'-------------------------------------------------------------------------------------
Sub LGS0_Show
    Log("screen 0 show")
   
    'Initializes the Stage
    Stage(0).Initialize("ST_0")

    'Adds a capture listener to the stage to filter the input events
    Dim IL As lgScn2DInputListener
    IL.Initialize("ST_0")
    Stage(0).AddCaptureListener(IL)

    'Creates the main table
    Table(0).Initialize("Table0")
    Table(0).FillParent = True
    Stage(0).AddActor(Table(0))

'    Uncomment here to produce Null Pointer errors
   
'    foComicFont = AM.Get("fonts/comic2.fnt")
'    foComicFont.SetTextureFilter(foComicFont.FILTER_Linear, foComicFont.FILTER_Linear)
'    foComicFont.Scale(Density)
'   
    'Creates the score label
'    Dim lblStyle As lgScn2DLabelStyle
'    lblStyle.Initialize(foComicFont, foComicFont.Color.WHITE)
'    lblScore.Initialize("Score" & CRLF & "000000", lblStyle, "")
'    Table(0).AddActor(lblScore).AlignLeft

   
End Sub

Sub LGS0_Resize(Width As Int, Height As Int)
    Log("screen 0 resize")
    'Sets the stage viewport
    Stage(0).SetViewport(Width, Height, True)
End Sub

Sub LGS0_Render(Delta As Float)
    'Log("1 render " & Delta)
    'Clears the screen
    GL.glClearColor(1, 0 , 0, 1)
    GL.glClear(GL.GL10_COLOR_BUFFER_BIT)

    'Applies the actions to actors
    Stage(0).Act2(Delta)
   
    'Draws the actors
    Stage(0).Draw
End Sub

Sub LGS0_Pause
    Log("screen 0 pause")
End Sub

Sub LGS0_Resume
    Log("screen 0 resume")
End Sub

Sub LGS0_Hide
    Log("screen 0 hide")
    Stage(0).dispose
    'foComicFont.dispose
    Log("screen 0 disposed")
End Sub

Sub ST_0_TouchDown(Event As lgScn2DInputEvent, X As Float, Y As Float, Pointer As Int)
    '...
    Event.Handle
End Sub

Sub ST_0_TouchUp(Event As lgScn2DInputEvent, X As Float, Y As Float, Pointer As Int)
    '...
    lGdx_ScrMgr.CurrentScreen = lGdx_Screen(1)
    Event.handle
End Sub

#End Region


#Region Screen 1
'-------------------------------------------------------------------------------------
' SCREEN 1 (second screen)
'-------------------------------------------------------------------------------------
Sub LGS1_Show
    Log("screen 1 show")
   
    'Initializes the Stage
    Stage(1).Initialize("ST_1")

    'Adds a capture listener to the stage to filter the input events
    Dim IL As lgScn2DInputListener
    IL.Initialize("ST_1")
    Stage(1).AddCaptureListener(IL)

    'Creates the main table
    Table(1).Initialize("Table1")
    Table(1).FillParent = True
    Stage(1).AddActor(Table(1))
End Sub

Sub LGS1_Resize(Width As Int, Height As Int)
    Log("screen 1 resize")
    'Sets the stage viewport
    Stage(1).SetViewport(Width, Height, True)
End Sub

Sub LGS1_Render(Delta As Float)
    'Log("1 render " & Delta)
    'Clears the screen
    GL.glClearColor(0, 0 , 1, 1)
    GL.glClear(GL.GL10_COLOR_BUFFER_BIT)

    'Applies the actions to actors
    Stage(1).Act2(Delta)
   
    'Draws the actors
    Stage(1).Draw
End Sub

Sub LGS1_Pause
    Log("screen 1 pause")
End Sub

Sub LGS1_Resume
    Log("screen 1 resume")
End Sub

Sub LGS1_Hide
    Log("screen 1 hide")
    Stage(1).dispose
    Log("screen 1 disposed")
End Sub

Sub ST_1_TouchDown(Event As lgScn2DInputEvent, X As Float, Y As Float, Pointer As Int)
    '...
    Log("Screen 01 touch down event")
    flTouchDown = DateTime.Now   
    Event.Handle
End Sub

Sub ST_1_TouchUp(Event As lgScn2DInputEvent, X As Float, Y As Float, Pointer As Int)
    '...
    If (DateTime.Now - flTouchDown) < 2000 Then
        lGdx_ScrMgr.CurrentScreen = lGdx_Screen(0)
    Else
        Activity.Finish
    End If
    Event.handle
End Sub

#End Region

This will run "as is" and switch screens just fine. As soon as I try to create a label with a font from the AssetMananger in the _Show method it will error out.

How can I restructure this to avoid this problem?
 
Upvote 0

Informatix

Expert
Licensed User
Longtime User
I can only repeat myself: you don't pass in LG_Render because you change the current screen in LG_Create. Assets cannot be loaded. Either you load the assets in the Render event of your screen, or you load your assets in LG_Render and, only once finished, you display your screen.
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
Does not the LG_Render event get called constantly? Surely I don't need to load the assets once every 60th of a second?

Originally, I did try moving the screen manager create and assign to the "Hide_Loading" block, but when I do that the _Render event errors on the .Act2 method:
B4X:
sensor listener setup
OGL renderer: PowerVR SGX 540
OGL vendor: Imagination Technologies
OGL version: OpenGL ES 2.0
OGL extensions: GL_OES_rgb8_rgba8 GL_OES_depth24 GL_OES_vertex_half_float GL_OES_texture_float GL_OES_texture_half_float GL_OES_element_index_uint GL_OES_mapbuffer GL_OES_fragment_precision_high GL_OES_compressed_ETC1_RGB8_texture GL_OES_EGL_image GL_OES_required_internalformat GL_OES_depth_texture GL_OES_get_program_binary GL_OES_packed_depth_stencil GL_OES_standard_derivatives GL_OES_vertex_array_object GL_OES_egl_sync GL_EXT_multi_draw_arrays GL_EXT_texture_format_BGRA8888 GL_EXT_discard_framebuffer GL_EXT_shader_texture_lod GL_IMG_shader_binary GL_IMG_texture_compression_pvrtc GL_IMG_texture_stream2 GL_IMG_texture_npot GL_IMG_texture_format_BGRA8888 GL_IMG_read_format GL_IMG_program_binary GL_IMG_multisampled_render_to_texture
framebuffer: (5, 6, 5, 0)
depthbuffer: (24)
stencilbuffer: (8)
samples: (0)
coverage sampling: (false)
Managed meshes/app: { }
Managed textures/app: { }
Managed shaders/app: { }
Managed buffers/app: { }
screen 0 show
java.lang.IllegalArgumentException: Error compiling shader:
    at com.badlogic.gdx.graphics.g2d.SpriteBatch.createDefaultShader(SpriteBatch.java:198)
    at com.badlogic.gdx.graphics.g2d.SpriteBatch.<init>(SpriteBatch.java:162)
    at com.badlogic.gdx.graphics.g2d.SpriteBatch.<init>(SpriteBatch.java:99)
    at anywheresoftware.b4a.libgdx.graphics.lgSpriteBatch.Initialize(lgSpriteBatch.java:42)
    at com.badlogic.gdx.scenes.scene2d.Stage.<init>(Stage.java:127)
    at anywheresoftware.b4a.libgdx.scene2d.lgStage.Initialize(lgStage.java:37)
    at b4a.example.main._lgs0_show(main.java:615)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
    at anywheresoftware.b4a.libgdx.lgScreenManager$lgScreen.show(lgScreenManager.java:139)
    at anywheresoftware.b4a.libgdx.lgScreenManager.setCurrentScreen(lgScreenManager.java:61)
    at b4a.example.main._hide_loading(main.java:470)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
    at anywheresoftware.b4a.BA$2.run(BA.java:285)
    at android.os.Handler.handleCallback(Handler.java:587)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:130)
    at android.app.ActivityThread.main(ActivityThread.java:3689)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
    at dalvik.system.NativeStart.main(Native Method)
java.lang.NullPointerException
    at anywheresoftware.b4a.libgdx.scene2d.lgStage.Act2(lgStage.java:134)
    at b4a.example.main._lgs0_render(main.java:576)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
    at anywheresoftware.b4a.libgdx.lgScreenManager$lgScreen.render(lgScreenManager.java:121)
    at anywheresoftware.b4a.libgdx.lgScreenManager.Render(lgScreenManager.java:74)
    at anywheresoftware.b4a.libgdx.LibGDX$LibGDX_Listener.render(LibGDX.java:121)
    at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:520)
    at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1388)
    at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1138)
java.lang.IllegalArgumentException: Error compiling shader:
java.lang.NullPointerException
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
    at android.os.Handler.<init>(Handler.java:121)
    at android.app.Dialog.<init>(Dialog.java:102)
    at android.app.AlertDialog.<init>(AlertDialog.java:63)
    at android.app.AlertDialog.<init>(AlertDialog.java:59)
    at android.app.AlertDialog$Builder.create(AlertDialog.java:794)
    at anywheresoftware.b4a.BA.ShowErrorMsgbox(BA.java:222)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:202)
    at anywheresoftware.b4a.libgdx.lgScreenManager$lgScreen.render(lgScreenManager.java:121)
    at anywheresoftware.b4a.libgdx.lgScreenManager.Render(lgScreenManager.java:74)
    at anywheresoftware.b4a.libgdx.LibGDX$LibGDX_Listener.render(LibGDX.java:121)
    at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:520)
    at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1388)
    at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1138)
** Activity (main) Pause, UserClosed = true **
waiting for pause synchronization took too long; assuming deadlock and killing

I guess I can just abandon the idea of the asset manager and do it manually as I am clearly too dense to grasp this concept.

Thanks again,
Richard
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
Ok, if that is the case, why does the LGS0_Show/_Render throw an error when I move the screen manager initialize and assign to the LG_Render event after the AM.Update is complete?
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
Yes but you changed the current screen to LGS0, so it's the LGS0_Render sub that is called, not LG_Render.
This is not the behavior I am experiencing. I added log writes to the LG_Render, LGS0_Show (beginning and end), and the LGS0_Render events, here is the log result:
B4X:
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
Setting up screen manager
screen 0 show
LG_RENDER
screen 0 render 0.016527267172932625
java.lang.IllegalArgumentException: Error compiling shader:
    at com.badlogic.gdx.graphics.g2d.SpriteBatch.createDefaultShader(SpriteBatch.java:198) ...<snip>...

It seems that the LGS0_Render is getting fired before the LGS0_Show event has completed since I never see my "screen 0 show COMPLETE" log entry.
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
The error I listed in post #5 above. It seems the Stage(0).Act2(Delta) is throwing a null pointer exception (which I would expect, I guess, if the render event is getting called before the show event has completed).
 
Upvote 0

Informatix

Expert
Licensed User
Longtime User
This is not the behavior I am experiencing.

Your log proves the contrary. After you set the screen, you switch to the other Render event.

I added log writes to the LG_Render, LGS0_Show (beginning and end), and the LGS0_Render events, here is the log result:
B4X:
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
Setting up screen manager
screen 0 show
LG_RENDER
screen 0 render 0.016527267172932625
java.lang.IllegalArgumentException: Error compiling shader:
    at com.badlogic.gdx.graphics.g2d.SpriteBatch.createDefaultShader(SpriteBatch.java:198) ...<snip>...

It seems that the LGS0_Render is getting fired before the LGS0_Show event has completed since I never see my "screen 0 show COMPLETE" log entry.
When you switch to another screen, the order of events is not guaranteed (the program continues to spawn a Render event on a regular basis and unless you stop the continuous rendering, the event can be fired before what you expect so you have to check that your assets are loaded before using them).
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
Alright, I can allow for the order not being correct. When I do, it seems to still be calling both render events and I still get an error trying to initialize the stage in the _Show event. I'm not even trying to reference any assets, just create a stage with a table:
B4X:
LG_RENDER
LG_RENDER
LG_RENDER
Setting up screen manager
screen 0 show
LG_RENDER
screen 0 render 0.018514249473810196
screen 0 show not complete
LG_RENDER
screen 0 render 0.023753192275762558
screen 0 show not complete
LG_RENDER
screen 0 render 0.02158685028553009
screen 0 show not complete
java.lang.IllegalArgumentException: Error compiling shader:
    at com.badlogic.gdx.graphics.g2d.SpriteBatch.createDefaultShader(SpriteBatch.java:198)
    at com.badlogic.gdx.graphics.g2d.SpriteBatch.<init>(SpriteBatch.java:162)
    at com.badlogic.gdx.graphics.g2d.SpriteBatch.<init>(SpriteBatch.java:99)
    at anywheresoftware.b4a.libgdx.graphics.lgSpriteBatch.Initialize(lgSpriteBatch.java:42)
    at com.badlogic.gdx.scenes.scene2d.Stage.<init>(Stage.java:127)
    at anywheresoftware.b4a.libgdx.scene2d.lgStage.Initialize(lgStage.java:37)
    at b4a.example.main._lgs0_show(main.java:601)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
    at anywheresoftware.b4a.libgdx.lgScreenManager$lgScreen.show(lgScreenManager.java:139)
    at anywheresoftware.b4a.libgdx.lgScreenManager.setCurrentScreen(lgScreenManager.java:61)
    at b4a.example.main._hide_loading(main.java:454)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
    at anywheresoftware.b4a.BA$2.run(BA.java:285)
    at android.os.Handler.handleCallback(Handler.java:587)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:130)
    at android.app.ActivityThread.main(ActivityThread.java:3689)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
    at dalvik.system.NativeStart.main(Native Method)
java.lang.IllegalArgumentException: Error compiling shader:
LG_RENDER
screen 0 render 0.019934624433517456
screen 0 show not complete
LG_RENDER
screen 0 render 0.019906291738152504
screen 0 show not complete

I've been banging my head against this for the past two days trying different things, surely this can't be this hard. I know you're busy, but if you could look at the attached project and tell me where I am screwing up my forehead would be very grateful.
 
Last edited:
Upvote 0

Informatix

Expert
Licensed User
Longtime User
Alright, I can allow for the order not being correct. When I do, it seems to still be calling both render events and I still get an error trying to initialize the stage in the _Show event. I'm not even trying to reference any assets, just create a stage with a table:

Don't be fooled by the log. What you read is not the real order of messages. The log function is run in a different thread. If you put a time beside each Log, you should be able to sort them in the right order.

I've been banging my head against this for the past two days trying different things, surely this can't be this hard. I know you're busy, but if you could look at the attached project and tell me where I am screwing up my forehead would be very grateful.
Strange because it's something that never caused me any problem. I will look at your project tomorrow.
In my current project, I use a simple boolean (RenderOK) that is set to false when I switch to another screen and true at the end of the resize event. In the render event, I return after the screen clearing if RenderOk is false.
 
Upvote 0

Informatix

Expert
Licensed User
Longtime User
When you use CallSubUI, you run the specified sub in the main thread (which is not the thread of libGDX). And as you create a screen with one of these calls, your create the screen instance in a separate thread of libGDX. That's why you see two render events triggered in parallel.
The thing to remember is that the main use of CallSubUI is to update a B4A view (like a Label or an Edittext) because these views cannot be udpated from another thread. It is also used to display a modal dialog (e.g. a MsgBox). Never use it to create or update libGDX objects.
The proper coding would be:
B4X:
Sub LG_Render
    'Loads the assets asynchronously
    If AM.Update Then
        Return
    Else
        lGdx_ScrMgr.Initialize(lGdx)
        lGdx_Screen(0) = lGdx_ScrMgr.AddScreen("LGS0")
        lGdx_Screen(1) = lGdx_ScrMgr.AddScreen("LGS1")
        lGdx_ScrMgr.CurrentScreen = lGdx_Screen(0)
    End If
End Sub
But I cannot test it in your project because all assets are missing.
 
Last edited:
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
First, thank you very much for taking the time to look at the mess I've cobbled together. Second, sorry for the missing files, I assumed the B4A "Export as Zip" did everything in the folder. Also, I was unaware that the threading behaved like that, I assumed a more ".Net" behavior.

I made the change you suggested, now the program will run without a null exception, however the base event is still firing and the program loops between the LG_Render and the LGS0_Show event:
B4X:
Managed buffers/app: { }
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
LG_RENDER
screen 0 show
screen 0 show COMPLETE
screen 0 resize
screen 0 render 0.019895974546670914
Hiding loading panel
LG_RENDER
screen 0 show
java.lang.RuntimeException: Stage already initialized.
at anywheresoftware.b4a.libgdx.scene2d.lgStage.Initialize(SourceFile:37)
at b4a.example.main._lgs0_show(main.java:591)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
at anywheresoftware.b4a.libgdx.lgScreenManager$lgScreen.show(SourceFile:139)
at anywheresoftware.b4a.libgdx.lgScreenManager.setCurrentScreen(SourceFile:61)
at b4a.example.main._lg_render(main.java:506)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:163)
at anywheresoftware.b4a.libgdx.LibGDX$b.render(SourceFile:117)
at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(SourceFile:438)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1388)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1138)
java.lang.RuntimeException: Stage already initialized.
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at android.app.Dialog.<init>(Dialog.java:102)
at android.app.AlertDialog.<init>(AlertDialog.java:63)
at android.app.AlertDialog.<init>(AlertDialog.java:59)
at android.app.AlertDialog$Builder.create(AlertDialog.java:794)
at anywheresoftware.b4a.BA.ShowErrorMsgbox(BA.java:222)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:202)
at anywheresoftware.b4a.libgdx.lgScreenManager$lgScreen.show(SourceFile:139)
at anywheresoftware.b4a.libgdx.lgScreenManager.setCurrentScreen(SourceFile:61)
at b4a.example.main._lg_render(main.java:506)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:163)
at anywheresoftware.b4a.libgdx.LibGDX$b.render(SourceFile:117)
at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(SourceFile:438)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1388)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1138)
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at android.app.Dialog.<init>(Dialog.java:102)
at android.app.AlertDialog.<init>(AlertDialog.java:63)
at android.app.AlertDialog.<init>(AlertDialog.java:59)
at android.app.AlertDialog$Builder.create(AlertDialog.java:794)
at anywheresoftware.b4a.BA.ShowErrorMsgbox(BA.java:222)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:202)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:163)
at anywheresoftware.b4a.libgdx.LibGDX$b.render(SourceFile:117)
at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(SourceFile:438)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1388)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1138)
** Activity (main) Pause, UserClosed = true **
waiting for pause synchronization took too long; assuming deadlock and killing
** Activity (main) Resume **
Which is what I would expect to happen if the LG_Render event kept firing. This is what I found initially, that caused me to move the screen initialization to the LG_Create in the first place.

If you're still interested, I've attached the modified project (manually zipped this time with a few resources removed to meet the .5MB attachment limit here).

Thanks again for all your time and attention,
Richard
 
Last edited:
Upvote 0

Informatix

Expert
Licensed User
Longtime User
Oooops. I discovered a bug in libGDX thanks to your project. I couldn't notice it with my own handling of screens. It will be fixed before tomorrow. Thanks for the report and sorry for the inconvenience.

PS: you cannot create two stages. Look at your error message:
java.lang.RuntimeException: Stage already initialized.
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
No worries, I'm just glad it wasn't all me! :confused:

And yes, I didn't know you couldn't "re-initialize" a stage, I'll wrap the stage and table code inside a "If Stage(0).IsInitialized = False" block.

Thank you again for your help and effort!
 
Last edited:
Upvote 0

Informatix

Expert
Licensed User
Longtime User
No worries, I'm just glad it wasn't all me! :confused:

And yes, I didn't know you couldn't "re-initialize" a stage, I'll wrap the stage and table code inside a "If State(0).IsInitialized = False" block.

Thank you again for your help and effort!
I'm so ashamed! It's a huge bug.... :(
I couldn't notice it because I redirect all my screen renderings to a common render event.
 
Upvote 0
Top