ActiveDelphi - Índice do Fórum ActiveDelphi
.: O site do programador Delphi! :.
 
 FAQFAQ   PesquisarPesquisar   MembrosMembros   GruposGrupos   RegistrarRegistrar 
 PerfilPerfil   Entrar e ver Mensagens ParticularesEntrar e ver Mensagens Particulares   EntrarEntrar 

Problemas com Application.ProcessMessasges no Tokyo

 
Novo Tópico   Responder Mensagem    ActiveDelphi - Índice do Fórum -> Mobile com Delphi
Exibir mensagem anterior :: Exibir próxima mensagem  
Autor Mensagem
valdiralbertod@gmail.com
Novato
Novato


Registrado: Sábado, 14 de Julho de 2018
Mensagens: 6

MensagemEnviada: Sáb Jul 14, 2018 6:48 pm    Assunto: Problemas com Application.ProcessMessasges no Tokyo Responder com Citação

Boa noite,

Até o Delphi Berlin, para apresentar uma mensagem ao usuário e aguardar a resposta dele para depois executar a rotina X ou a rotina Y, eu utilizava a função abaixo e funcionava legal.

class function TFuncoes.MsgConfirmacao(VMsg : String) : boolean;
Var
VModalResult : TModalResult;
begin
MessageDlg(VMsg, System.UITypes.TMsgDlgType.mtConfirmation,
[System.UITypes.TMsgDlgBtn.mbYes, System.UITypes.TMsgDlgBtn.mbNo], 0,
procedure(const AResult: TModalResult)
begin
VModalResult := AResult;
end);

While VModalResult = mrNone do application.ProcessMessages;

Result := VModalResult = mrYes;
end;

Porém, no Delphi Tokyo, o sistema congela ao executar essa função. Nas pesquisa que fiz, parece que o problema está no application.ProcessMessages que agora (com o Tokyo) gera um resultado diferente no processamento quando SO Android.
A minha dúvida é: alguém tem alguma rotina, sugestão ou qualquer dica que possa me passar em relação a essa questão?
O que preciso é apresentar uma pergunta ao usuário e somente depois da resposta executar determinada rotina.
Encontrei inúmeros artigos e até com e exemplos sobre isso, mas nada funciona. Parece que no Android não funciona nada sincrono. Tem que ser tudo assíncrono.

Agradeço qualquer ajuda.
Obrigado.
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
strak2012
Colaborador
Colaborador


Registrado: Segunda-Feira, 13 de Janeiro de 2014
Mensagens: 1518
Localização: Maceió - AL

MensagemEnviada: Sáb Jul 14, 2018 9:21 pm    Assunto: Responder com Citação

Com o uso de thread tem a questão resolvida.
_________________
Tudo podemos quando tudo sabemos!
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular Enviar E-mail MSN Messenger
valdiralbertod@gmail.com
Novato
Novato


Registrado: Sábado, 14 de Julho de 2018
Mensagens: 6

MensagemEnviada: Dom Jul 15, 2018 9:06 am    Assunto: Responder com Citação

strak2012 escreveu:
Com o uso de thread tem a questão resolvida.


Bom dia,
Obrigado pela resposta.

Eu fiz uma thread colocando toda a minha class function TFuncoes.MsgConfirmacao(VMsg : String) : boolean dentro da thread. No Windows funciona beleza, mas no Android ele congela (trava) do mesmo jeito que s executada fora da thread.

Na verdade eu não tenho muito conhecimento com threads...você poderia me ajudar com algumas dicas de como iniciar? Talvez um pequeno exemplo?

Obrigado.[/b]
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
igormoita
Profissional
Profissional


Registrado: Quinta-Feira, 14 de Janeiro de 2010
Mensagens: 601

MensagemEnviada: Seg Jul 16, 2018 9:41 am    Assunto: Responder com Citação

Thread é um assunto complexo, visto que ela deve rodar fora da Aplicação em um novo processo no CPU. Acontece que com o FMX alguns detalhes na sua utilização mudaram, segue código para utilização de AnonymousThread para o FMX (testado no Windows e Android):

https://textuploader.com/dzzmv

