How to switch screens correctly?

Hello,
I want to know the correct way to switch screens because my device often crashes when performing repeated switching, and I don’t know the reason.

I do a simple test, which demonstrated my implementation methods and they were fine. Are there Memory leak in some widgets?
gui_test.c (2.8 KB)

I think the code creates a memory leak, only create the scr object once I would say. Set them to NULL and check if they are already created. Or delete them.
But in general I would use objects any switch visibility or switch them from front to background

Yes,when I switch screens, the crash is in this place.

 scr = lv_obj_create(NULL);
 lv_scr_load(scr);

Why is there a memory leak? My current operation is to delete the scr, and I have tried to create it only once, but it has not been resolved. I think my approach is correct.

@pete-pjb

I think better first switch screen, then delete the objects

static void screen2_event_handler(lv_event_t *e)
{
lv_event_code_t code = lv_event_get_code(e);
switch (code)
{
case LV_EVENT_CLICKED:
{
lv_style_reset(&style_btn);
lv_style_reset(&style_label);
lv_obj_del(scr_2);
create_screen_1();
}
break;

default: break;

}
}

This can significantly increase the number of switches, but eventually it will crash, and there is no problem with the memory monitoring display.

Hi @gui_lvgl ,

Your method is good except you shouldn’t call lv_style_init() each time… Here’s your example modified to fix the issue:

static  lv_obj_t *scr_1;
static  lv_obj_t *scr_2;

static  lv_style_t style_btn;
static  lv_style_t style_label;
static	bool first_run = false;

void create_screen_1(void);
void create_screen_2(void);

static void screen1_event_handler(lv_event_t *e)
{
  lv_event_code_t code = lv_event_get_code(e);
  switch (code)
  {
    case LV_EVENT_CLICKED:
    {
      lv_obj_del(scr_1);
      create_screen_2();
    }
    break;

    default: break;
  }
}

static void screen2_event_handler(lv_event_t *e)
{
  lv_event_code_t code = lv_event_get_code(e);
  switch (code)
  {
    case LV_EVENT_CLICKED:
    {
      lv_obj_del(scr_2);
      create_screen_1();
    }
    break;

    default: break;
  }
}

void create_screen_1(void)
{
  scr_1 = lv_obj_create(NULL);
  lv_scr_load(scr_1);

  if( !first_run ) {
	  lv_style_init(&style_label);
	  lv_style_init(&style_btn);
	  first_run = true;
  }

  lv_style_reset(&style_btn);
  lv_style_reset(&style_label);

  lv_style_set_text_font(&style_label, &lv_font_montserrat_18);
  lv_style_set_text_opa(&style_label, LV_OPA_100);
  lv_style_set_text_color(&style_label, lv_color_black());

  lv_style_set_border_width(&style_btn, 1);
  lv_style_set_border_opa(&style_btn, LV_OPA_100);
  lv_style_set_border_color(&style_btn, lv_color_black());

  lv_obj_t * exit_btn = lv_btn_create(scr_1);
  lv_obj_add_style(exit_btn, &style_btn, 0);
  lv_obj_set_size(exit_btn, 80, 30);
  lv_obj_align(exit_btn, LV_ALIGN_CENTER, 0,0);
  lv_obj_add_event_cb(exit_btn, screen1_event_handler, LV_EVENT_CLICKED, NULL);

  lv_obj_t * exit_btn_label = lv_label_create(exit_btn);
  lv_obj_add_style(exit_btn_label, &style_label, 0);
  lv_label_set_text(exit_btn_label, "screen 1");
  lv_obj_align_to(exit_btn_label, exit_btn, LV_ALIGN_CENTER, 0, 0);
}

void create_screen_2(void)
{
  scr_2 = lv_obj_create(NULL);
  lv_scr_load(scr_2);

  if( !first_run ) {
	  lv_style_init(&style_label);
	  lv_style_init(&style_btn);
	  first_run = true;
  }

  lv_style_reset(&style_btn);
  lv_style_reset(&style_label);

  lv_style_set_text_font(&style_label, &lv_font_montserrat_14);
  lv_style_set_text_opa(&style_label, LV_OPA_100);
  lv_style_set_text_color(&style_label, lv_color_white());

  lv_style_init(&style_btn);
  lv_style_set_border_width(&style_btn, 1);
  lv_style_set_border_opa(&style_btn, LV_OPA_100);
  lv_style_set_border_color(&style_btn, lv_color_white());

  lv_obj_t * exit_btn = lv_btn_create(scr_1);
  lv_obj_add_style(exit_btn, &style_btn, 0);
  lv_obj_set_size(exit_btn, 80, 30);
  lv_obj_align(exit_btn, LV_ALIGN_CENTER, 0,0);
  lv_obj_add_event_cb(exit_btn, screen2_event_handler, LV_EVENT_CLICKED, NULL);

  lv_obj_t * exit_btn_label = lv_label_create(exit_btn);
  lv_obj_add_style(exit_btn_label, &style_label, 0);
  lv_label_set_text(exit_btn_label, "screen 2");
  lv_obj_align_to(exit_btn_label, exit_btn, LV_ALIGN_CENTER, 0, 0);
}

