I would like to test functions, widgets etc. from lazy loaded packages. I'm using Dart’s deferred imports to shrink the main.dart.js file.
For example: import 'package:spitch/app/splashscreen.dart' deferred as splashscreen;
But because the packages etc. are not ready I get in my tests the following error: "the following _ Deferred Not Loaded Error was thrown building ..."
I have not found anything in the dart and flutter docs about how to test deferred loaded data.
Make sure you call .loadLibrary(); in the deferred object before rendering the widget.
The deffered library/page should be called in async, so wrap it inside a future builder.
Good Examples:
FutureBuilder(
future: home.loadLibrary(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) return home.HomePage();
return Material(child: Center(child: Text('Loading...')));
},
)
void get()async{
await home.loadLibrary().then((value){
// Your navigation code
push(home.HomePage(), context);
});
}
Bad Examples:
return FutureBuilder(
future: home.loadLibrary(),
builder: (context, snapShot) {
return home.HomeBasement();
});
return FutureBuilder<void>(
future: signIn.loadLibrary(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.hasData) {
return signIn.SignInPage();
} else {
return const Txt(text: 'Loading...');
}
});
In case you are using any linting, please make sure you are not setting any object types like void, dynamic, widget?. If you specify the type, it will throw the error.
Note: You must open the modified code on Incognito tab or a cache
cleared browser, If previous app data is hosted on the page, this will
return the old Error only. So better go Incognito
Related
I'm having a problem compiling this flutter code. It throws me the following error:
The following assertion was thrown building FutureBuilder(dirty, state: _FutureBuilderState#afa3f):
A build function returned null.
The offending widget is: FutureBuilder
Build functions must never return null.
To return an empty space that causes the building widget to fill available room, return "Container()". To return an empty space that takes as little room as possible, return "Container(width: 0.0, height: 0.0)".
The code is this:
home: Builder(builder: (context) {
return FutureBuilder(
future: DeeplinkConfig().initUniLinks(context),
builder: (_, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Container(width: 0.0, height: 0.0);
}
return snapshot.data as Widget;
},
);
}),
Please, if someone explains the error and tells me how to fix it, I would greatly appreciate it.
This error message is indicating that the FutureBuilder's builder callback is returning null as the widget to be displayed.
The builder callback should return a non-null Widget to display in the FutureBuilder. You can either return a widget with dimensions 0.0 width and height, or return a widget indicating that data is loading, like a CircularProgressIndicator.
I would recommend a FutureBuilder that returns a CircularProgressIndicator while the future is waiting:
return FutureBuilder(
future: DeeplinkConfig().initUniLinks(context),
builder: (_, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
return snapshot.data as Widget;
},
);
The issue is this line:
return snapshot.data as Widget;
Your Future is out of the waiting state but data is still null. You then cast it to a Widget, which bypasses Dart's type checking and allows the code to compile but break at runtime.
You can assign snapshot.data to a local variable and check that it's not null. That will allow Dart's type promotion to kick in and you can just return the local variable after the check passes without any cast:
return FutureBuilder<Widget>(
future: DeeplinkConfig().initUniLinks(context),
builder: (_, snapshot) {
final data = snapshot.data;
snapshot.connectionState
if (snapshot.connectionState == ConnectionState.waiting || data == null) {
return Container(width: 0.0, height: 0.0);
}
return data;
},
);
This assumes that
Your future always returns a non-null result when it completes and
That return value is a widget
app was working fine all pages working fine but a single page is getting slow after adding this code to my listview
leading: FutureBuilder<Uint8List?>(
future: _thumbnailImage(files[index].path),
builder: (_, AsyncSnapshot<Uint8List?> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasData) {
return Image.memory(snapshot.data!);
}
return Text("error");
},
),
FutureBuilder waits for the data. Until the future function _thumbnailImage(files[index].path) doesn't return the data, ListView (leading property) won't be build.
Note that FutureBuilder will impact only where it is used. Other widgets should be loaded normally.
When a screen where the main content comes from an API, what would be the option to have a good UI? Should this really be done with FutureBuilder?
Yes, you can use FutureBuilder and use different states to inform your users.
For example:
return FutureBuilder(
future: _getMark(context),
builder: (ctx, snapshot) {
if (snapshot.hasData) {
return snapshot.data as Widget;
}
if (snapshot.hasError) {
//show error
}
return markUnRead;
},
);
In my application I am using appsflyer for deep linking.
https://pub.dev/packages/appsflyer_sdk
The application works as expected. But if I reload the application via code. It gives me this error.
The following StateError was thrown building FutureBuilder<dynamic>(state: _FutureBuilderState<dynamic>#39b5e):
Bad state: Stream has already been listened to.
The code that is causing this error is;
_loadLandingView(Stream<Map> onData, Stream<Map> onAttribution,
Future<bool> Function(String, Map) trackEvent) {
return StreamBuilder<dynamic>(
stream: onAttribution?.asBroadcastStream(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.hasData) {
return _detectOperation(snapshot.data);
} else {
return LandingView();
}
});
}
Is there a way to resolve this?
I have seen controllers can be used with streams. Can it be used here?
I have a StreamBuilder that is taking data from my bloc component.
However it keeps rejecting my type annotation AsyncSnapshot<List<int>> snapshot and only accepts dynamic as a type AsyncSnapshot<List<dynamic>> snapshot. Yet in the examples i've viewed they do have type annotaions with no complaints.
Here is my stream creation.
Widget buildList(StoriesBloc bloc) {
return StreamBuilder(
stream: bloc.topIds,
builder: (BuildContext context, AsyncSnapshot<List<int>> snapshot) {
if (!snapshot.hasData) {
return Text("Still Waiting for Ids to fetch");
}
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, int index) {
return Text('${snapshot.data[index]}');
},
);
},
);
}
Here is the VSCode error generated.
What could i be doing wrong ?
Turns out my bloc.topIds result type was not of type List<int>.
Observable<List> get topIds => _topIds.stream;
So i simply changed it to fulfill the required type.
Observable<List<int>> get topIds => _topIds.stream;
And that fixed the issue. Hope it helps someone else.