The method goes to the line that calls the method that calls it, without moving to the lines after the await keyword
class WordAndMeaning extends StatelessWidget {
WordAndMeaning({super.key});
final viewModel = locator<HomeViewModel>();
#override
Widget build(BuildContext context) {
return Observer(
builder: (_) {
if (viewModel.userDailyRight == null) {
return const CircularProgressIndicator();
} else if (viewModel.userDailyRight == 0) {
return const Text(
"Out of your limit",
style: TextStyle(color: Colors.red, fontSize: 20),
);
} else if (viewModel.userDailyRight != 0 && !viewModel.isWordsPulled) {
viewModel.runPullWord();
if (viewModel.isStartedWordPulling) {
return const CircularProgressIndicator();
}
I run runPullWord after check userDailyRight and isWordsPulled at this stateless widget.
List<String> wordList = [
"pencil",
"headphone",
"bag",
"door",
"dress",
"bin",
];
final String _apiLink = "https://api.dictionaryapi.dev/api/v2/entries/en/";
#action
runPullWord() async {
isStartedWordPulling = true;
learnedWordKey = await pullLearnedWordsKeys();
wordAndMeanList = await pullWord();
setRandomWordIndexRightNow();
}
#action
Future<List<String>> pullLearnedWordsKeys() async {
return (await _firestore
.doc("students/$userID/learnedwords/learnedwords")
.get())
.data()!
.keys
.toList();
}
#action
Future<List<WordModel>> pullWord() async {
List<WordModel> localWordAndMeanList = [];
isWordsPulled = false;
try {
for (String word in learnedWordKey) {
wordList.remove(word);
}
for (int i = 0; i < wordList.length; i++) {
_response = await Dio().get(_apiLink +
wordList[
i]);
_pulledData = _response.data;
List<WordModel> currentWord =
((_pulledData as List).map((e) => WordModel.fromMap(e)).toList());
localWordAndMeanList.add(currentWord[0]);
}
isStartedWordPulling = false;
isWordsPulled = true;
return localWordAndMeanList;
} catch (e) {
debugPrint(e.toString());
return Future.error(e);
}
}
When the line with _response works here, the program goes back to the viewModel.runPullWord() line in the widget as soon as it comes to the await keyword and the pullWord method is not completed(_response is still null). In this way, the pullWord method is repeatedly executed.
This situation made me question my knowledge. Why did this situation occur? How can I solve this?
Related
My problem is that when I run the app, the data doesn't show up on the UI. The code below is rendered under a bottom navigation bar format which is a stateful widget. To my knowledge the below code should work (show data on the initial running of app).
The code works but the data is only shown when I press hot reload. I've tried everything that I know but it still doesn't show data when I start the app.
final imageControllerProvider = Provider((ref) {
return ImageController();
});
final mainScreenImages = FutureProvider<List<String>>((ref) async {
List<String> list = [];
list = await ref.watch(imageControllerProvider).getImages();
return list;
});
class ImageController{
Future<List<String>> getImages() async {
List<String> imageUrls = [];
try {
final Reference reference = _storage.ref().child("weed/");
reference.listAll().then((value) {
for (var element in value.items) {
element.getDownloadURL().then((e) => imageUrls.add(e));
}
});
} catch (e) {
print(e);
}
return imageUrls;
}
}
class GenerateImages extends ConsumerWidget {
const GenerateImages({super.key});
#override
Widget build(BuildContext context, WidgetRef ref) {
final imageList = ref.watch(mainScreenImages);
final double screenwidth = MediaQuery.of(context).size.width;
final double screenheight = MediaQuery.of(context).size.height;
return imageList.when(data: (data) {
return Text('$data');
}, error: (_, __) {
return const Scaffold(
body: Center(
child: Text("OOPS"),
),
);
}, loading: () {
return const Center(child: const CircularProgressIndicator());
});
}
}
I think the problem is because in getImages() you are not awaiting the results instead you are using the then() handler to register callbacks. Replace your getImages() function with this and try.
Future<List<String>> getImages() async {
List<String> imageUrls = [];
try {
final Reference reference = _storage.ref().child("weed/");
final value = await reference.listAll();
for (var element in value.items) {
final url = await element.getDownloadURL();
imageUrls.add(url);
}
} catch (e) {
print(e);
}
return imageUrls;
}
}
I am trying to use a connected bluetooth device on other pages, but I'm unable to do that. I tried to use the provider, but that did not work, parameter passing did not work either.
After testing, I am using the following
I made a class ReactiveProvider
class ReactiveProvider(){
Stream<ConnectionStateUpdate> get currentConnectionStream {
return flutterReactiveBle.connectToAdvertisingDevice(
id: _foundBleUARTDevices[index].id,
prescanDuration: const Duration(seconds: 1),
withServices: [_uartUuid, _uartRx, _uartTx],
);
}
}
and setup in start
void main() {
runApp(
MultiProvider(providers: [
StreamProvider<ConnectionStateUpdate>(
create: (context) => ReactiveProvider().currentConnectionStream,
initialData: const ConnectionStateUpdate(
deviceId: "",
connectionState: DeviceConnectionState.disconnected,
failure: null),
)
], child: const MainApp()),
);
}
and in StatefullWidget
final _currentConnectionStream = Provider.of<ConnectionStateUpdate>(context);
I got the errors
The instance member 'context' can't be accessed in an initializer.
Try replacing the reference to the instance member with a different expression
and
The method 'listen' isn't defined for the type 'ConnectionStateUpdate'.
Try correcting the name to the name of an existing method, or defining a method named 'listen'.
In following function
_connection = _currentConnectionStream.listen((event) {});
I want to access the following parameters on another page using any state management
final flutterReactiveBle = FlutterReactiveBle();
List<DiscoveredDevice> _foundBleUARTDevices = [];
late StreamSubscription<DiscoveredDevice> _scanStream;
late Stream<ConnectionStateUpdate> _currentConnectionStream;
late StreamSubscription<ConnectionStateUpdate> _connection;
late QualifiedCharacteristic _txCharacteristic;
//late QualifiedCharacteristic _rxCharacteristic;
late Stream<List<int>> _receivedDataStream;
These are other functions I am using
void onNewReceivedData(List<int> data) {
_numberOfMessagesReceived += 1;
_receivedData
.add("$_numberOfMessagesReceived: ${String.fromCharCodes(data)}");
if (_receivedData.length > 10) {
_receivedData.removeAt(0);
}
}
void _disconnect() async {
await _connection.cancel();
_connected = false;
}
void _stopScan() async {
await _scanStream.cancel();
_scanning = false;
}
void _startScan() async {
_foundBleUARTDevices = [];
_scanning = true;
_scanStream = flutterReactiveBle
.scanForDevices(withServices: [_uartUuid]).listen((device) {
if (_foundBleUARTDevices.every((element) => element.id != device.id)) {
_foundBleUARTDevices.add(device);
}
}, onError: (Object error) {
_logTexts = "${_logTexts}ERROR while scanning:$error \n";
}, onDone: () async {
await _scanStream.cancel();
_scanning = false;
});
}
void onConnectDevice(index) {
_currentConnectionStream = flutterReactiveBle.connectToAdvertisingDevice(
id: _foundBleUARTDevices[index].id,
prescanDuration: const Duration(seconds: 1),
withServices: [_uartUuid, _uartRx, _uartTx],
);
_logTexts = "";
_connection = _currentConnectionStream.listen((event) {
var id = event.deviceId.toString();
switch (event.connectionState) {
case DeviceConnectionState.connecting:
{
_logTexts = "${_logTexts}Connecting to $id\n";
break;
}
case DeviceConnectionState.connected:
{
_connected = true;
_logTexts = "${_logTexts}Connected to $id\n";
_numberOfMessagesReceived = 0;
_receivedData = [];
_txCharacteristic = QualifiedCharacteristic(
serviceId: _uartUuid,
characteristicId: _uartTx,
deviceId: event.deviceId);
_receivedDataStream =
flutterReactiveBle.subscribeToCharacteristic(_txCharacteristic);
_receivedDataStream.listen((data) {
onNewReceivedData(data);
}, onError: (dynamic error) {
_logTexts = "${_logTexts}Error:$error$id\n";
});
break;
}
case DeviceConnectionState.disconnecting:
{
_connected = false;
_logTexts = "${_logTexts}Disconnecting from $id\n";
break;
}
case DeviceConnectionState.disconnected:
{
_logTexts = "${_logTexts}Disconnected from $id\n";
break;
}
}
});
}
Another question I have, is how I can use or keep connected using on void onConnectDevice(index) function, because as per the provider you don't need to pass the parameters.
I'm in a Flutter project using Getx. Every time I enter the screen that lists the records I get an error message as you can see below;
I don't know where I'm going wrong, but I'll leave the main parts of the code. I need to find where I'm going wrong.
Class Repository
Future<List<Post>> getAlbum({
bool isFavoritedPage = false,
bool isNewEdition = false,
}) async {
dio.options.headers['Cookie'] = 'ASP.NET_SessionId=${user.sessionID}';
final response = await dio.get(
isFavoritedPage ? AppConstants.apiFavoritedsPost : AppConstants.apiPosts,
queryParameters: {
'sessionId': user.sessionID,
'CodUserProfile': '${user.codUser!}',
'CodUserLogged': '${user.codUser!}',
'Page': '${page}',
'pagesize': '10',
'myPostOnly': isFavoritedPage ? 'true' : 'false',
},
);
final body = response.data['ListPosts'] as List;
return body.map((post) => Post.fromJson(post)).toList();
}
Class Controller
var lstPost = List<Post>.empty(growable: true).obs;
var page = 1;
var isDataProcessing = false.obs;
// For Pagination
ScrollController scrollController = ScrollController();
var isMoreDataAvailable = true.obs;
#override
void onInit() async {
super.onInit();
// Fetch Data
getPost(page);
//For Pagination
paginateTask();
}
void getPost(var page) {
try {
isMoreDataAvailable(false);
isDataProcessing(true);
getAlbum(page).then((resp) {
isDataProcessing(false);
lstPost.addAll(resp);
}, onError: (err) {
isDataProcessing(false);
showSnackBar("Error", err.toString(), Colors.red);
});
} catch (exception) {
isDataProcessing(false);
showSnackBar("Exception", exception.toString(), Colors.red);
}
}
showSnackBar(String title, String message, Color backgroundColor) {
Get.snackbar(title, message,
snackPosition: SnackPosition.BOTTOM,
backgroundColor: backgroundColor,
colorText: Colors.white);
}
void paginateTask() {
scrollController.addListener(() {
if (scrollController.position.pixels ==
scrollController.position.maxScrollExtent) {
print("reached end");
page++;
getMoreTask(page);
}
});
}
void getMoreTask(var page) {
try {
getAlbum(page).then((resp) {
if (resp.length > 0) {
isMoreDataAvailable(true);
} else {
isMoreDataAvailable(false);
showSnackBar("Message", "Não existem registro", Colors.lightBlueAccent);
}
lstPost.addAll(resp);
}, onError: (err) {
isMoreDataAvailable(false);
showSnackBar("Error", err.toString(), Colors.red);
});
} catch (exception) {
isMoreDataAvailable(false);
showSnackBar("Exception", exception.toString(), Colors.red);
}
}
#override
void onClose() {
searchDrawerEC.dispose();
super.onClose();
}
Future<List<Post>> getAlbum(pagina,[bool isFavoritedPage = false]) async {
final response =
await repository.getAlbum(isFavoritedPage: isFavoritedPage);
return response;
}
Class Page
Expanded(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
if (index == controller.lstPost.length - 1 &&
controller.isMoreDataAvailable.value == true) {
return Center(child: CircularProgressIndicator());
}
return PostWidget(post: controller.lstPost[index]);
}
),
),
I'm basing myself on this github project.
https://github.com/RipplesCode/FlutterGetXTodoAppWithLaravel/tree/master/lib/app/modules/home
I don't use getx, but I see something odd in your Listview.builder. It feels as if you're abusing it a little, to also show the "no data" case, and there's also no count. I think it should have a count, so something like this:
if (lstPost.isEmpty) {
return Center(child: CircularProgressIndicator());
} else {
return ListView.builder(
itemCount: lstPost.length,
itemBuilder: (BuildContext context, int index) {
return PostWidget(...);
}
);
}
I am trying to use this plugin https://pub.dev/packages/connectivity/example Issue is its not showing or print internet is connected or not.
This is my code
class _HomePageState extends State<HomePage> {
String _connectionStatus = 'Unknown';
final Connectivity _connectivity = Connectivity();
StreamSubscription<ConnectivityResult> _connectivitySubscription;
#override
void initState() {
super.initState();
initConnectivity();
_connectivitySubscription =
_connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
if (mounted) {
if (userManager.getCurrentDriver() != null &&
userManager.getCurrentDriver().isNotEmpty) {
FirebaseFirestore.instance
.collection(FIREBASE_PATH_TRIP)
.doc(userManager.getCurrentDriver())
.get()
.then((event) {
if (event != null) {
var trip =
DriverModel.fromMap(Map<String, dynamic>.from(event.data()));
Provider.of<TripState>(context, listen: false).driver = trip;
Provider.of<BottomSheetSelector>(context, listen: false)
.changeSheet(SheetType.Profile);
} else {
userManager.saveCurrentDriver('');
}
});
}
if (Theme.of(context).platform == TargetPlatform.android) {
checkForAndroidUpdate(context);
}
}
});
}
#override
void dispose() {
_connectivitySubscription.cancel();
super.dispose();
}
Future<void> initConnectivity() async {
ConnectivityResult result;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
result = await _connectivity.checkConnectivity();
} on PlatformException catch (e) {
print(e.toString());
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) {
return Future.value(null);
}
return _updateConnectionStatus(result);
}
#override
Widget build(BuildContext context) {
final _drawerKey = GlobalKey<ScaffoldState>();
ScreenUtil.init(context);
return SafeArea(
child: WillPopScope(
child: Scaffold(
key: _drawerKey,
backgroundColor: Colors.black,
resizeToAvoidBottomInset: false,
drawer: ViteDrawer(),
body: null,
),
));
}
Future<void> _updateConnectionStatus(ConnectivityResult result) async {
switch (result) {
case ConnectivityResult.wifi:
case ConnectivityResult.mobile:
case ConnectivityResult.none:
setState(() => _connectionStatus = result.toString());
break;
default:
setState(() => _connectionStatus = 'Failed to get connectivity.');
break;
}
}
}
What i need to do is simple print if internet is connected or not. I want to show alert but print is ok so ill manage it. But dont know why its not printing anything
You can try with this
Future<bool> check() async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
print("Connected}");
return true;
} else if (connectivityResult == ConnectivityResult.wifi) {
print("Connected}");
return true;
}
print("not Connected}");
// return You can add your dialog for notify user to your connectivity is off
}
you can use below code to check the connectivity
Future<bool> checkInternetConnectivity() async {
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
return true;
} else {
return false;
}
} on SocketException catch (_) {
return false;
}
}
simple
Future<bool> isConnected() async {
var result = await Connectivity().checkConnectivity();
return result != ConnectivityResult.none;
}
What I'm trying to do
After sign in, showing HomeScreen which has a listview. This listview is showing data coming from an API. So, it takes a little bit time to load. I want to render my HomeScreen after loading is completed an my listview is full of data.
What I've already done
I have an api helper class that does api works. It has a static method which is getting data for my listview and returning a list. This is my getFixtureData method.
static Future<List<Fixtures>> getFixtureData() async {
Map<String, String> queryParameters = {
'league': '78',
'next': '20',
};
http.Response response = await http.get(
getUrl('fixtures', queryParameters),
headers: requestHeaders,
);
print(response.body);
if (response.statusCode == 200) {
String data = response.body;
List<dynamic> result = jsonDecode(data)['response'];
for (int i = 0; i < result.length; i++) {
Fixtures fixture = Fixtures();
fixture.leagueID = jsonDecode(data)['response'][i]['league']['id'];
fixture.country = jsonDecode(data)['response'][i]['league']['country'];
fixture.leagueName = jsonDecode(data)['response'][i]['league']['name'];
fixture.fixtureID = jsonDecode(data)['response'][i]['fixture']['id'];
//get Odds to match with fixtures by fixtureID
await getOddsData(fixture.fixtureID);
fixture.dateTime =
DateTime.parse(jsonDecode(data)['response'][i]['fixture']['date']);
fixture.homeTeam =
jsonDecode(data)['response'][i]['teams']['home']['name'];
fixture.awayTeam =
jsonDecode(data)['response'][i]['teams']['away']['name'];
fixture.status =
jsonDecode(data)['response'][i]['fixture']['status']['long'];
fixture.homeGoals = jsonDecode(data)['response'][i]['goals']['home'];
fixture.awayGoals = jsonDecode(data)['response'][i]['goals']['away'];
fixture.htScoreHome =
jsonDecode(data)['response'][i]['score']['halftime']['home'];
fixture.htScoreAway =
jsonDecode(data)['response'][i]['score']['halftime']['away'];
fixture.ftScoreHome =
jsonDecode(data)['response'][i]['score']['fulltime']['home'];
fixture.ftScoreAway =
jsonDecode(data)['response'][i]['score']['fulltime']['away'];
if (oddsList.length > 0) {
for (int j = 0; j < oddsList.length; j++) {
if (oddsList[j].fixtureID == fixture.fixtureID) {
fixture.homeOdds = oddsList[j].homeOdds;
fixture.drawOdds = oddsList[j].drawOdds;
fixture.awayOdds = oddsList[j].awayOdds;
fixture.bookmakerName = oddsList[j].bookmakerName;
FootballApi.fixtureList.add(
fixture); // this line must be here. If there is no odds of that match, it should not be in fixtureList
}
}
}
}
} else {
print('statusCode: ' + response.statusCode.toString());
}
return FootballApi.fixtureList;
}
I'm calling this method in my stateful widget(HomeScreen) which have a listview that I feed it with the list getFixtureData method returned. I'm calling it in initState of HomeScreen.
This is the relevant code.
class HomeScreen extends StatefulWidget {
static String id = 'home_screen';
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int gameIndex = 0;
String gameTitle = 'Soccer';
int selectedCategoryIndex = 0;
List<Fixtures> fixtureList = List<Fixtures>();
#override
void initState() {
// TODO: implement initState
super.initState();
getFixture();
}
Future<List<Fixtures>> getFixture() async {
fixtureList = await FootballApi.getFixtureData();
return fixtureList;
}
And this part is the where I pass the data to listview in HomeScreen.
Stack(children: [
AppListView(
matchList: FootballApi.fixtureList,
//callback function brings the matchCounter value from ListView class
onChange: (value) {
setState(() {
matchCounter = value;
});
},
finalBetList: (value) {
setState(() {
betList = value;
});
},
),
The problem is; when user signs in, he is viewing my home screen with an empty listview. After a few seconds listview is loaded. I want to render HomeScreen after my listview loaded fully. What is the best way for that?
use FutureBuilder widget to build widgets after getting data from async functions;
FutureBuilder<List<Fixtures>>(
future: getFixture(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Fixtures> yourResponseDataFromAsync = snapshot.data;
return AppListView(
matchList: yourResponseDataFromAsync,
//callback function brings the matchCounter value from ListView class
onChange: (value) {
setState(() {
matchCounter = value;
});
},
finalBetList: (value) {
setState(() {
betList = value;
});
},
);
}
return CircularProgressIndicator();
},
),