Acontece que ao utilizarmos Thread o sistema executa um processo fora do Aplication para realização da seu código, isso quer dizer que seu código fora da Thread vai rodar normalmente msm se a Thread não terminar, aqui temos dois detalhes:
1º: Se vc precisa de qualquer informação de retorno da Thread, vai ter que bolar um jeito de 'aguardar' a finalização;
2º: Qualquer interação da Thread para com qualquer objeto criado em Application deve ser executado dentro de um TThread.Synchronize (segue no código). Esse comando obriga a Thread a sincronizar com o objeto da aplicação (esse objeto pode ser uma variável, componente, class, etc);

Para o 1º caso existem vários contextos, um dos que eu utilizo é na hora de realizar o Login: aciono a Thread para fazer o Login, inicio no Application um Timer que irá esperar o fim da Thread, após o fim da Thread (try finally end) eu preencho uma variável para informar ao Timer que o Login finalizou, daí pego os retornos e valido. Existem várias outras formas de se 'esperar', esse é um exemplo;

Uma observação no 2º caso, passamos meses tentando solucionar um problema com a Thread, onde se perdia os resultados que precisávamos, apenas às vezes dava o erro, na maioria o sistema funcionava perfeitamente, apenas com o Synchronize passou a dar 100% certo. Não posso te dizer exatamente como utilizar, pois Thread é um assunto muito delicado, espero que estas dicas facilitem teu aprendizado nessa área.
_________________
SEMPRE COLOQUE [RESOLVIDO] NO SEU POST
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular Enviar E-mail Yahoo Messenger MSN Messenger
valdiralbertod@gmail.com
Novato
Novato


Registrado: Sábado, 14 de Julho de 2018
Mensagens: 6

MensagemEnviada: Seg Jul 16, 2018 10:30 am    Assunto: Responder com Citação

igormoita escreveu:
Thread é um assunto complexo, visto que ela deve rodar fora da Aplicação em um novo processo no CPU. Acontece que com o FMX alguns detalhes na sua utilização mudaram, segue código para utilização de AnonymousThread para o FMX (testado no Windows e Android):

https://textuploader.com/dzzmv

Acontece que ao utilizarmos Thread o sistema executa um processo fora do Aplication para realização da seu código, isso quer dizer que seu código fora da Thread vai rodar normalmente msm se a Thread não terminar, aqui temos dois detalhes:
1º: Se vc precisa de qualquer informação de retorno da Thread, vai ter que bolar um jeito de 'aguardar' a finalização;
2º: Qualquer interação da Thread para com qualquer objeto criado em Application deve ser executado dentro de um TThread.Synchronize (segue no código). Esse comando obriga a Thread a sincronizar com o objeto da aplicação (esse objeto pode ser uma variável, componente, class, etc);

Para o 1º caso existem vários contextos, um dos que eu utilizo é na hora de realizar o Login: aciono a Thread para fazer o Login, inicio no Application um Timer que irá esperar o fim da Thread, após o fim da Thread (try finally end) eu preencho uma variável para informar ao Timer que o Login finalizou, daí pego os retornos e valido. Existem várias outras formas de se 'esperar', esse é um exemplo;

Uma observação no 2º caso, passamos meses tentando solucionar um problema com a Thread, onde se perdia os resultados que precisávamos, apenas às vezes dava o erro, na maioria o sistema funcionava perfeitamente, apenas com o Synchronize passou a dar 100% certo. Não posso te dizer exatamente como utilizar, pois Thread é um assunto muito delicado, espero que estas dicas facilitem teu aprendizado nessa área.


Bom dia,
Beleza Igor. Vou me aprofundar na questão. Suas dicas foram de grande ajuda.
Obrigado.
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
valdiralbertod@gmail.com
Novato
Novato


Registrado: Sábado, 14 de Julho de 2018
Mensagens: 6

MensagemEnviada: Qua Jul 18, 2018 10:27 am    Assunto: Responder com Citação

igormoita escreveu:
Thread é um assunto complexo, visto que ela deve rodar fora da Aplicação em um novo processo no CPU. Acontece que com o FMX alguns detalhes na sua utilização mudaram, segue código para utilização de AnonymousThread para o FMX (testado no Windows e Android):

https://textuploader.com/dzzmv

