Why even after putting await keyword my app will show 0? - asynchronous

I have called trigger function inside initState function.In trigger function i will be taking data from an API and i parsed the data using storeddata.fromjson function. Then afterwards i will store those values in variables. As far as i know initState function will be called as soon as object of this statefull widget is created. But still in app, it will show exchangeval_bitcoin as 0 for some seconds and then it will get updated(I have initialized exchangeval_bitcoin as 0). does that mean build function will be called even before completion of initState function even after putting await keyword ? And how can i implement loading screen until that value is updated ?
void triggerfun() async {
var decodedmap;
Jsonparse p = Jsonparse(url: uri);
decodedmap = await p.cryptocovert();
Storeddata s = Storeddata.fromjson(decodedmap);
setState(() {
exchangeval_bitcoin = s.getdataforbitcoin();
exchangeval_etherium = s.getdataforetherium();
exchangeval_litecoin = s.getdataforlitecoin();
});
permanent = s;
}
//calling initstate
#override
void initState() {
super.initState();
triggerfun();
}
Thanks in advance.

triggerfun() is an asynchronous function. So in your initState(), it's going to call triggerfun(), but still continue with the rest of your program. When trigger function is finished, it will set state and rebuild the widget.
The await keyword will stop the program until that line is finished, but triggerfun() as a whole is still asynchronous.

Related

accessing data from a static function globally

