Petición REST en segundo plano
En la encuesta pasada el 66% de los votantes han pedido algún tema relacionado con REST para este artículo y tal como lo han pedido aquí va.
Es común que en los sistemas que hacen peticiones a un servidor REST necesitemos hacer peticiones en segundo plano, utilizando un hilo diferente, ¿Esto para qué? Hoy en día cuando estamos por ejemplo desarrollando para un dispositivo móvil es muy necesario (por no decir obligatorio) el uso de hilos en todos los aspectos y así evitar esos “odiosos” mensajes donde le indican al usuario que la aplicación está bloqueada y le preguntan si quieren cerrarla…
O por ejemplo cuando traemos información en un ListView, Grid o en lo que sea que traigas información, pero queremos que además las imágenes se carguen en segundo plano y no se bloquee la aplicación mientras el usuario puede hacer otra cosa. En fin, el límite en cuanto a la utilidad de poder hacer una petición REST en segundo plano lo pone tu imaginación.
En este artículo supongo que ya sabes cómo hacer una petición normal con los componentes TRESTClient, TRESTResponse y TRESTRequest (Dicho sea de paso hay cientos de ejemplos que muestran cómo hacerlo, la documentación online tiene un ejemplo bastante claro en su DocWiki e incluso si buscas en YouTube). Una vez dicho esto, regreso al tema de este artículo.
Hoy en día hay varias formas de lograr el cometido expuesto hasta aquí, entre ellas por ejemplo hacer algo como lo siguiente:
1 2 3 4 5 6 | TThread.CreateAnonymousThread( procedure begin RESTRequest1.Execute; Memo1.Text := RESTResponse1.Content; end).Start; |
A simple vista, esto ejecutaría la petición en segundo plano y escribiría el resultado (Un valor JSON) en el TMemo. Pero como bien se sabe tenemos que sincronizar la interfaz con el hilo y seguramente también el RESTRequest1 al tratarse de un objeto puesto en tiempo de diseño y común para todos los objetos en dicha aplicación. Quedando algo más o menos así…
1 2 3 4 5 6 7 8 9 10 | TThread.CreateAnonymousThread( procedure begin TThread.Synchronize(TThread.CurrentThread, procedure begin RESTRequest1.Execute; Memo1.Text := RESTResponse1.Content; end); end).Start; |
Ya hemos sincronizado todo, pero algunos se preguntarán… ¿Entonces cuál es la gracia de usar otro hilo si vamos a sincronizar todo con el hilo principal?, quizá evitamos de alguna manera el error aquel donde dice que la aplicación no responde, aunque nótese el “quizá”.
Es por eso que una opción más acorde al asunto podría ser crear los 3 componentes “El trio maravilla” en tiempo de ejecución y utilizarlos, así:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | TThread.CreateAnonymousThread( procedure var vClient: TRESTClient; vRequest: TRESTRequest vResponse: TRESTResponse; begin vClient := TRESTClient.Create(nil); vRequest := TRESTRequest.Create(nil); vResponse := TRESTResponse.Create(nil); try vClient.BaseURL := RUTA_URI; //Supongamos que RUTA_URI es una constante con la ruta vRequest.Client := vClient; vRequest.Response := vResponse; vRequest.Execute; TThread.Synchronize(TThread.CurrentThread, procedure begin Memo1.Text := RESTResponse1.Content; end; finally vClient.Free; vResponse.Free; vRequest.Free; end); end).Start; |
Lo anterior ejecutaría la petición en segundo plano y sincronizaría con el hilo principal, únicamente cuando lo necesitamos, o sea al colocar el valor en el TMemo. Eso es mejor, pues logramos el objetivo real.
Al analizar el componente TRESTRequest vemos que tiene ya implementado un método para esta labor, supongamos que aún tenemos este “trio maravilla” declarado globalmente o colocados en nuestra aplicación en tiempo de diseño… podríamos usar lo siguiente:
1 2 3 4 5 6 7 8 9 | RESTRequest1.ExecuteAsync( procedure begin TThread.Synchronize(TThread.CurrentThread, procedure begin Memo1.Text := RESTResponse1.Content; end); end, False); |
ExecuteAsync tiene 3 parámetros, el primero (ACompletionHandler) es un método anónimo de tipo TProc, donde podemos poner lo que queremos que el sistema haga después de ejecutar la petición, el segundo (ASynchronized) es un parámetro de tipo Boolean que básicamente es para indicar si preferimos que ExecuteAsync se encargue de sincronizar el ACompletionHandler o lo haremos nosotros (para este ejemplo me he encargado yo mismo del asunto) y por último (AFreeThread) que básicamente es para indicarle al hilo que se crea si se debe liberar automaticamente al terminar o no (el famoso FreeOnTerminate), por defecto es True.
Y bueno, eso es todo por hoy, espero que este artículo les sea de utilidad. Bye.
Impresionante, no tengo ni idea de estas cosas.
Saludos.
Un gusto tenerte por acá :), saludos. No dudes en preguntar en todo caso, quizá alguien sepa la respuesta :D.
una pregunta he visto los componentes de aniindicator y el ksloading indicator he visto que no pueden estar en un mismo proceso incluso ni esperando a que terminen mi pregunta es si declaro una tarea o hilo intermedia entre decirle al indicador empiese y termine no afectaran estos su funcion de verse en rimer plano y este hilo dejara correr la animacion de estos ??
La verdad nunca he usado la combinación de estos 2 componentes, sin embargo en teoría deberías activar los 2 en el hilo principal y correr tu proceso en el hilo secundario.
Aunque como te indico, no he probado lo que comentas, mezclando ambos componentes. Sin embargo quedo con la duda y en algún momento probaré tu caso.
Buenas Tardes, me encuentro con un problema, al momento de consumir un servicio rest con api_key uso delphi seattle con los componentes TRestClient, TRestRequest y TRestResponse; al hacer el llamado al servicio me genera un bad request; pero la verdad es que no se como adicionarle el cuerpo del mensaje(que contiene el api_key, archivo xml en base64) .
En mi codigo simplemente hago esto:
RQEsDinamico.Resource := ‘”api_key”:”zonui4iuedo6sy0480oeon69564j6g29″, “xml”:”‘+Codi+'”, “adjunto”:false, “contingencia”:”false”, “prefijo”:”PRUE”‘;
Cualquier ayuda sera bienvenida.
Muchas gracias