My async metho didn't go after "for" iteration - flutter

My code like this:
Future<List<ListClass>> getIndexList() async {
return Future.delayed(delayTime).then((_) async {
//initialize
List<ListClass> resultListItems = new List<ListClass>();
await listCollection.get().then((value) async {
var v = value.data;
for (var data in v) {
String userId = data['userId'];
String authorName=await UserTable().getUserNameById(userId);
print("createUserName=" + authorName);
resultListItems.add(
ListClass(header, content, userId, wordCount, authorName));
}
print("resultListItems.length="+resultListItems.length.toString());
return resultListItems;
});
return resultListItems;
});
}
When I debug,it shows that this method return null,and after the for,the print("resultListItems"); doesn't run too. How can I fix this?Thanks!!

I have found the problem,the for clause doesn't run completely.One of my data in database is null,so it runs with bug.Sorry for my fault

Related

How to assign values from an API call to a variable in flutter

I have the following method which is use dto verify a ticket/token
var ticketArray = ticket.split('|');
//First check to verify token using simple versification algo
if (widget.eventID.toString() != (ticketArray[0])) {
setState(() {
ticketMainMsg = 'This QR code is NOT VALID';
ticketsubtitle = ticketArray.length != 2
? 'The QR code is fake'
: 'QR code could belong to another event';
ticketStatus = false;
return;
});
}
//Make API call
ticketModel = HttpVerifyTicketPost(
eventId: widget.eventID,
ticket: ticket,
scannerId: widget.scannerId,
).verifyTicket();
}
From above, you can see I do a very simple check on the qr code/token if this simple step fails, I don't bother making an API call and I set the state based on these values.
However if the check passes, then I proceed to make an API call to the server to fully verify the token/code.
My issue is I am struggling to now assign the values from the API call to the ticketStatus, ticketMainMsgand ticketsubtitle parameters. Can anyone helo shed some light. I am quite new to flutter but I am aware that the TicketModel will be a type of Future. My background is PHP so forgive me!
EDIT: The httpVerifyTicket Class
class HttpVerifyTicketPost {
String ticket;
int someId;
int anotherId;
HttpVerifyTicketPost(
{required this.ticket, required this.someId, required this.anotherId});
String verifyURL =
'https://api.com/api/vendors/scanner/native/verify/ticket';
Future<TicketModel> verifyTicket() async {
var storage = await SharedPreferences.getInstance();
var code= storage.getString('code');
var client = http.Client();
var ticketModel = null;
var body = {
'ticket': ticket,
'scanner': scannerCode,
'someId': someId,
'anotherId': anotherId
};
try {
var url = Uri.parse(verifyURL);
var res = await client.post(url, body: jsonEncode(body));
if (res.statusCode == 200) {
var jsonString = res.body;
var jsonMap = json.decode(jsonString);
ticketModel = TicketModel.fromJson(jsonMap);
}
return ticketModel;
} catch (Exception) {
return ticketModel;
}
}
}
Try this please
HttpVerifyTicketPost(
eventId: widget.eventID,
ticket: ticket,
scannerId: widget.scannerId,
).verifyTicket().then((value){setState(() {
ticketModel=value
});
});
I don't quite understand what you want to achieve, but maybe you need to add an asynchronous method like
ticketModel = await HttpVerifyTicketPost( //add await eventId: widget.eventID, ticket: ticket, scannerId: widget.scannerId, ).verifyTicket();
and you must add async like Future Foo() async {your code...}

clean future builder for new data

i'm using a builder for a search page in my application, basically i get data from a json file,
my issue is that if i try to search for a new word, the old result will still be shown and the new one are going to be shown under them.
here is how i get data from my website:
Future<List<Note>> fetchNotes() async {
var url = 'https://sample.com/';
var response = await http.get(url + _controller.text.trim());
var notes = List<Note>();
if (response.statusCode == 200) {
var notesJson = json.decode(response.body);
for (var noteJson in notesJson) {
notes.add(Note.fromJson(noteJson));
}
} else {
ercode = 1;
}
return notes;
}
fetchNotes().then((value) {
setState(() {
_notes.addAll(value);
});
});
if (_notes[0] == null) {
ercode = 2;
}
}
and i display data like this:
here is full example for showing that data
I think you should use "clear()".
fetchNotes().then((value) {
setState(() {
_notes.clear();
_notes.addAll(value);
});
});

