Temporary Screen with an infinite loop animation crashes when deleted

There is an event for Play Animation but I think there needs to be one for either Stop Animation or Delete Animation that can be called from the Unload event. Or is called automatically when the screen is deleted.

Also, squareline generates the animation as a local variable in a function, so there is no way to reference the animation object from outside it to delete it or stop playback from custom function

void My_Animation( lv_obj_t *TargetObject, int delay)
{
...
lv_anim_t PropertyAnimation_0;
...
}

I confirmed that this does not crash is the screen is not marked at Temporary. So my guess is because the animation target has been deleted and this causes the crash.

I tried doing this but it didn’t work:

void MyTemporaryScreen_UnloadStart(lv_event_t *e)
{
	// delete the animation
	lv_anim_del(ui_MyAnimatedObject, NULL);
}

We discussed this with LVGL-authors and the advise was to avoid creating animations from temporary screens, but create them separately or by screen_loaded events, so there would be more control over the creation/deletion of animations. You concluded something similar, but you told in the last post the (same? crashing?) problem still exists.
As for the supposed animation-deletion functions, we’ll discuss the possibilities.
The SquareLine documentation explicitly tells to be careful with Temporary Screens: they shouldn’t contain ‘continuous animation’.

The code you generate for the SquareLine animations encapsulates the object reference inside the creation method rather than having a global variable like all the other widgets. Having a global variable would allow interaction with the animation from outside the create function.

After checking the code of lv_anim_del() function in LVGL source-tree, it seems that you can delete (stop) the animation by setting 1st parameter to NULL and giving the executor callback function’s name instead to identify the animation. It isn’t mentioned in LVGL 8.3 documentation, just the cases when you give both the animated variable/object and the function name. But the code shows if any of them is set to NULL the other parameter will be used nevertheless to stop the matching animation.)

So you don’t need to have the animated variable/object ‘PropertyAnimation_0’ (in your latest example ‘ui_MyAnimatedObject’) to be in a global scope, the function name is enough. You can delete (stop) the animation like this before switching from temporary screen to another (tested and works):

lv_anim_del( NULL, (lv_anim_exec_xcb_t) _ui_anim_callback_set_x );

(The 2nd argument - function name - should be rewritten to your actual animator function in your code. The casting is necessary to avoid warnings thrown by lv_anim_del(). )

1 Like

Revisiting this, I’ve come to the conclusion it is not a good solution.

lv_anim_del( NULL,  (lv_anim_exec_xcb_t) _ui_anim_callback_set_x );

This deletes all animations using that callback, including those on permanent screens. This also assumes the UI developer does not change the animation type, and when they do, then it will crash again. Keeping these updated is error-prone and tedious and these handlers must double checked after every export.

What do you think about SquareLine generating code on screen or widget destruction to call lv_anim_del() on the specific animations only?

I think one simple solution is for SquareLine to instantiate the animations globally in ui.c like all the other widgets and that way we can reference them in lv_anim_del().

More elaborate, it would auto delete them in the screen _ui_screen_delete helper in ui_helpers.c

1 Like

If I can get all screens to be temporary, would it work to lv_anim_del(NULL, NULL) globally on UNLOAD_START?

Thanks for all the feedbacks and ideas regarding the animations. I reported the need for this feature to the respective team.

1 Like

Thanks Hermit!

I think one simple solution is for SquareLine to instantiate the animations globally in ui.c like all the other widgets and that way we can reference them in lv_anim_del().

@CodeGrue , I don’t think that will work, at least not by itself. I found this LVGL ticket, and the same issue occurs in our SquareLine-exported code. This line, or similar, is the issue:
lv_anim_set_custom_exec_cb(&PropertyAnimation_0, _ui_anim_callback_set_y);

When that happens, the lv_anim_t->var is pointed not against the animation target, but pointed to the lv_anim_t itself(a stack variable soon to be destroyed). This means that even having each animation object globally accessible wouldn’t help, because lv_anim_del(objPointer, callbackPointer) searches the animation global list for lv_anim_t->var == objPointer.

Why do the animations work at all? Well, the information they need is stored via the user-data section, not by the var pointer.

@Hermit , instead of SquareLine emitting lv_anim_set_custom_exec_cb(), could SquareLine please consider emitting lv_anim_set_exec_cb() to set the callback and lv_anim_set_var() to set the animation target object? I believe this will fix lv_anim_del(obj,NULL) and lv_anim_del(obj,callback) which currently do not appear to work, leading to these dangling animation crashes. Once the lv_anim_t->var correctly points to the animation target, LVGL should be able to destroy the relevant animations when destroying the target object, as it will now be able to find them.

Edit: remove outdated statement

I wrote a regex to do this, but doing so also requires updating the parameter type of the callbacks from: void _ui_anim_callback_set_y(lv_anim_t * a, int32_t v) to void _ui_anim_callback_set_y(void * a, int32_t v) or void _ui_anim_callback_set_y(lv_obj_t * a, int32_t v). Luckily, many of the callbacks can be replaced directly with the LVGL equivalents, but we have to be careful, as many of the other callbacks for this animation will take a lv_anim_t

Thank you Richard for bringing the topic further by doing some research in this area, and for sharing the results with us. We’ll see what can be done.

1 Like