Acontece que ao utilizarmos Thread o sistema executa um processo fora do Aplication para realização da seu código, isso quer dizer que seu código fora da Thread vai rodar normalmente msm se a Thread não terminar, aqui temos dois detalhes:
1º: Se vc precisa de qualquer informação de retorno da Thread, vai ter que bolar um jeito de 'aguardar' a finalização;
2º: Qualquer interação da Thread para com qualquer objeto criado em Application deve ser executado dentro de um TThread.Synchronize (segue no código). Esse comando obriga a Thread a sincronizar com o objeto da aplicação (esse objeto pode ser uma variável, componente, class, etc);

Para o 1º caso existem vários contextos, um dos que eu utilizo é na hora de realizar o Login: aciono a Thread para fazer o Login, inicio no Application um Timer que irá esperar o fim da Thread, após o fim da Thread (try finally end) eu preencho uma variável para informar ao Timer que o Login finalizou, daí pego os retornos e valido. Existem várias outras formas de se 'esperar', esse é um exemplo;

Uma observação no 2º caso, passamos meses tentando solucionar um problema com a Thread, onde se perdia os resultados que precisávamos, apenas às vezes dava o erro, na maioria o sistema funcionava perfeitamente, apenas com o Synchronize passou a dar 100% certo. Não posso te dizer exatamente como utilizar, pois Thread é um assunto muito delicado, espero que estas dicas facilitem teu aprendizado nessa área.


Bom dia Igor,

Desculpe a insistência Igor, mas não estou conseguindo e não há quase nenhum material na net sobre o assunto. Estou há 60 dias nessa peleja, rs...sem progresso, hehe!
Se puder me ajudar fazendo um exemplo funcional. Gostaria inclusive de lhe pagar por isso. Se for o caso me manda uma msg em pv (ou WhatsApp 41-99709-5622) para combinarmos.

Vou relatar como tentei fazer, mas sem sucesso.

Var
VThread: TThread;
VFModal : TFModalResult;
begin
VControle := 0; //é uma variável global.
VThread := TThread.CreateAnonymousThread(procedure ()
begin
TThread.Synchronize(TThread.CurrentThread,
procedure ()
begin
//FModalResult é um form que tem 3 botões. Quando clica no primeiro botão, VControle := 1.
if VFModal = nil then VFModal := TFModalResult.Create(nil);
VFModal.ShowModal(procedure(ModalResult: TModalResult)
begin
While VControle = 0 do Application.ProcessMessages; //isto deveria parar a aplicação com o VFModal na tela até que o usuário clique no botão lá no VFModal, mas não pára.
end);
end);
end);
VThread.FreeOnTerminate := True;
VThread.Start();

//isto acontece mesmo sem o usuário ter clicado lá no FModal
ShowMessage('Daqui em diante só deve processar após thread, ou seja, após o usuário ter clicado no botão fo VModal');
end;


Obrigado.
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
igormoita
Profissional
Profissional


Registrado: Quinta-Feira, 14 de Janeiro de 2010
Mensagens: 601

MensagemEnviada: Qua Jul 18, 2018 11:16 am    Assunto: Responder com Citação

Desculpe, mas acabei de passando uma dica errada. Esqueça a utilização de Thread neste caso, não irá facilitar a solução, deixe o código como estava sem a Thread, vamos fazer de uma outra forma.

(mas sugiro que aprenda a utilizar Thread para outros casos, ajuda muito para deixar o App fluido)

Vamos para minha solução para seu problema (Apresentar um MessageDiolog e "esperar" resposta):

Links ao final.
No Fontes1 é um código que eu utilizo em um Biblioteca.pas, basicamente é uma unit compartilhada com vários outros projetos, tentei deixar o mais padrão possível para ser utilizada em Units ou Units de Forms (não sei quais alterações seriam necessárias para uma UnitForm);

No Fontes2 é um exemplo de chamada para o código do Fontes1.

Basicamente estou utilizado o MessageDialog do FMX, mas executo um procedimento no caso se a resposta for mrYes (Sim). Neste caso específico eu vou executar um procedimento que obrigatoriamente recebe um parâmetro do tipo TObject, fiz o exemplo assim pois apanhei horrores para migrar da execução Sem parâmetro para o Com Parâmetro. Deixei no Fontes1 detalhes para que vc consiga fazer a execução sem parâmetros, até sugiro que vc altere e teste sem, pois é mais fácil de entender, mas já mandei com parâmetro para diminuir o tempo de aprendizagem.

