#android #flutter
#Android #флаттер
Вопрос:
Я делаю проект в Flutter, в котором я получаю скорость передачи данных в реальном времени с помощью API, и я получаю свою скорость, но не могу отобразить на своем экране, что она равна нулю ..! код ниже:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'coin_data.dart';
import 'dart:io' show Platform;
import 'networking.dart';
class PriceScreen extends StatefulWidget {
@override
_PriceScreenState createState() => _PriceScreenState();
}
class _PriceScreenState extends State<PriceScreen> {
BitNetwork bitNetwork = BitNetwork('$BitCoinURL/BTC/USD?apikey=$BitCoinKey');
int bitRate;
void getCurrentBitRate() async {
dynamic bitData = await bitNetwork.getData();
double temp = bitData['rate'];
bitRate = temp.toInt();
print(bitRate);
}
String selectedCurrency = 'USD';`enter code here`
@override
Widget build(BuildContext context) {
getCurrentBitRate();
return Scaffold(
appBar: AppBar(
title: Text('Coin Ticker'),
),`enter code here`
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(18.0, 18.0, 18.0, 0),
child: Card(
color: Colors.lightBlueAccent,
elevation: 5.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 15.0, horizontal: 28.0),
child: Text(
'1 BTC = $bitRate USD',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
),
),
),
Container(
height: 150.0,
alignment: Alignment.center,
padding: EdgeInsets.only(bottom: 30.0),
color: Colors.lightBlue,
child: Platform.isIOS ? iOSPicker() : androidDropdown()),
],
),
);
}
}
ответ в консоли:
I / flutter (14181): 47131
I / flutter (14181): 47131
I / flutter (14181): 47129
вывод на экран = 1 BTC = null USD. => ????
Ответ №1:
Вам нужно дождаться загрузки валюты, оберните свой виджет в FutureBuilder
:
Future<int> getCurrentBitRate() async {
dynamic bitData = await bitNetwork.getData();
double temp = bitData['rate'];
return temp.toInt();
}
// build method
child: FutureBuilder<int>(
future: getCurrentBitRate(),
builder (context, snapshot) {
if (snapshot.hasData) {
final bitRate = snapshot.data;
return Column(
// Your column here.
);
}
return CircularProgressIndicator();
}
),
Кроме того, вы можете найти дополнительную информацию о том, как работать с асинхронными функциями здесь, и прочитать больше об этом FutureBuilder
здесь .
Ответ №2:
Проблема в том, что вы не ожидаете getCurrentBitRate(), и вы также вызываете его в своем методе сборки. В методе сборки должен быть только код пользовательского интерфейса. Что я рекомендую вам сделать, так это переопределить initState() и вызвать его там (все еще не могу его дождаться, но он будет вызван перед сборкой);
@override
initState(){
getCurrentBitRate();
super.initState();
}
Это поможет решить вашу проблему, но это не лучшее решение. Я рекомендую посмотреть учебные пособия по какой-либо внешней системе управления состоянием, такой как BLoC, Provider и / или RxDart. Это значительно упростит отладку подобных ситуаций.
Ответ №3:
bitRate
Значение null
связано с тем, что вы вызываете его в build
функции, а ваш метод getCurrentBitRate()
является async
методом, что означает, что метод будет ждать получения значения, но до тех пор ваш build
метод уже завершит рендеринг виджетов с bitRate
сохранением значения null
.
Есть несколько способов исправить это, но я бы порекомендовал следующий:
Вызовите свой метод getCurrentBitRate()
в initState
методе и удалите его из build
функции, так как это первый метод, который запускается в вашем виджете и используется setState
, чтобы обновленное значение bitRate
отображалось в вашем виджете.
class _PriceScreenState extends State<PriceScreen> {
BitNetwork bitNetwork = BitNetwork('$BitCoinURL/BTC/USD?apikey=$BitCoinKey');
int bitRate;
@override
void initState() {
super.initState();
getCurrentBitRate(); // Call it in initState amp; use setState
}
void getCurrentBitRate() async {
dynamic bitData = await bitNetwork.getData();
double temp = bitData['rate'];
bitRate = temp.toInt();
print(bitRate);
if (mounted) { // <--- mounted property checks whether your widget is still present in the widget tree
setState((){}); // Will update the UI once the value is retrieved
}
}
String selectedCurrency = 'USD';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Coin Ticker'),
),`enter code here`
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(18.0, 18.0, 18.0, 0),
child: Card(
color: Colors.lightBlueAccent,
elevation: 5.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 15.0, horizontal: 28.0),
child: Text(
'1 BTC = $bitRate USD',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
),
),
),
Container(
height: 150.0,
alignment: Alignment.center,
padding: EdgeInsets.only(bottom: 30.0),
color: Colors.lightBlue,
child: Platform.isIOS ? iOSPicker() : androidDropdown()),
],
),
);
}
}
Ответ №4:
Это значение равно нулю, потому что при build()
вызове getCurrentBitRate()
оно еще не завершило свою работу.
Для этих операций FutureBuilder
это один из лучших виджетов. Ему просто нужно a future
и a builder
, чтобы объявить, что делать после получения данных.
// CHANGE TO FUTURE STYLE
Future<Int> getCurrentBitRate() async {
dynamic bitData = await bitNetwork.getData();
double temp = bitData['rate'];
bitRate = temp.toInt();
print(bitRate);
return bitRate;
}
Затем измените структуру сборки на это
// DECLARE A FUTURE FOR getCurrentBitRate()
Future _future;
initState(){
_future = await getCurrentBitRate();
super.initState();
}
@override
Widget build(BuildContext context) {
// getCurrentBitRate(); REMOVE THIS LINE
return FutureBuilder(
future: _future,
builder: (context, snapshot) {
if(snapshot.hasData){
// YOUR DATA IS READY
double temp = snapshot.data['rate'];
// JUST CONTINUE REST OF ORIGINAL CODE BELOW
return Scaffold(
appBar: AppBar(
title: Text('Coin Ticker'),
),
...
}
}
);