async await not working as expected, it must return me future result

My code with Future & Then works perfectly. see below:
/*main is the entry point of code*/
void main() {
var futureObject = getPostFromServer();
printPost(futureObject);
}
getPostFromServer(){
var duration = Duration(seconds : 5);
var computation = (){
return "You will get it in future" ;
};
var futureObject = Future.delayed(duration, computation);
return futureObject;
}
printPost(var futureObject){
futureObject.then(
(actualString){
print(actualString);
}
);
}
/*
OUTPUT
You will get it in future
*/
However, when I am trying the same with async & wait I am not able to get the same output.
Instance of '_Future<dynamic>'
Why not I am able to get future value?
/*main is the entry point of code*/
void main() {
var futureObject = getPostFromServer();
printPost(futureObject);
}
getPostFromServer() async {
var duration = Duration(seconds : 5);
var computation = (){
return "You will get it in future" ;
};
var futureObject = await Future.delayed(duration, computation);
return futureObject;
}
printPost(var futureObject){
print(futureObject);
}
/*
OUTPUT
start
Instance of '_Future<dynamic>'
end */
Thanks
When you mark a method with async, dart will return you a Future implicitly. So if you want to use the result of this method you have to again await the result.
Below I have awaited the future and then printed it in an async method. So my rule of thumb is always await and do your functionality as you would in a sequential program. If you return a value from an async function you are telling dart that method will take time execute so wrap it in a future and return the results.
In your example getPostFromServer() acts as a mini server in you client side code and printPost() acts as sub client who should wait and then read the results. async and await are equally important in both server and client side. Only diference would be how we use it. :)
void main() {
var futureObject = getPostFromServer();
printPost(futureObject);
}
getPostFromServer() async {
var duration = Duration(seconds : 5);
var computation = (){
return "You will get it in future" ;
};
var futureObject = await Future.delayed(duration, computation);
return futureObject;
}
printPost(var futureObject) async {
print(await futureObject);
}
Same code in dartpad:
https://dartpad.dartlang.org/59610dc768e232ac5a8e724f7fe0eee6

How to map each item from observable to another one that comes from async function?

