Перейти к содержанию
Fire Monkey от А до Я
  • 0

Зависает программа, использующая фреймы (Android)


Major

Вопрос

Господа, помогите пожалуйста разобраться, в чем проблема.

В программе одна форма, на ней табконтрол с двумя вкладками. TabPosition - None. Одна вкладка выполняет роль меню, из которой можно перейти во вторую вкладку, куда грузится фрейм.

Если возвращаться в главную вкладку из фрейма через обработку OnKeyUp, то всё норм, без зависаний:

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
var KeyChar: Char; Shift: TShiftState);
begin
  if (Key = vkHardwareBack) then
  begin
    Key := 0;
    if (TabControl1.ActiveTab = TabItem1) then
      Close
    else
      TabControl1.ActiveTab := TabItem1;
  end;
end;

А если через кнопку внутри фрейма

  Form1.TabControl1.ActiveTab := Form1.TabItem1;

то виснет.

Уничтожаю фрейм так:

procedure TForm1.TabControl1Change(Sender: TObject);
begin
  if (TabControl1.ActiveTab = TabItem1) then
    if (FFrame <> nil) then
    begin
      FFrame.Parent := nil;
      FFrame.DisposeOf;
      FFrame := nil;
    end;
end;

 

 

 

 

 

Ссылка на комментарий

Рекомендуемые сообщения

  • 0
3 часа назад, Major сказал:

А если через кнопку внутри фрейма


  Form1.TabControl1.ActiveTab := Form1.TabItem1;

 

1). Я так понимаю эта строка в модуле фрейма? Похоже на циклическую ссылку. Uses в модуле фрейма ссылается на Form1, а Form1 ссылается на модуль фрейма?
2). Вы создаете фрейм каждый раз при открытии TabItem2? Много ли контролов на фрейме? Создание фрейма с контролами в рантайм на андроиде - затратная по времени операция. Если программа использует не много фреймов, то я бы не создавал/удалял каждый раз фрейм при смене таба, а использовал фрейм созданный один раз. Это улучшит отзывчивость программы.

Ну а причина зависания - то, что вы в процедуре обработчика кнопки фрейма OnClick вызываете TForm1.TabControl1Change и там удаляете этот фрейм и саму кнопку.

Изменено пользователем enatechno
Ссылка на комментарий
  • 0
4 часа назад, enatechno сказал:



Ну а причина зависания - то, что вы в процедуре обработчика кнопки фрейма OnClick вызываете TForm1.TabControl1Change и там удаляете этот фрейм и саму кнопку.

а как можно решить эту проблему? как перейти из фрейма на главную вкладку не только через vkHardwareBack?

вот приложил тестовый проект

Test.zip

Ссылка на комментарий
  • 0

запустил программу через отладчик, получил такую ситуацию. Открывается FMX.Controls, а в нем:

procedure TControl.MouseClick(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
  if FPressed and not(FDoubleClick) and PointInObjectLocal(X, Y) then
  begin
    Click;
    FPressed := False;
    StartTriggerAnimation(Self, 'Pressed');
  end;
end;

 

Ссылка на комментарий
  • 0

 

1 час назад, Major сказал:

а как можно решить эту проблему? как перейти из фрейма на главную вкладку не только через vkHardwareBack?

1 Вариант. Заменой удаления фреймов на скрытие (подправленный проект приложил).
2 Вариант. Расположить панель с кнопкой Back на главной форме, а не дублировать ее в каждом фрейме. (При необходимости саму кнопку Back можно скрывать при возврате на первый таб).
3 Вариант. Использовать отложенное удаление фрейма).
 ...
и еще много разных вариантов.

1 час назад, Major сказал:

кстати, подскажите, как можно извлечь полезную информацию из этого окна?

    Click;
    FPressed := False;
    StartTriggerAnimation(Self, 'Pressed')

Отладчик выдал ошибку в методе объекта TControl (в Вашем случае это кнопка SpeedButton1 на фрейме). В этом методе в Click вы удаляете Frame, а значит и кнопку на ней. А в строке StartTriggerAnimation(Self, 'Pressed'); вы обращаетесь к этой удаленной кнопке (Self). Здесь и происходит AV.

test2.zip

Изменено пользователем enatechno
Ссылка на комментарий
  • 0

enatechno,

спасибо за ответ!

1 Вариант. Заменой удаления фреймов на скрытие (подправленный проект приложил).

Фреймов будет много и они будут не такими голыми, как в тестовом примере, поэтому скрывать/показывать - не подойдет (думаю, что быстро кончится память).

2 Вариант. Расположить панель с кнопкой Back на главной форме, а не дублировать ее в каждом фрейме. (При необходимости саму кнопку Back можно скрывать при возврате на первый таб).

Идея интересная, только тогда получится два тулбара (один - для Back, второй - для самого фрейма, где на тулбаре будет несколько кнопок). Не очень красиво

3 Вариант. Использовать отложенное удаление фрейма (например в потоке).

а есть пример? интересно очень

Ссылка на комментарий
  • 0
if (TabControl1.ActiveTab = TabItem1) then
    if (FFrame <> nil) then
    begin
      FFrame.Parent := nil;
      FFrame.DisposeOf;
      FFrame := nil;
    end;

вместо этого написать:
 

if (TabControl1.ActiveTab = TabItem1) then
  if Assigned(FFrame) then
    begin
      FFrame.Release;
      FFrame := nil;
    end;

Этого будет достаточно, чтобы завершились все обработчики событий и в то же время не было новых обращений к этому фрейму.

 

Кстати, вам уже рекомендовалось использовать именно Release. Но, видимо, вам нравятся кактусы.

Изменено пользователем kami
Ссылка на комментарий
  • 0

kami,

спасибо за помощь.

В статье Я.Бровина про удаление объектов под Андроидом ни слова о методе Release:

http://yaroslavbrovin.ru/object_life_cycle_in_delphi_part_2_android_ios-ru/

Ссылка на комментарий
  • 0
  • Модераторы
22 минуты назад, Major сказал:

kami,

спасибо за помощь.

В статье Я.Бровина про удаление объектов под Андроидом ни слова о методе Release:

http://yaroslavbrovin.ru/object_life_cycle_in_delphi_part_2_android_ios-ru/

Метод Release как раз нужно использовать когда удаляешь "сам из себя"

На пальцах это выглядит так:

  • при вызове метода Release объект помещается в список/очередь
  • запускается таймер с интервалом 10 мсек, в котором идёт очистка этой очереди
  • при очистке используется метод DisposeOf

Не нужно везде использовать этот метод, только при крайней необходимости

Ссылка на комментарий
  • 0
1 час назад, Major сказал:

Фреймов будет много и они будут не такими голыми, как в тестовом примере, поэтому скрывать/показывать - не подойдет (думаю, что быстро кончится память).

Тут нужна золотая середина. Если фрейм на устройстве будет строится более 0.1 сек, то рекомендую использовать скрытие.

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...