Pelo que me lembre este código funciona igualmente para Desktop (Windows) e Mobile (Android), não testei em outras plataformas.

Fontes1: https://textuploader.com/dz708
Fontes2: https://textuploader.com/dz7kd

(Dica: sempre faça testes em projetos novos, pois é mais fácil vc controlar seus erros. Se vc for testar em seu projeto completo pode ser que um erro externo cause falhas e vc terá dificuldade para saber se foi no seu código novo ou não)
_________________
SEMPRE COLOQUE [RESOLVIDO] NO SEU POST
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular Enviar E-mail Yahoo Messenger MSN Messenger
valdiralbertod@gmail.com
Novato
Novato


Registrado: Sábado, 14 de Julho de 2018
Mensagens: 6

MensagemEnviada: Qua Jul 18, 2018 2:29 pm    Assunto: Responder com Citação

igormoita escreveu:
Desculpe, mas acabei de passando uma dica errada. Esqueça a utilização de Thread neste caso, não irá facilitar a solução, deixe o código como estava sem a Thread, vamos fazer de uma outra forma.

(mas sugiro que aprenda a utilizar Thread para outros casos, ajuda muito para deixar o App fluido)

Vamos para minha solução para seu problema (Apresentar um MessageDiolog e "esperar" resposta):

Links ao final.
No Fontes1 é um código que eu utilizo em um Biblioteca.pas, basicamente é uma unit compartilhada com vários outros projetos, tentei deixar o mais padrão possível para ser utilizada em Units ou Units de Forms (não sei quais alterações seriam necessárias para uma UnitForm);

No Fontes2 é um exemplo de chamada para o código do Fontes1.

Basicamente estou utilizado o MessageDialog do FMX, mas executo um procedimento no caso se a resposta for mrYes (Sim). Neste caso específico eu vou executar um procedimento que obrigatoriamente recebe um parâmetro do tipo TObject, fiz o exemplo assim pois apanhei horrores para migrar da execução Sem parâmetro para o Com Parâmetro. Deixei no Fontes1 detalhes para que vc consiga fazer a execução sem parâmetros, até sugiro que vc altere e teste sem, pois é mais fácil de entender, mas já mandei com parâmetro para diminuir o tempo de aprendizagem.

Pelo que me lembre este código funciona igualmente para Desktop (Windows) e Mobile (Android), não testei em outras plataformas.

Fontes1: https://textuploader.com/dz708
Fontes2: https://textuploader.com/dz7kd

(Dica: sempre faça testes em projetos novos, pois é mais fácil vc controlar seus erros. Se vc for testar em seu projeto completo pode ser que um erro externo cause falhas e vc terá dificuldade para saber se foi no seu código novo ou não)


Muitíssimo obrigado Igor.

Consegui fazer funcionar, mas ocorre um probleminha. Não sei se fiz algo errado ou que foi...

Chamando a função (button 1) conforme abaixo, tudo certo
procedure TFPrincipal.Button1Click(Sender: TObject);
begin
inherited;
ShowMessageYesNo('Faz uma pergunta?', Sender, ExecutarSeForSim);
end;



Mas, se chamar a função mais de uma vez a função (button 2) conforme abaixo, aí ele inverte a ordem quando em Android (no Windows blz), ou seja, executa a terceira chamada, depois a segunda e depois a primeira.
procedure TFPrincipal.Button2Click(Sender: TObject);
begin
inherited;
ShowMessageYesNo('Faz a primeira pergunta?', Sender, ExecutarSeForSim1); //no Android isto é executado por terceiro
ShowMessageYesNo('Faz a segunda pergunta?', Sender, ExecutarSeForSim2); //no Android isto é executado por segundo
ShowMessageYesNo('Faz a segunda pergunta?', Sender, ExecutarSeForSim3); //no Android isto é executado por primeiro
end;


Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
igormoita
Profissional
Profissional


Registrado: Quinta-Feira, 14 de Janeiro de 2010
Mensagens: 601

MensagemEnviada: Qua Jul 18, 2018 3:50 pm    Assunto: Responder com Citação

Na realidade a ordem de execução está correta, mas provavelmente a lógica de execução não.

