Contamos con la contestación a este atolladero, al menos eso pensamos. Si sigues con inquietudes puedes dejar un comentario y sin dudarlo te responderemos
Solución:
FutureBuilder
elimina el código repetitivo.
Supongamos que desea obtener algunos datos del backend al iniciar la página y mostrar un cargador hasta que lleguen los datos.
Tareas para ListBuilder:
- Tener dos variables de estado,
dataFromBackend
yisLoadingFlag
- En el lanzamiento, configurar
isLoadingFlag = true
, y en base a esto, mostrarloader
. - Una vez que lleguen los datos, configure los datos con lo que obtiene del backend y configure
isLoadingFlag = false
(dentrosetState
obviamente) - Necesitamos tener un
if-else
en la creación de widgets. SiisLoadingFlag
estrue
, mostrar laloader
más muestra eldata
. Si falla, muestra un mensaje de error.
Tareas para FutureBuilder:
- Dar la tarea asincrónica en
future
de Future Builder - Residencia en
connectionState
, Mostrar mensaje (loading
,active(streams)
,done
) - Residencia en
data(snapshot.hasError)
, mostrar vista
Ventajas de FutureBuilder
- No usa las dos variables de estado y
setState
- Programación reactiva (
FutureBuilder
se encargará de actualizar la vista a la llegada de los datos)
Ejemplo:
FutureBuilder(
future: _fetchNetworkCall, // async work
builder: (BuildContext context, AsyncSnapshot snapshot)
switch (snapshot.connectionState)
case ConnectionState.waiting: return Text('Loading....');
default:
if (snapshot.hasError)
return Text('Error: $snapshot.error');
else
return Text('Result: $snapshot.data');
,
)
Impacto en el rendimiento:
Solo miré en el FutureBuilder
código para entender el rendimiento impacto de usar esto.
- FutureBuilder es solo un
StatefulWidget
cuyostate
variable es_snapshot
- El estado inicial es
_snapshot = AsyncSnapshot
.withData(ConnectionState.none, widget.initialData); - Se está suscribiendo a
future
que enviamos a través del constructor y actualizamos elstate
basado en eso.
Ejemplo:
widget.future.then((T data)
if (_activeCallbackIdentity == callbackIdentity)
setState(()
_snapshot = AsyncSnapshot.withData(ConnectionState.done, data);
);
, onError: (Object error)
if (_activeCallbackIdentity == callbackIdentity)
setState(()
_snapshot = AsyncSnapshot.withError(ConnectionState.done, error);
);
);
Entonces el FutureBuilder
es un envoltorio / caldera de lo que hacemos normalmente, de ahí que no debe tener ningún impacto en el rendimiento.
Ejemplo de FutureBuilder
-
Cuando desee rander el widget después de la llamada asíncrona, use
FutureBuilder()
class _DemoState extends State
@override Widget build(BuildContext context) return FutureBuilder ( future: downloadData(), // function where you call your api builder: (BuildContext context, AsyncSnapshot snapshot) // AsyncSnapshot if( snapshot.connectionState == ConnectionState.waiting) return Center(child: Text('Please wait its loading...')); else if (snapshot.hasError) return Center(child: Text('Error: $snapshot.error')); else return Center(child: new Text('$snapshot.data')); // snapshot.data :- get your object which is pass from your downloadData() function , ); Future downloadData()async // var response = await http.get('https://getProjectList'); return Future.value("Data download successfully"); // return your response
En el constructor futuro, llama a la función futura para esperar el resultado, y tan pronto como produce el resultado, llama a la función del constructor donde construimos el widget.
AsyncSnapshot tiene 3 estados:
- connectionState.none = En este estado el futuro es null
- connectionState.waiting = [future] no es null, pero aún no ha completado
- connectionState.done = [future] no es null, y se ha completado. Si el futuro se completó con éxito, el [AsyncSnapshot.data] se establecerá en el valor al que se completó el futuro. Si se completó con un error, [AsyncSnapshot.hasError] estarán true