Como encerrar uma aplicação no dispositivo Android através de uma Caixa de Diálogo simples com Delphi XE5. Evitando que o usuário saia da aplicação por acidente.

Situação a que se aplica

Imagine aquela situação em que o usuário está com seu dispositivo móvel na mão e acaba esbarrando sem querer na tecla voltar, que ao ser tocada finaliza a aplicação que ele estava interagindo. A solução abordada nesta postagem visa solucionar este pequeno contratempo que nossos usuários podem fatidicamente estar sujeitos.

Screenshot_2014-07-26-14-00-11

MessageDlg: Funciona ou não???

Desenvolvedor Delphi de longa data tem conhecimento da função MessageDlg. Na VCL publicada na unit Dialogs, a função é capaz de retornar para a aplicação o valor da resposta dada pelo usuário a uma determinada pergunta na caixa de mensagem.  Veja abaixo um exemplo da sua utilização em aplicações VCL:

procedure TForm1.Button1Click(Sender: TObject);
begin
  if MessageDlg('Esta é a MessageDlg. Você já a conhecia?',
    mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrYes then

end;

Um pouco mais sobre MessageDlg você pode encontrar na Embarcadero DocWiki e uma ótima referência também é encontrada na Delphi Basics.

Entretanto ao tentar fazer uso da MessageDlg na plataforma mobile (Firemonkey) digitando e compilando seu código, recebemos a mensagem de erro: “Undeclared identifier” para os tipos e botões da caixa de mensagem como pode ser observado na imagem abaixo:

Erro ao compilar MessageDlg

Então para solucionar este caso, ao utilizarmos MessageDlg para desenvolvermos  Mobile no Delphi XE5  devemos declarar este tipos com Namespaces completos como: TMsgDlgTypeTMsgDlgBtn. Veja abaixo como ficaria a declaração da função:

MessageDlg('Deseja realmente fechar a aplicação?',
        TMsgDlgType.mtConfirmation,[TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 
        0, TMsgDlgBtn.mbNo)

 Definindo a Interface do Usuário

Para colocarmos em prática o que realmente é proposto no título da postagem vamos iniciar um novo projeto Mobile em branco no Delphi XE5. Como já fizemos em diversas postagens aqui no blog. Neste projeto vamos inserir 1 Button e 1 TImage, e vamos alterar suas propriedades como a lista abaixo:

  • Button1
    • Align -> alBottom
    • Text -> ‘Sair’
    • TextAlign -> taCenter
  • Image1
    • Align -> alClient
    • MultiResBitmap -> [selecione uma imagem de sua preferência]
    • WrapMode -> iwStretch

Com isso definimos a interface de usuário da aplicação, ao final teremos algo muito próximo da imagem abaixo:

Interface do Usuário da Aplicação

Na prática: Permitir o encerramento da aplicação apenas através de uma confirmação do usuário.

A ideia é que o usuário ao clicar no botão sair chame o método Close da aplicação, e no evento onCloseQuery faremos o tratamento da resposta do usuário à nossa MessageDlg. Vamos codificar essa ideia.

No clique do botão insira o código:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Close;
end;

Para podermos fazer uso da função do Android de encerrar a Activity da Aplicação precisamos declarar o Namespace FMX.Helpers.Android na cláusula uses da seção implementation da Unit de nosso formulário:

implementation

uses FMX.Helpers.Android;

{$R *.fmx}

Já o evento onCloseQuery do nosso formulário,  vamos codificar como a seguir:

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
 if MessageDlg('Deseja realmente fechar a aplicação?',
        TMsgDlgType.mtConfirmation,[TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0, TMsgDlgBtn.mbNo) = mrYes  then
   begin
      CanClose := True;
      SharedActivity.finish
   end
 else
  begin
    CanClose := False;
    ShowMessage('Você respondeu não');
  end;
end;

Note que temos até aí puro código Delphi, a exceção da linha SharedActivity.Finish. Que vem nativamente do Android sendo responsável por retirar nosso apk de execução.

Até a próxima e confira o resultado na galeria de fotos abaixo.

31 Replies to “Encerrar aplicação Android através de Caixa de Diálogo com Delphi XE5”

    1. Olá Nilton, seja muito bem vindo!
      Insira no seu projeto a Unit FMX.Consts, ela contém as constantes das mensagens. Sendo bem específico à sua pergunta, procure pela Seção {Dialog Strings}, aí é só efetuar a tradução!

      { Dialog Strings }
      SMsgDlgWarning = 'Warning';
      SMsgDlgError = 'Error';
      SMsgDlgInformation = 'Information';
      SMsgDlgConfirm = 'Confirm';
      SMsgDlgYes = 'Yes';
      SMsgDlgNo = 'No';
      SMsgDlgOK = 'OK';
      SMsgDlgCancel = 'Cancel';
      SMsgDlgHelp = 'Help';
      SMsgDlgHelpNone = 'No help available';
      SMsgDlgHelpHelp = 'Help';
      SMsgDlgAbort = 'Abort';
      SMsgDlgRetry = 'Retry';
      SMsgDlgIgnore = 'Ignore';
      SMsgDlgAll = 'All';
      SMsgDlgNoToAll = 'No to All';
      SMsgDlgYesToAll = 'Yes to &All';
      SMsgDlgClose = 'Close';

      SWindowsVistaRequired = '%s requires Windows Vista or later';

      SUsername = '&Username';
      SPassword = '&Password';
      SDomain = '&Domain';
      SLogin = 'Login';

      Espero tê-lo ajudado! E não deixe de postar seu feedback!
      Até mais!

  1. Landerson, é possível fazer aquelas mensagens suspensas no rodapé do aparelho (apenas aviso), tipo de se conectando no wifi ou salvando algo que em segundos desaparece?

    Obrigado,

    até mais.

    1. Olá Alexandre… bem vindo ao blog!
      Bem se entendi bem o que você está querendo vai atender por TNotificationCenter. Abaixo um vídeo de como implementar às notificações, obviamente você vai ter que adaptá-las aos eventos que deseja “policiar”, ex: Wi-fi se tiver desligada receber notificação.

      Veja o vídeo:

      Espero que ajude!
      E mais uma vez obrigado por sua participação!

      1. Obrigado amigo!
        Já conhecia o TNotification, mas acredito que não seja ele responsável por essa mensagem no rodapé, pelo menos todos os exemplos que olhei ele usa o titleBar para exibir as notificações.
        A mensagem que vejo meu aparelho fazendo são mensagens no rodapé, tipo quando faço um print para área de transferência, duro é não saber nem o nome da tecnologia, rs!! Abraço e obrigado.

    1. Olá Andreik… primeiramente seja muito bem vindo ao blog!!! Como relação ao erro, o ideal seria sinalizar qual versão do Delphi você está utilizando.
      A partir do XE6 se não me engano as mensagens passam a ser feitas para plataforma Android utilizando outra forma.

      Obrigado por sua participação!

    2. var
      loCanClose: Boolean;
      begin
      MessageDLG(‘Deseja realmente fechar a aplicação?’, system.UITypes.TMsgDlgType.mtConfirmation, [
      system.UITypes.TMsgDlgBtn.mbYes,
      system.UITypes.TMsgDlgBtn.mbNo],0,
      procedure (const AResult : TModalResult)
      begin
      case AResult of
      mrYes : begin
      loCanClose:= True;
      SharedActivity.finish
      end;
      else
      loCanClose := False;
      end;
      end);
      CanClose := loCanClose;

        1. Olá Filipe obrigado pela parabenização! Primeiramente seja bem vindo! Bom tê-lo interagindo com as postagens e mais ainda saber que está sendo útil, esse é o propósito!

          Bem como a evolução do Delphi como plataforma de desenvolvimento multi-dispositivo vimos uma mudança nos códigos de alguns diálogos (DIALOGS) no Delphi.
          Isso explica-se na Embarcadero DocWiki assim: Se uma chamada para MessageDlg não inclui o parâmetro, a chamada é de bloqueio em todas as plataformas; ou seja, MessageDlg não retornar até que a caixa de diálogo é fechada. Android não suporta estas chamadas de bloqueio, você só pode usar MessageDlg no Android se você fornecer a como parâmetro.

          Dá uma olhada aí: http://docwiki.embarcadero.com/Libraries/XE7/en/FMX.Dialogs.MessageDlg. Eu estava preparando uma postagem sobre o assunto, talvez eu retome e coloque no ar em breve.

          Espero que ajude e consiga!
          Poste aqui um feedback depois!

          Abração e boa sorte aí!

          EDITADO –> Acabei de finalizar o post, fica aí o link: DELPHI XE7 ANDROID E DIALOGS, O QUE MUDOU?

          1. Olá Landerson. Estou com um problema para encerrar meu app. Após X minutos estou mandando fechar com o comando close no form principal. Para isso utilizo um Ttimer. Se eu estou com o app ativo em primeiro plano, está funcionando normal, mas se o app está em 2º plano não está rolando. Depois do tempo passaram-se abrir o app e ele está travado, fica numa tela preta. Pelo jeito o close está funcionando em partes. Tenho a sensação que o form fecha mas o app não. Após esperar um tempo até o SO perguntar se que fechar o app, quando respondo sim. Meu app abre. Você sabe outra maneira de encerrar um app? Vou tentar um application.Terminate. Mas não sei ainda se p Android aceita. Obrigado pela atenção. Abs. Vinicius

  2. Olá, estou com o mesmo problema do Vinicius de não fechar
    corretamente e quando tentar abrir novamente travar.

    try
    DM.CONEXAO.Connected := False;
    Self.Hide;
    SharedActivity.Finish;
    MainActivity.finish;
    Application.MainForm.DisposeOf;
    except
    on E : Exception do
    begin
    Application.MainForm.DisposeOf;
    end;
    end;

    1. Olá Reijanio, o exemplo em questão foi feito com o Delphi XE5, não me recordo o Android do aparelho na época o que pode ser um diferencial, entretanto gostaria de sugerir um revisão nos processos do tutorial afim verificar a persistência do erro.

      Desde já agradeço sua participação e seja bem vindo!

  3. Bom dia Landerson, parabéns pelo post.
    Desejo tirar uma dúvida:
    Efetuei alteração na Unit FMX.Consts, Seção {Dialog Strings}, em seguida inseri a Unit FMX.Consts no projeto e executei o projeto, mas a tradução não funcionou.
    O label: (Confirm – para Confirmar), (Yes – Sim) e (No – Não), não foram alterados.
    Será que esta faltando mais algum procedimento?

    1. Olá Antônio Carlos, bem vindo!
      Primeiramente peço desculpas pela demora em respondê-lo…
      É possível você subir seu código para algum servidor na nuvem e me mandar o link?
      Não vejo outra forma de ajudá-lo que não seja conferindo aqui o que está acontecendo.

      Desde já agradeço sua participação e aguardo seu retorno!
      Até+

    2. Boa tarde Landerson!
      Parabéns pelos teus posts. Eu também fiz as modificações na Unit FMX.Consts, Seção {Dialog Strings}, em seguida inseri a Unit FMX.Consts no projeto e executei o projeto, mas a tradução não funcionou.
      Obrigado

      1. Bom dia!

        Somente um detalhe em relação ao problema da unit FMX.Cconsts, quando executado no Windows as mensagens aparecem em português, mas no Android aparecem em Inglês.
        Rafael

  4. Olá Landerson e amigos que comentaram.
    Se na versão do Delphi que você usa, aparecer o erro Undeclared identifier: ‘SharedActivity’, ao invés de usar FMX.Helpers.Android, use Androidapi.Helpers.
    Isso resolve o problema.

  5. Fala Landerson, beleza chefe ?

    Landerson foi de grande ajuda esse dica, porém, eu tive um pequeno problema de declaração na function SharedActivity.Finish, eu tive que implementar na uses a classe Android.Helpers também, só queria deixar registrado, caso alguém estivesse passando pelo mesmo BO que eu. Muito obrigado pela ajuda.

    OBS: Estou usando o Berlin UPDATE2

    Vaaaleu !

    1. MessageDlg(‘Deseja realmente sair do aplicativo?’, TMsgDlgType.mtConfirmation,
      [TMsgDlgBtn.mbNo, TMsgDlgBtn.mbYes], 0,
      procedure (const AResult: TModalResult)
      begin
      if AResult = mrYes then
      begin
      {$IFDEF ANDROID}
      SharedActivity.Finish;
      {$ENDIF}

      {$IFDEF MSWINDOWS}
      Exit;
      {$ENDIF}
      end
      else
      Abort;
      end);

      Para dar certo no Android e Windows usei dessa forma, na Uses tive que separar também oque é Android e Windows, se não ele não compilava. Não sei se é o certo, mas foi oque funcionou aqui kkkkkkkkkk. Vaaaaaaleu !

    2. Eu denovo kkkk, quando compilei o código, a IDE me disse que o MessageDlg estava um pouco obsoleto e que eu deveria usar o TDialogService da classe FMX.DialogService. Bom muda 2 coisinha só, vou postar aqui , Vaaaaleeeuu.

      TDialogService.MessageDialog(‘Deseja realmente sair do aplicativo?’, System.UITypes.TMsgDlgType.mtInformation,
      [System.UITypes.TMsgDlgBtn.mbYes, System.UITypes.TMsgDlgBtn.mbNo], System.UITypes.TMsgDlgBtn.mbYes, 0,
      procedure(const AResult: TModalResult)
      begin
      case AResult of
      mrYes: begin
      {$IFDEF ANDROID}
      SharedActivity.Finish;
      {$ENDIF}

      {$IFDEF MSWINDOWS}
      Application.Terminate;
      {$ENDIF}
      end;
      mrNo: begin
      Abort;
      end;
      end;
      end);

      1. Olá José Lucas… Obrigado por sua participação!
        Vi aí que você percebeu algumas mudanças evolutivas desde a época que escrevi o código. Na verdade é fundamental ler as mensagens do compilador, que no seu caso devem ter indicado como “deprecated”.
        Que bom que compartilhou, e mais uma vez obrigado por sua participação.

        Grande abraço e seja muito bem vindo!

Deixe um comentário