I want to
1.map item from observable to another one if it has already saved in database.
2.otherwise, use it as it is.
and keep their order in result.
Saved item has some property like tag, and item from observable is 'raw', it doesn't have any property.
I wrote code like this and run testMethod.
class Item {
final String key;
String tag;
Item(this.key);
#override
String toString() {
return ('key:$key,tag:$tag');
}
}
class Sample {
///this will generate observable with 'raw' items.
static Observable<Item> getItems() {
return Observable.range(1, 5).map((index) => Item(index.toString()));
}
///this will find saved item from repository if it exists.
static Future<Item> findItemByKey(String key) async {
//simulate database search
await Future.delayed(Duration(seconds: 1));
if (key == '1' || key == '4') {
final item = Item(key)..tag = 'saved';
return item;
} else
return null;
}
static void testMethod() {
getItems().map((item) async {
final savedItem = await findItemByKey(item.key);
if (savedItem == null) {
print('not saved:$item');
return item;
} else {
print('saved:$savedItem');
return savedItem;
}
}).listen((item) {});
}
The result is not expected one.
expected:
saved:key:1,tag:saved
not saved:key:2,tag:null
not saved:key:3,tag:null
saved:key:4,tag:saved
not saved:key:5,tag:null
actual:
not saved:key:2,tag:null
not saved:key:3,tag:null
not saved:key:5,tag:null
saved:key:1,tag:saved
saved:key:4,tag:saved
How to keep their order in result?
I answer myself to close this question.
According to pskink's comment, use asyncMap or concatMap solve my problem. Thanks!!
below is new implementation of testMethod.
asyncMap version:
getItems().asyncMap((item) {
final savedItem = findItemByKey(item.key);
if (savedItem != null)
return savedItem;
else
return Future.value(item);
}).listen(print);
concatMap version:
getItems().concatMap((item) {
final savedItem = findItemByKey(item.key);
if (savedItem != null)
return Observable.fromFuture(savedItem);
else
return Observable.just(item);
}).listen(print);

what is the proper way of subscribing to a ReactiveCommand in ReactiveUI 8.2

I have following snippet in ViewModel.
public ReactiveCommand<object, System.Reactive.Unit> LoadCustomerDetails;
ReactiveCommand<OrderViewPager<SalesOrderOrderOptionsEnum>, CommandSubmitResultDto<List<SalesOrderDto>>> _loadSalesOrderList;
public ReactiveCommand<OrderViewPager<SalesOrderOrderOptionsEnum>, CommandSubmitResultDto<List<SalesOrderDto>>> LoadSalesOrderList
{
get { return _loadSalesOrderList; }
private set { this.RaiseAndSetIfChanged(ref _loadSalesOrderList, value); }
}
this.LoadSalesOrderList = ReactiveCommand.CreateFromTask<Pager<OrderOptionsEnum>, CommandSubmitResultDto<List<SalesOrderDto>>>(
async filter =>
{
Debug.WriteLine("Load SalesOrderList...");
Debug.WriteLine("Customer Id : " + SelectedCustomerId);
await LoadCustomerDetails.Execute();
var result = await SalesOrderMobApi.GetByCustomerTraderEntityIdPaged(SelectedCustomerId, filter, null, SalesOrderTypeEnum.SalesOrder, SalesOrderPOOptions.NotOriginatingFromPurchaseOrder);
return result;
})
.DisposeWith(ViewModelBindings.Value);
this.LoadSalesOrderList.ThrownExceptions
.Subscribe(ex =>
{
Debug.WriteLine("Load SalesOrderList Failed!");
});
this.LoadSalesOrderList
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(result =>
{
if (result.PagingInfo.CurrentPage > 1)
{
foreach (var item in result.Data)
{
SalesOrdersList.Add(SalesOrderVMM.From(item));
}
}
else
{
SalesOrdersList.Clear();
foreach (var item in result.Data)
{
SalesOrdersList.Add(SalesOrderVMM.From(item));
}
}
});
LoadCustomerDetails = ReactiveCommand.CreateFromTask<object, System.Reactive.Unit>(
async _ =>
{
Debug.WriteLine(SelectedCustomerId);
var customers = await TraderEntityMobApi.GetById(SelectedCustomerId);
var customer = customers.Data;
SelectedCustomer = customer;
return System.Reactive.Unit.Default;
}
).DisposeWith(ViewModelBindings.Value);
It sometimes gives exception as follows.
System.NullReferenceException: Object reference not set to an instance of an object.
06-20 16:05:02.480 I/MonoDroid(15304): at DistributrIII.Mobile.Lib.VM.SalesOrder.CreateSOListVM.<RegisterObservables>b__43_2 (System.Collections.Generic.List`1[T] result) [0x0000e] in C:\Users\gayanbu\Source\Repos\Distributr 3.0 UI\Mobile\DistributrIII.Mobile.Lib\VM\SalesOrder\CreateSOListVM.cs:131 .at System.Reactive.AnonymousSafeObserver`1[T].OnNext (T value) [0x0000a] in <99f8205c51c44bb480747b577b8001ff>:0
06-20 16:05:02.480 I/MonoDroid(15304): at System.Reactive.ScheduledObserver`1[T].Run (System.Object state, System.Action`1[T] recurse) [0x000f5] in <99f8205c51c44bb480747b577b8001ff>:0
06-20 16:05:02.480 I/MonoDroid(15304): at System.Reactive.Concurrency.Scheduler+<>c__DisplayClass49_0`1[TState].<InvokeRec1>b__0 (TState state1) [0x0001e] in <99f8205c51c44bb480747b577b8001ff>:0
06-20 16:05:02.480 I/MonoDroid(15304): at System.Reactive.Concurrency.Scheduler.InvokeRec1[TState] (System.Reactive.Concurrency.IScheduler scheduler,
I guess it tries to execute the code inside reactive command ,LoadSalesOrderList even the result of this is null. How to handle this ? Could someone kindly explain the proper way of subscribing to Reactive Command. I am executing this command in the page load as, this.ViewModel.LoadSalesOrderList.Execute().subscribe(new Pager<OrderOptionsEnum>())
Thanks!
if you want your command when throw exception to be catched in ThrownExceptions execute command like Observable.Return(input).InvokeCommand(Command).DisposeWith(disposable) where input is the input for command and Command is the name of the Command