Потоки на планшете Android вызывают зависания - PullRequest
0 голосов
/ 02 ноября 2018

Я работаю над приложением Firemonkey в Delphi Tokyo и решил добавить экран загрузчика, который выполняет некоторую анимацию. У меня есть форма с анимацией списка, которая выполняется в одном потоке, а затем мои вызовы к серверу datasnap выполняются в другом потоке. Я делаю это так, потому что я не мог заставить анимацию работать, если оба вызова не были внутри потока.

Теперь запуск этой версии для Windows работает нормально. Запуск его как на моем телефоне Huawei, так и на другом планшете Samsung работает в 70% случаев. Остальные 30% времени он зависает, и мне приходится убивать приложение. После завершения загрузки datasnap форма загрузчика должна быть освобождена и закрыта, а непрозрачность основных панелей установлена ​​на 1, и я снова включаю панель. Я не уверен на 100%, если приложение зависает, и если код не запускается успешно, это должно снова включить панель. Я смог отладить его один раз, когда не работал, что вызвало ошибку нехватки памяти, но я не могу воссоздать проблему во время отладки на телефоне.

Идея заключалась в том, что при нажатии кнопки регистрации на экране загрузчика отображается некоторая анимация во время извлечения данных, а затем она снова скрывается. Я делаю что-то не так в приведенном ниже коде?

  ShowLoader;

  fThread := TTask.Create
  (
    procedure ()
    begin
      try
        LoDataset := fmxDataModule.ServerMethods.GetLoginDetails(edtEmail.Text, edtPassword.Text);
      except on E:Exception do
        begin
          TThread.Synchronize(TThread.CurrentThread,
            procedure()
            begin
              ShowMessage('The system could not log you in.  Error Details: '+slinebreak+slinebreak+E.Message+slinebreak+slinebreak+'Please try again.');
              HideLoader;
            end
          )
        end;
      end;

      TThread.Synchronize(TThread.CurrentThread,
        procedure()
        begin
          fmxDataModule.LoggedInUser.LoadFromDataset(LoDataset);
          if fmxDataModule.LoggedInUser.CompanyID.Value > 0 then
          begin
            Toolbarheader.Visible := True;
            lblLoginInfo.Visible := false;
            lblWelcome.Text := 'Welcome ' + fmxDataModule.LoggedInUser.FirstName.Value + ', ' + fmxDataModule.LoggedInUser.LastName.Value;
            GoToProfilesTab.Execute;
            GenerateProfiles;
            pnlButtons.Visible := True;
            fLoggedIn := True;
            FormResize(nil);
          end else
          begin
            lblLoginInfo.Visible := True;
            lblLoginInfo.Text := 'User does not exist, or login details invalid';
          end;
        end
      );

      HideLoader;
    end
  );

  fThread.Start;

Вот код для ShowLoader:

procedure TfrmLogin.CreateLoaderForm;
begin
  if Assigned(fLoader) then
    FreeAndNil(fLoader);
  fLoader := TfrmLoader.Create(Self);
  floader.Parent := Self;
  fLoader.Left := Self.Left + (Self.Width div 2) - (fLoader.Width div 2);
  fLoader.Top  := Self.Top + (Self.Height div 2) - (fLoader.Height div 2);
  fLoader.Show;
end;

procedure TfrmLogin.ShowLoader;
begin

  pnlMain.Enabled := false;
  pnlMain.Opacity := 0.4;

  TTask.Create (
    procedure ()
        begin

          TThread.Queue(TThread.CurrentThread,
            procedure()
            begin
              CreateLoaderForm
            end);

        end
    ).Start;

end;

Скрытие загрузчика:

procedure TfrmLogin.HideLoader;
begin
  pnlMain.Enabled := True;
  pnlMain.Opacity := 1;
//  pnlMain.Repaint;
  fLoader.Visible := False;
end;

Я что-то упустил в коде выше?

Другой вопрос, почему моя форма не открывается в середине экрана? Я пробовал разные вещи, устанавливая положение в свойствах формы и вычисляя вручную. Он всегда открывается в верхнем левом углу на устройстве, но работает на Windows.

1 Ответ

0 голосов
/ 05 ноября 2018

Попробовав другой подход, предложенный @nolaspeaker, и синхронизировав поля имени пользователя и пароля, например, предложенные @RemyLebeau, я удалил загрузчик форм, который находился в другом потоке, и проблема все еще не устранена. После этого стало очевидно, что в приведенном ниже фрагменте кода, который я разместил изначально, должна быть проблема, только немного измененная:

TThread.CreateAnonymousThread
  (
    procedure
    var
      LsUsername,LsPassword:String;
    begin
      try
        TThread.Synchronize(TThread.CurrentThread,
          procedure()
          begin
            LsUsername := edtEmail.Text;
            LsPassword := edtPassword.Text;
          end
        );

        LoDataset := fmxDataModule.ServerMethods.GetLoginDetails(LsUsername, LsPassword);
      except on E:Exception do
        begin
          TThread.Synchronize(TThread.CurrentThread,
            procedure()
            begin
              ShowMessage('The system could not log you in.  Error Details: '+slinebreak+slinebreak+E.Message+slinebreak+slinebreak+'Please try again.');
              HideLoader;
            end
          )
        end;
      end;


      TThread.Synchronize(TThread.CurrentThread,
        procedure()
        begin
          fmxDataModule.LoggedInUser.LoadFromDataset(LoDataset);
          if fmxDataModule.LoggedInUser.CompanyID.Value > 0 then
            GoToProfilesTab.Execute
          else
          begin
            lblLoginInfo.Visible := True;
            lblLoginInfo.Text := 'User does not exist, or login details invalid';
          end;
        end
      );

      HideLoader;
    end
  ).Start;

Попытка еще пару раз отладить сценарий, который я закончил в TTabControl.SetActiveTabWithTransition.

Проблема возникает в этой строке

LocalAnimateIntWait(Layout2, 'Position.X', Round(P.X), Duration, TAnimationType.In,
              TInterpolationType.Linear);

в этом блоке кода:

procedure TTabControl.SetActiveTabWithTransition(const ATab: TTabItem; ATransition: TTabTransition;
const ADirection: TTabTransitionDirection = TTabTransitionDirection.Normal);

  ...
begin
  case ATransition of
    TTabTransition.Slide:
      begin
        FTransitionRunning := True;
        ClipChildren := True;
        try
          ...

          if ADirection = TTabTransitionDirection.Normal then
          begin
            P...
          end
          else
          begin
            ...


            LocalAnimateIntWait(Layout2, 'Position.X', Round(P.X), Duration, TAnimationType.In,
              TInterpolationType.Linear);


          end;
        finally
          SetLength(FTransitionTabs, 0);
          ClipChildren := False;
          FTransitionRunning := False;
          Realign;
        end;
        // Force repaint
        Application.ProcessMessages;
      end
  else
    ActiveTab := ATab;
  end;
end;

Так что я удаляю вкладку, переходящую для этого одного клика, и она, наконец, работает как положено. В тот момент, когда я возвращаю переход к слайду, он снова останавливается на этой линии. Я обязательно сообщу об этой проблеме.

...