I hope that makes sense…

Kind Regards,

Pete

Great, my problem was immediately resolved. Thank you pete!

Hi pete, are these two lines of code unnecessary?

Hi @gui_lvgl ,

Can you show which lines?

Kind Regards,

Pete

Oh, sorry forget.

Hi @gui_lvgl ,

If you are just setting the same set of style parameters in each screen then no, as you will just overwrite the setting when the new screen is created.

Kind Regards,

Pete

I am currently using styles separately for each screen, but now I have found that the problem still exists. I think reset_ style will release the previous memory, and there will be no available styles for the next use.

Hi @gui_lvgl ,

My apologies, if you are testing with my posted example I left a line which should have been removed:

Does this work okay for you now:

static  lv_obj_t *scr_1;
static  lv_obj_t *scr_2;

static  lv_style_t style_btn;
static  lv_style_t style_label;
static	bool first_run = false;

void create_screen_1(void);
void create_screen_2(void);

static void screen1_event_handler(lv_event_t *e)
{
  lv_event_code_t code = lv_event_get_code(e);
  switch (code)
  {
    case LV_EVENT_CLICKED:
    {
      lv_obj_del(scr_1);
      create_screen_2();
    }
    break;

    default: break;
  }
}

static void screen2_event_handler(lv_event_t *e)
{
  lv_event_code_t code = lv_event_get_code(e);
  switch (code)
  {
    case LV_EVENT_CLICKED:
    {
      lv_obj_del(scr_2);
      create_screen_1();
    }
    break;

    default: break;
  }
}

void create_screen_1(void)
{
  scr_1 = lv_obj_create(NULL);
  lv_scr_load(scr_1);

  if( !first_run ) {
	  lv_style_init(&style_label);
	  lv_style_init(&style_btn);
	  first_run = true;
  }

  lv_style_set_text_font(&style_label, &lv_font_montserrat_18);
  lv_style_set_text_opa(&style_label, LV_OPA_100);
  lv_style_set_text_color(&style_label, lv_color_black());

  lv_style_set_border_width(&style_btn, 1);
  lv_style_set_border_opa(&style_btn, LV_OPA_100);
  lv_style_set_border_color(&style_btn, lv_color_black());

  lv_obj_t * exit_btn = lv_btn_create(scr_1);
  lv_obj_add_style(exit_btn, &style_btn, 0);
  lv_obj_set_size(exit_btn, 80, 30);
  lv_obj_align(exit_btn, LV_ALIGN_CENTER, 0,0);
  lv_obj_add_event_cb(exit_btn, screen1_event_handler, LV_EVENT_CLICKED, NULL);

  lv_obj_t * exit_btn_label = lv_label_create(exit_btn);
  lv_obj_add_style(exit_btn_label, &style_label, 0);
  lv_label_set_text(exit_btn_label, "screen 1");
  lv_obj_align_to(exit_btn_label, exit_btn, LV_ALIGN_CENTER, 0, 0);
}

void create_screen_2(void)
{
  scr_2 = lv_obj_create(NULL);
  lv_scr_load(scr_2);

  if( !first_run ) {
	  lv_style_init(&style_label);
	  lv_style_init(&style_btn);
	  first_run = true;
  }

  lv_style_set_text_font(&style_label, &lv_font_montserrat_14);
  lv_style_set_text_opa(&style_label, LV_OPA_100);
  lv_style_set_text_color(&style_label, lv_color_white());

  lv_style_set_border_width(&style_btn, 1);
  lv_style_set_border_opa(&style_btn, LV_OPA_100);
  lv_style_set_border_color(&style_btn, lv_color_white());

  lv_obj_t * exit_btn = lv_btn_create(scr_1);
  lv_obj_add_style(exit_btn, &style_btn, 0);
  lv_obj_set_size(exit_btn, 80, 30);
  lv_obj_align(exit_btn, LV_ALIGN_CENTER, 0,0);
  lv_obj_add_event_cb(exit_btn, screen2_event_handler, LV_EVENT_CLICKED, NULL);

  lv_obj_t * exit_btn_label = lv_label_create(exit_btn);
  lv_obj_add_style(exit_btn_label, &style_label, 0);
  lv_label_set_text(exit_btn_label, "screen 2");
  lv_obj_align_to(exit_btn_label, exit_btn, LV_ALIGN_CENTER, 0, 0);
}

I will also post an alternative method which you can consider which will use slightly less memory and code, give me a bit of time…

Kind Regards,

Pete

