Snapshot not restored on applicationResume for Android (4.3)

Hi Guys

I’m having some issues with the android version of an app that uses the snapshot object (canvas mode is set to discard). The issue occurs when you exit the app by clicking the home or the task manager button and then returning to it (the snapshot is not being restored from the memory). This is not happening on iOS.

Attached are 2 screenshots of the “TrailingPaint” example with the issue.

Anybody has any idea how to fix this?

Apparently this is a “normal” behaviour on android according to http://forums.coronalabs.com/topic/41150-issues-with-snapshots-resuming-on-android/, so the only solution would be to save the snapshot on “applicationSuspend” event and restore it “applicationResume”.

However when I try to do this, the image is saved but on “applicationResume” I only get a blank screen - no actual code is executed on this event. The test is again on Android.

Yup, have tried the following and getting the same result (the base is taken from http://coronalabs.com/blog/2013/11/01/snapshot-canvas-paint-brushes-trailing-object-effects-etc/)

local w = display.viewableContentWidth

local h = display.viewableContentHeight

local snapshot = display.newSnapshot( w,h )

snapshot:translate( w * 0.5, h * 0.5 )

snapshot.canvasMode = “discard”

function listener( event )

    local x,y = event.x - snapshot.x, event.y - snapshot.y

    if ( event.phase == “began” or event.phase == “moved” ) then

        local r = display.newRect( 0, 0, w, h )

        r:setFillColor( .05, .05, .05, .05 )

        local o = display.newImage( “brush.png”, x, y )

        o:setFillColor( 1 )

        o.alpha = .3

        snapshot.canvas:insert( r )

        snapshot.canvas:insert( o )

        snapshot:invalidate( “canvas” )

    end

end

Runtime:addEventListener( “touch”, listener )

local function onSystemEvent( event )

    if(event.type==“applicationSuspend”) then

        display.save(snapshot,“temp.png”,system.TemporaryDirectory)

    elseif(event.type==“applicationResume”) then

        print(“resume code here - THIS IS WHERE THE BLANK SCREEN HAPPENS, or maybe even on suspend”)

    end

end

Runtime:addEventListener( “system”, onSystemEvent )

There are a couple of things to keep in mind:

  1. Textures are lost between suspend/resume. Normally, an image is backed by an actual file, so you can regenerate the texture on the GPU.
  2. Snapshots use render-to-texture, so as long as you know how to redraw the objects added to the texture, you can regenerate the texture.
  3. In general, you *can* regenerate the texture of the snapshot. 
  • Now, the reason the code above fails is that the snapshot’s canvasMode is set to “discard”. This means all objects drawn to the snapshot are discarded (thrown away). 
  • The trick is to set the canvasMode to “append”. That way objects are saved off into the snapshot’s group (http://docs.coronalabs.com/api/type/SnapshotObject/group.html) instead of just being thrown away. Then in the resume event, you can call snapshot:invalidate() — with 0 params, so it invalidates the group.

Hey Walter, but if you have large number of objects - for instance used in a painting app, then those objects will take a lot of memory so reconstructing the snapshot is not an option in this scenario. So the actual question is when do I save the image of the snapshot since on the system event .type “applicationSuspend” is not possible/not working?

How much memory are we talking about? The memory of an object is usually a lot less than the memory consumed by a texture, so what numbers are you seeing?

Of course, your other option is to display.save this to a file, but the trick is you have to then load that file into an image and draw that into the snapshot.

At the time that the canvas discard was not available - in the early G2 beta the memory use to go up to 3MB (not texture memory) with a few brush strokes. So keeping the objects in the memory won’t do the thing.

As for the possible workaround - I managed to save the snapshot in to a png file with the original width / height and was able to restore it - put it back in the snapshot on application resume event (on the simulator), however once I add the following code on android:

local function onSystemEvent( event )

    if(event.type==“applicationSuspend”) then

        display.save(snapshot,“temp.png”,system.TemporaryDirectory)

    elseif(event.type==“applicationResume”) then

        print(“resume code here - THIS IS WHERE THE BLANK SCREEN HAPPENS, or maybe even on suspend”)

    end

end

Runtime:addEventListener( “system”, onSystemEvent )

I usually get a blank screen on application resume (on android, but it works in the simulator) - This might be a bug.

At the moment I’m looking for an alternative when to save the snapshot (other than on application resume).

Here is a short video of the application template - https://www.youtube.com/watch?v=cSKewk2k2Zs

How many display objects for that 3 MB?

Around 10.000

Apparently this is a “normal” behaviour on android according to http://forums.coronalabs.com/topic/41150-issues-with-snapshots-resuming-on-android/, so the only solution would be to save the snapshot on “applicationSuspend” event and restore it “applicationResume”.

However when I try to do this, the image is saved but on “applicationResume” I only get a blank screen - no actual code is executed on this event. The test is again on Android.

Yup, have tried the following and getting the same result (the base is taken from http://coronalabs.com/blog/2013/11/01/snapshot-canvas-paint-brushes-trailing-object-effects-etc/)

local w = display.viewableContentWidth

local h = display.viewableContentHeight

local snapshot = display.newSnapshot( w,h )

snapshot:translate( w * 0.5, h * 0.5 )

snapshot.canvasMode = “discard”

function listener( event )

    local x,y = event.x - snapshot.x, event.y - snapshot.y

    if ( event.phase == “began” or event.phase == “moved” ) then

        local r = display.newRect( 0, 0, w, h )

        r:setFillColor( .05, .05, .05, .05 )

        local o = display.newImage( “brush.png”, x, y )

        o:setFillColor( 1 )

        o.alpha = .3

        snapshot.canvas:insert( r )

        snapshot.canvas:insert( o )

        snapshot:invalidate( “canvas” )

    end

end

Runtime:addEventListener( “touch”, listener )

local function onSystemEvent( event )

    if(event.type==“applicationSuspend”) then

        display.save(snapshot,“temp.png”,system.TemporaryDirectory)

    elseif(event.type==“applicationResume”) then

        print(“resume code here - THIS IS WHERE THE BLANK SCREEN HAPPENS, or maybe even on suspend”)

    end

end

Runtime:addEventListener( “system”, onSystemEvent )

There are a couple of things to keep in mind:

  1. Textures are lost between suspend/resume. Normally, an image is backed by an actual file, so you can regenerate the texture on the GPU.
  2. Snapshots use render-to-texture, so as long as you know how to redraw the objects added to the texture, you can regenerate the texture.
  3. In general, you *can* regenerate the texture of the snapshot. 
  • Now, the reason the code above fails is that the snapshot’s canvasMode is set to “discard”. This means all objects drawn to the snapshot are discarded (thrown away). 
  • The trick is to set the canvasMode to “append”. That way objects are saved off into the snapshot’s group (http://docs.coronalabs.com/api/type/SnapshotObject/group.html) instead of just being thrown away. Then in the resume event, you can call snapshot:invalidate() — with 0 params, so it invalidates the group.

Hey Walter, but if you have large number of objects - for instance used in a painting app, then those objects will take a lot of memory so reconstructing the snapshot is not an option in this scenario. So the actual question is when do I save the image of the snapshot since on the system event .type “applicationSuspend” is not possible/not working?

How much memory are we talking about? The memory of an object is usually a lot less than the memory consumed by a texture, so what numbers are you seeing?

Of course, your other option is to display.save this to a file, but the trick is you have to then load that file into an image and draw that into the snapshot.

At the time that the canvas discard was not available - in the early G2 beta the memory use to go up to 3MB (not texture memory) with a few brush strokes. So keeping the objects in the memory won’t do the thing.

As for the possible workaround - I managed to save the snapshot in to a png file with the original width / height and was able to restore it - put it back in the snapshot on application resume event (on the simulator), however once I add the following code on android:

local function onSystemEvent( event )

    if(event.type==“applicationSuspend”) then

        display.save(snapshot,“temp.png”,system.TemporaryDirectory)

    elseif(event.type==“applicationResume”) then

        print(“resume code here - THIS IS WHERE THE BLANK SCREEN HAPPENS, or maybe even on suspend”)

    end

end

Runtime:addEventListener( “system”, onSystemEvent )

I usually get a blank screen on application resume (on android, but it works in the simulator) - This might be a bug.

At the moment I’m looking for an alternative when to save the snapshot (other than on application resume).

Here is a short video of the application template - https://www.youtube.com/watch?v=cSKewk2k2Zs

How many display objects for that 3 MB?

Around 10.000

@nikraver:

We’re experiencing this exact same issue.  Were you able to determine a solution that worked to prevent the black screen issue on applicationResume?

This bug is still present, for us we’re getting it specifically on the Galaxy Tab 10.1. Any updates on this? @nikraver - have you been able to solve this issue or work around it in any way?

No, have tried every possible scenario and the only workaround was to redirect the user to the main menu on applicationResume.

Note: The app was rejected on Samsung due to this “workaround”