No Android (não sei no iOS) realmente as coisas são assíncronas, ou seja, vai executar o primeiro ShowMessage, depois o segundo e depois o terceiro, como está escrito no seu código, sendo assim é certo apresentar de 'trás para frente', visto que a msg 3 sobrepõe a 2 e a 1, consequentemente.

O correto nessa estratégia seria vc colocar os ShowMessage dentro dos procedures, por exemplo:
ExecutarSeForSim1 executa o ShowMessage2;
ExecutarSeForSim2 executa o ShowMessage3;
Etc...

Daí vc faz só a primeira chamada

procedure TFPrincipal.Button2Click(Sender: TObject);
begin
inherited;
ShowMessageYesNo('Faz a primeira pergunta?', Sender, ExecutarSeForSim1);
end;


Tecnicamente dizendo o Android vai executar tudo depois do ShowMessage, mas só vai executar a Procedure se a pessoa clicar em Sim.

procedure TFPrincipal.Button2Click(Sender: TObject);
begin
inherited;
ShowMessageYesNo('Faz a primeira pergunta?', Sender, ExecutarSeForSim1);
StrToIn('1'); // Sera executado mesmo sem escolher Sim ou Nao
//Mas a procedure ExecutarSeForSim1 so sera executada se clicar em Sim, msm se o sistema excutou estas linhas apos o ShowMessage
end;


Sabendo disso, tudo que vc quer que seja executado em caso de SIM deve ser codificado dentro da procedure ExecutarSeForSim1 (que foi enviada no ShowMessage)
_________________
SEMPRE COLOQUE [RESOLVIDO] NO SEU POST
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular Enviar E-mail Yahoo Messenger MSN Messenger
valdiralbertod@gmail.com
Novato
Novato


Registrado: Sábado, 14 de Julho de 2018
Mensagens: 6

MensagemEnviada: Qui Jul 19, 2018 7:30 am    Assunto: Responder com Citação

igormoita escreveu:
Na realidade a ordem de execução está correta, mas provavelmente a lógica de execução não.

No Android (não sei no iOS) realmente as coisas são assíncronas, ou seja, vai executar o primeiro ShowMessage, depois o segundo e depois o terceiro, como está escrito no seu código, sendo assim é certo apresentar de 'trás para frente', visto que a msg 3 sobrepõe a 2 e a 1, consequentemente.

O correto nessa estratégia seria vc colocar os ShowMessage dentro dos procedures, por exemplo:
ExecutarSeForSim1 executa o ShowMessage2;
ExecutarSeForSim2 executa o ShowMessage3;
Etc...

Daí vc faz só a primeira chamada

procedure TFPrincipal.Button2Click(Sender: TObject);
begin
inherited;
ShowMessageYesNo('Faz a primeira pergunta?', Sender, ExecutarSeForSim1);
end;


Tecnicamente dizendo o Android vai executar tudo depois do ShowMessage, mas só vai executar a Procedure se a pessoa clicar em Sim.

procedure TFPrincipal.Button2Click(Sender: TObject);
begin
inherited;
ShowMessageYesNo('Faz a primeira pergunta?', Sender, ExecutarSeForSim1);
StrToIn('1'); // Sera executado mesmo sem escolher Sim ou Nao
//Mas a procedure ExecutarSeForSim1 so sera executada se clicar em Sim, msm se o sistema excutou estas linhas apos o ShowMessage
end;


Sabendo disso, tudo que vc quer que seja executado em caso de SIM deve ser codificado dentro da procedure ExecutarSeForSim1 (que foi enviada no ShowMessage)


Beleza, vou tentar implementar.
Muito obrigado. Foi de grande ajuda.

Abraços.
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
Mostrar os tópicos anteriores:   
Novo Tópico   Responder Mensagem    ActiveDelphi - Índice do Fórum -> Mobile com Delphi Todos os horários são GMT - 3 Horas
Página 1 de 1

 
Ir para:  
Enviar Mensagens Novas: Proibido.
Responder Tópicos Proibido
Editar Mensagens: Proibido.
Excluir Mensagens: Proibido.
Votar em Enquetes: Proibido.


Powered by phpBB © 2001, 2005 phpBB Group
Traduzido por: Suporte phpBB