No, actually I have multiple screens and I need to switch between them. Although I do this on every screen, I find that there is a Memory leak. What is the reason for this?

Hi @gui_lvgl ,

Can you check through all your screens and make sure you haven’t left any lv_style_init() calls like I did? Also do you allocate any other memory for other purposes? If so make sure you free it when you delete the screen.
I can confirm the code I have posted above is no leaking memory after many switches…

If you can not spot the issue after carefully checking, if you are able to you are welcome to send me your code and I will check through it, if that is helpful… (petebone00@gmail.com)

Kind Regards,

Pete

Hi @gui_lvgl ,

In the examples you gave above you are using one style per object, there is not really any point having a style set up if you are not going to use it with many objects. If this is how you are doing things in general then I would suggest using the following approach which I use in my own projects:

static  lv_obj_t *scr_1;
static  lv_obj_t *scr_2;

void create_screen_1(void);
void create_screen_2(void);

static void screen1_event_handler(lv_event_t *e)
{
  lv_event_code_t code = lv_event_get_code(e);
  switch (code)
  {
    case LV_EVENT_CLICKED:
    {
      lv_obj_del(scr_1);
      create_screen_2();
    }
    break;

    default: break;
  }
}

static void screen2_event_handler(lv_event_t *e)
{
  lv_event_code_t code = lv_event_get_code(e);
  switch (code)
  {
    case LV_EVENT_CLICKED:
    {
      lv_obj_del(scr_2);
      create_screen_1();
    }
    break;

    default: break;
  }
}

void create_screen_1(void)
{
  scr_1 = lv_obj_create(NULL);
  lv_scr_load(scr_1);

  lv_obj_t * exit_btn = lv_btn_create(scr_1);
  lv_obj_set_style_border_width(exit_btn, 1, LV_PART_MAIN);
  lv_obj_set_style_border_opa(exit_btn, LV_OPA_100, LV_PART_MAIN);
  lv_obj_set_style_border_color(exit_btn, lv_color_black(), LV_PART_MAIN);
  lv_obj_set_size(exit_btn, 80, 30);
  lv_obj_align(exit_btn, LV_ALIGN_CENTER, 0,0);
  lv_obj_add_event_cb(exit_btn, screen1_event_handler, LV_EVENT_CLICKED, NULL);

  lv_obj_t * exit_btn_label = lv_label_create(exit_btn);
  lv_obj_set_style_text_font(exit_btn_label, &lv_font_montserrat_18, LV_PART_MAIN);
  lv_obj_set_style_text_opa(exit_btn_label, LV_OPA_100, LV_PART_MAIN);
  lv_obj_set_style_text_color(exit_btn_label, lv_color_black(), LV_PART_MAIN);
  lv_label_set_text(exit_btn_label, "screen 1");
  lv_obj_align_to(exit_btn_label, exit_btn, LV_ALIGN_CENTER, 0, 0);
}

void create_screen_2(void)
{
  scr_2 = lv_obj_create(NULL);
  lv_scr_load(scr_2);

  lv_obj_t * exit_btn = lv_btn_create(scr_1);
  lv_obj_set_style_border_width(exit_btn, 1, LV_PART_MAIN);
  lv_obj_set_style_border_opa(exit_btn, LV_OPA_100, LV_PART_MAIN);
  lv_obj_set_style_border_color(exit_btn, lv_color_white(), LV_PART_MAIN);
  lv_obj_set_size(exit_btn, 80, 30);
  lv_obj_align(exit_btn, LV_ALIGN_CENTER, 0,0);
  lv_obj_add_event_cb(exit_btn, screen2_event_handler, LV_EVENT_CLICKED, NULL);

  lv_obj_t * exit_btn_label = lv_label_create(exit_btn);
  lv_label_set_text(exit_btn_label, "screen 2");
  lv_obj_set_style_text_font(exit_btn_label, &lv_font_montserrat_14, LV_PART_MAIN);
  lv_obj_set_style_text_opa(exit_btn_label, LV_OPA_100, LV_PART_MAIN);
  lv_obj_set_style_text_color(exit_btn_label, lv_color_white(), LV_PART_MAIN);
  lv_obj_align_to(exit_btn_label, exit_btn, LV_ALIGN_CENTER, 0, 0);
}

I hope that is helpful.

Kind Regards,

Pete

Hi pete,

I have carefully checked the code and found no issues. Your second method will cause too much change, and I prefer the first method. I have already sent the code to your email.

Hi pete,

When I asked about the mouse display issue in the forum, I thought it might be the configuration of the input device that caused the crash. Can you see if this is the case?
lv_port_indev.c (10.8 KB)

Hi @gui_lvgl ,

I am currently looking at your project in the simulator, which I have just got going, I needed to do a few modifications, but I now have it up and running. I have one question can you tell me your working screen resolution please?

I will take a look at everything, I just need a bit of time :slight_smile:

Kind Regards,

Pete