in the init() of my splash screen page, i am calling the function of the next page in order to load the data from backend, and meanwhile the splash screen will run.
the issue here is it only calls the static function, and that function stores the data locally.
on my other page, i want data globally, so that i can access that data anywhere on that particular page.
highlights of my code is:
splash screen page init code:
void initState() {
super.initState();
FeedScreen.getdata();
}
and my next page, that is FeedScreen page, where i want data globally is:
class FeedScreen extends StatefulWidget {
#override
_FeedScreenState createState() => _FeedScreenState();
static void getdata() async{
CollectionReference collectionReference = FirebaseFirestore.instance
.collection('Feed');
var snapshot = await collectionReference.get();
snapshot.docs.forEach((result){
collectionReference.doc(result.id).collection('myfeed').snapshots().listen((event) {
var latarr,longarr,titlearr,descarr,urlarr;
for(int i=0;i<event.docs.length;i++){
urlarr.add(event.docs[i].data()['imageurl']);
latarr.add(event.docs[i].data()['lat']);
longarr.add(event.docs[i].data()['long']);
titlearr.add(event.docs[i].data()['title']);
descarr.add(event.docs[i].data()['description']);
}
});
});
}
i want to access the value of latarr,longarr,titlearr,descarr,urlarr outside the getdata() function.
Declare your variables latarr,longarr,titlearr,descarr,urlarr outside any class. For instance in your main.dart file before the void main() function. These variables will be considered as global variables and will be accessible anywhere in your app.
The best and clean approach to do this is that you use State Management. With that, you will be able to manage your variables, etc in your code smoothly and you can access those variables anywhere in your program whenever needed. Some popular ones are Provider
, Bloc and GetX.
By using state management you can easily able to Manipulate and access data anywhere in your project.

Async Fetch of Data when a Property Set in Blazor

What is the proper way to fetch data from an async method when a property value changes? Currently, I am doing something like this.
<form>
<select class="form-control" #bind="DayFilter">
<option>None</option>
<option>Monday</option>
<option>Tuesday</option>
<option>Wednesday</option>
<option>Thursday</option>
<option>Friday</option>
<option>Saturday</option>
<option>Sunday</option>
</select>
</form>
#code
{
private string dayFilter = NoDayFilter;
private string DayFilter
{
get => dayFilter;
set
{
dayFilter = value;
_ = GetData();
}
}
private async Task GetData()
{
....
StateHasChanged();
}
}
I am guessing this is not correct according to the Blazor Docs:
Asynchronous work when applying parameters and property values must
occur during the OnParametersSetAsync lifecycle event.
Your doubts about whether you employ async calls properly are not really related to the component life cycle methods...
What you're doing is fine, and it should work. If you use the async key word your method is asynchronous... But you don't have to call the StateHasChanged method. It is called automatically when UI events are involved and when an async mehtod is used: If you use async method, you must await the called method, as for instance:
private async Task GetData()
{
forecasts = await httpClient.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
}
When the runtime executes this method, and notices the await key word, it yields control to the calling code... When the GetFromJsonAsync method returns, execution continues, synchronously to the end of the method... Also the StateHasChanged method is automatically called, and your component is re-render.
The only issue I find with your code, is calling GetData() from the set accessor. This works and all, but I would call the GetData() from an event handler set for the selection of a new item ( change event).
UPDATE
"firing and forgetting" is fine. But you must use the await key word in your GetData method, which is why you need to call StateHasChanged manually, without which there is no way for the component to know when the call has completed. I guess if you place await Task.CompletedTask;
you're going to solve the issue.
I did consider just using the OnChange event, but I like the aesthetics the property binding approach
'change' event you mean, right?
What aesthetics ? The compiler is going to produce a different code for you, anyway, with a 'value' attribute and 'onchange' event.
I hope that helps! If you get stuck, let me know
Calling an async method from a property setter is definitely not OK if you want the UI to update. After thinking about the answers that enet and Henk Holterman gave, I added some debug code
set
{
dayFilter = value;
_ = GetData();
Debug.WriteLine("Day Filter After GetData()");
}
private async Task GetData()
{
Debug.WriteLine("Before http");
var temp = await Http.GetFromJsonAsync<DailyData[]>("https://...");
Debug.WriteLine("After http");
...
}
Which produced the following output:
Before http
Day Filter After GetData()
After http
Based on that, I think the UI finished updating prior to the data being fetched. Since there is no way to await from a setter, my original solution is not workable without calling StateHasChanged- which I want to avoid as I think it would lead to multiple UI updates.
You are using GetData like an async void. Possible but not advisable.
I would avoid this 'fire and forget' pattern and use the onchange event instead:
<select class="form-control" #onchange="OnChange"> ... </select>
async Task OnChange(ChangeEventArgs e)
{
DayFilter = (string) e.Value;
await GetData();
}
async Task GetData()
{
.... // await stuff
}
No need to call StateHasChanged anymore.

Getting firebase data in a stream

I built an application, which gets data from the firebase (realtime db). I did it whith this code, but I want, that I always get the new data. In the internet I found something like in a stream, but I didn't find a manual for that.
Does somebody know how this works?
This is my code:
void readData() {
FirebaseDatabase.instance.reference().child('CHECK').once().then(
(DataSnapshot dataSnapShot) {
print(dataSnapShot.value);
},
);
}
I want to get the data for example every 0.5 seconds
That's not really how Firebase works. But if you want to get the data from the database once right away, and then whenever it is updated, you can use onValue for that.
That'd look something like:
FirebaseDatabase.instance.reference().child('CHECK').onValue.listen((event) {
print(event.snapshot.value);
});
Give it a try: just set up the listener with this code, run the app, and then make a change to the database in the Firebase console. You'll see the data be printed once as soon as you run the app, and then again whenever you make a change.
From what I've read in your comments, you want the function to be executed repeatedly every 0.5 seconds.
A stream is not appropriate for that. However, you can use Timer
#override
void initState() {
super.initState();
timer = Timer.periodic(Duration(seconds: 15), (Timer t) => readData());
}
#override
void dispose() {
timer?.cancel();
super.dispose();
}
Your build() function will be called more than once once Timer.periodic is created.

async is snowballing to callers, can't make constructor async

I have a function loadData that loads some text from a file:
Future<String> loadAsset() async {
return await rootBundle.loadString('assets/data/entities.json');
}
The loadString method is from Flutter SDK, and is asynchronous.
The loadAsset method is then called in another method, that must me marked as async, since loadAsset is async and I need to use await:
Future<List<Entity>> loadEntities() async {
String jsonData = await loadAsset();
return parseData(jsonData);
}
The parseData method is not async, it receives a String, parse it, and return a list of objects:
List<Entity> parseData(String jsonString) {
...
}
But since loadEntities must be marked with async, this requires that it returns a Future, but in practice, it's not a Future because since I use await, it awaits for the loadAsset method to finish, then call the parseData funcion using the result.
This easily turns into a snowball of async call, because every method that uses loadEntities must be marked as async too.
Also, I can't use loadEntities in a class constructor, because the constructor should be marked as async, which is not allowed in Dart.
Am I using the async/await pattern in Dart wrong? How could I use the loadEntities method in a class constructor?
No, async is contagious and there is no way to go back from async to sync execution.
async/await is only syntactic sugar for methodThatReturnsFuture().then(...)
Marking a method with async is only to allow you to use await inside its body. Without async you would still need to return a Future for calling code to only execute after the result of loadAsset() becomes available.
You can use the Future returned from the async call directly. This would look something like this:
class HasAsync {
HasAsync() {
asyncFunction().then((val) {
print(val);
});
}
Future<int> asyncFunction() async {
int val = await otherFunction();
return val;
}
}
You just can't use await within the non-async function.
As you've tagged this with 'flutter', I'm going to guess this is within a flutter app. If that's the case look at the docs for FutureBuilder - it might help with what you're trying to do.
I know I may be too late for you to make any use of this answer but I am writing it anyways hoping someone will find it useful. So here is my two cents.
I had the same thought process as you did when I first tried to figure out what is asynchronous programming and how it can be used.
Since the question is regarding Flutter, I will use dart to explain this.
First, let's dive in to the the basic actually the purpose of using async await in asynchronous programming.
According to the flutter documentation, the purpose of async and await keywords is to declaratively mark a function as asynchronous and use it's results.
To define an async function, add async before the function body
The await keyword works only in async functions.
Therefore, whenever you try to get an output from a function marked as asynchronous it will have no option but to return a Future. Look at the following example for more clarification.
Firstly, you have a function which will do some calculations
Secondly, you have a simple function which gets data from an API by doing a simple http get request.
finally another function which will process some data and print some values.
void processInfo(){
calculateStuff();
Future<Map> decodedData = getDataFromInternet();
getDataProcessed(decodedData);
}
so in synchronous programming this would mean that all three functions will execute one after another. But let's say the second function getDataFromInternet() is called asynchronously. A simple implementation would be like below.
Future<Map> getDataFromInternet() async {
http.Response response = await http.get(this._apiPath);
Map decodedData;
if (response.statusCode != 200)
print("invalid response. cannot proceed!");
else {
decodedData = jsonDecode(response.body);
}
return decodedData;
}
So the above function is required to return a future. The question is why?
It's simple. In this case, it's because since we want to return something and by the time the return statement is executed and the data from the 'get request' may or may not be available at that moment.
Thus, the function returns a Future type result which and either be in complete state or incomplete state.
So how can we process this result? As a matter of fact this can be done in 3 ways.
1. Method One - Handle it as a promise
So once the getDataFromInternet() function returns a Future result in this example, you need the process that future result like how you'd handle a promise in javascript. Refer the code sample below.
void getDataProcessed(Future<Map> data) {
print('getting data from future map');
data.then((d) {
print(d);
});
}
2. Method Two - mark the parent function asynchronous (contagious way)
void processInfo() async{
calculateStuff();
//now you can simply await that result and process the result rather
//than handling a Future<Map> result in this case.
//Note: it is not required to use future variable because we are awaiting
//for result
Map decodedData = await getDataFromInternet();
getDataProcessed(decodedData);
}
so in this case the getDataProcessed() function will look something like this.
void getDataProcessed(Map data) {
//this will simply print the data object which is complete result which is by
//no way is a promise object
print(data);
}
3. Method Three - Use the results from the asynchronous method in a synchronous function (non-contagious way)
In this case the processInfo() function will change slightly, i.e. the getDataProcessed() will no longer be invoked in this method and will look something like this.
void processInfo(){
calculateStuff();
getDataFromInternet();
}
Instead of invoking getDataProcessed() in processInfo() function, we can use the result from getDataFromInternet() function to invoke the getDataProcessed() function.this mean we won't have to mark processInfo() as async and we can process getDataProcessed() method after we finish executing getDataFromInternet() method. The following code sample demonstrates how to do it.
void getDataFromInternet() async {
http.Response response = await http.get(this._apiPath);
Map decodedData;
if (response.statusCode != 200)
print("invalid response. cannot proceed!");
else {
decodedData = jsonDecode(response.body);
}
//in this case, since we are awaiting for get results response and the
//function is not expected to return anything the data type passed into
//getDataProcessed() function now will be of type Map rather than being type
//Future<Map> . Thus allowing it to be a synchronous function and without
//having to handle the future objects.
getDataProcessed(decodedData);
}
void getDataProcessed(Map data) {
//this will simply print the data object which is complete result which is by
//no way is a promise object
print(data);
}
So revising back this long answer,
async/await is just the declarative way to mark asynchronous functions
when an asynchronous function is called it can be handled in 3 ways.
get the return Future and handle it like a promise with the use of 'then()' function so no need to mark the parent
function async
mark the parent function async and handle the returned object with await to force the function to wait for the result.
call the desired function with the output of the async function at the end of the async function. This will allow the main
function to continue non-dependent functions while waiting for the
results of the async function and one the async function get the
results it can go in to the other function at the end and execute it
with the data received.
then and await are different. await will stop the program there until the Future task is finished. However then will not block the program. The block within then will be executed when the Future task is finished afterwards.
If you want your program to wait for the Future task, then use await. If you want your program to continue running and the Future task do it things "in the background", then use then.
As to your problem, I suggest redesign it. Do the loading assets and other async things that are needed for the constructor elsewhere. After these tasks are completed, then call the constructor.

rxJava Observer.onNext not called second time

I am using rxJava to fetch data from the database and show it in a recyclerview. The relevant code is shown below
function updateUI(){
ContactsLab contactsLab = ContactsLab.get(getActivity());
Subscription sub = contactsLab.getContactList().subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.toList()
.subscribe(onContactsReceived());
mCompositeSubscription.add(sub);
}
ContactsLab is a singleton that returns an Observable of Contact objects.
onContactsReceived function is shown below
private Observer<List<Contact>> onContactsReceived(){
return new Observer<List<Contact>>() {
#Override
public void onCompleted() {}
#Override
public void onError(Throwable e) {}
#Override
public void onNext(List<Contact> contacts) {
if(mContactsAdapter == null) {
mContactsAdapter = new ContactsAdapter(contacts);
mRecyclerView.setAdapter(mContactsAdapter);
} else{
mContactsAdapter.setContactList(contacts);
mContactsAdapter.notifyDataSetChanged();
}
}
};
}
The updateUI function is called in my fragment onResume but the view is updated only the first time. If I come back to this fragment from any other fragment (having added more items to db), onResume is called, updateUI runs and onContactsReceived also runs but returns immediately without calling onNext or onComplete.
I think this has something to do with the way rxJava handles observables but no idea how to fix it (read about defer but couldn't understand much). Can somebody please help?
Edit:
The getContactList function look like this :
public rx.Observable<Contact> getContactList() {
List<Contact> contacts = new ArrayList<>();
ContactCursorWrapper cursorWrapper = queryContacts(null, null);
try{
cursorWrapper.moveToFirst();
while (!cursorWrapper.isAfterLast()){
contacts.add(cursorWrapper.getContact());
cursorWrapper.moveToNext();
}
} finally {
cursorWrapper.close();
}
return rx.Observable.from(contacts);
}
Basically it queries the database and maps the returned Cursor into my Contact class(which is a POJO). I added the rx.Observable.from to get an observable that was later collated using toList and updated into the adapter.
I used this approach avoid having to call notifyDataSetChanged after getting each item (and call it only once after getting all that).
What's the right approach to minimize the number of notifyDataSetChanged calls and also, refresh each time onResume is called?
Your observable contactsLab.getContactList().toList() has terminated.toList() collects all emissions from a source observable to a list and emits the entire list once the source Observable terminates (see the documentation). You aren't going to observe any more emissions from it.

Resources