I have some dart code in an interface to a Firebase Realtime Database that I need to handle setting up a stream for a particular path in my database and return all entries or use a pair of optional filter parameters to get only the required entries.
The method was originally just for the all entries requirement and works fine:
class _DatabaseStream<T> {
_DatabaseStream(
{String apiPath,
DatabaseNodeParser<T> parser,
String key = '',
String filter = ''}) {
AppDatabase _database = AppDatabase.db;
FirebaseDatabase _firebaseDatabase = _database.firebaseDatabaseInstance;
DatabaseReference _databaseReference =
_firebaseDatabase.reference().child(apiPath);
var eventStream = _databaseReference.onValue;
stream = eventStream.map((event) => parser.parse(event));
}
Stream<T> stream;
}
However when I edit the code to process the optional filter parameters I get an exception from dart. This is the updated code:
class _DatabaseStream<T> {
_DatabaseStream(
{String apiPath,
DatabaseNodeParser<T> parser,
String key = '',
String filter = ''}) {
AppDatabase _database = AppDatabase.db;
FirebaseDatabase _firebaseDatabase = _database.firebaseDatabaseInstance;
DatabaseReference _databaseReference =
_firebaseDatabase.reference().child(apiPath);
var eventStream;
if (filter == '') {
eventStream = _databaseReference.onValue;
stream = eventStream.map((event) => parser.parse(event));
} else {
// we have a filter
Query query = _databaseReference.orderByChild(key).equalTo(filter);
eventStream = query.onValue;
stream = eventStream.map((event) => parser.parse(event));
}
}
Stream<T> stream;
}
The exception reported is:
I/flutter (32750): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (32750): The following assertion was thrown building EggsPage(dirty, state: _EggsPageState#93899):
I/flutter (32750): type '_MapStream<Event, dynamic>' is not a subtype of type 'Stream<List<Egg>>'
I/flutter (32750):
I/flutter (32750): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter (32750): more information in this error message to help you determine and fix the underlying cause.
I/flutter (32750): In either case, please report this assertion by filing a bug on GitHub:
I/flutter (32750): https://github.com/flutter/flutter/issues/new?template=BUG.md
Is this really a bug that I need to report, or is there some error in my updates to the method?
Related
I am trying to create a Dart function that essentially wraps other functions with some boilerplate error handling code, and otherwise returns the value returned by the original function. A key requirement is that it should accept functions with multiple different return types, while avoiding duplicating the common error handling logic across multiple different functions. I found one approach that seems to work by using the dynamic type, except that the compiler is not able to detect type mismatches, so they are only caught at runtime.
Is there a better way to accomplish what I'm aiming for here, and particularly in a way that catches type mismatches at compile time?
Below is a simplified example of my code, where the functions compile fine, but at runtime getAString will raise an error Dart Error: Unhandled exception: type 'List<String>' is not a subtype of type 'String'
/// Signature of API function calls
typedef APIFunctionCall = dynamic Function();
dynamic doWithErrorHandling(APIFunctionCall fn, {retries: 2}) async {
for (int attempts = 0; attempts < retries + 1; attempts++) {
try {
return await fn();
}
on Exception catch (e) {
print(
"This is just an example; actual function does a bunch of more specific error handling.");
}
}
}
Future<String> getAString() async {
// Want a function that can support multiple return types but detect type errors
String doesReturnAString = await doWithErrorHandling(() async => 'hello world'); // This runs fine
String doesntReturnAString = await doWithErrorHandling(() async => <String>['hello', 'world']); // This throws an Error
return doesntReturnAString;
}
You can abstract over the return type using a type parameter:
Future<T> doWithErrorHandling<T>(Future<T> fn(), {int retries = 2}) async {
do {
try {
return await fn();
} catch (e) {
// record error.
}
retries--;
} while (retries >= 0);
return null; // or whatever.
}
With that, you can call with any function. In most cases, the type argument can be inferred from the static type of the argument function, or from the type expected by the surrounding context, but if not, you can write it yourself.
Future<String> getAString() async {
String doesReturnAString = await doWithErrorHandling(() async => 'hello world');
// The next line has a compile-time type error!
String doesntReturnAString = await doWithErrorHandling(() async => <String>['hello', 'world']);
return doesntReturnAString;
}
(As an unrelated hint, you should never catch Exception. Dart errors do not implement Exception, they implement Error. Exception is a meaningless marker interface used by some thrown objects that the user is intended to catch and handle, but in that case, you should be catching the particular exception, like on FormatException, not the plain Exception. So, general rule: Never write on Exception).
everyone,i'm confuse on this problem few days,any one can help me?
when i using flutter redux,i got this problems.
Deserializing '[data, {accounts: [], version: 5.4}, null, null]' to 'LoginResponse' failed due to: Invalid
argument(s): Unknown type on deserialization. Need either specifiedType or discriminator field.
here is LoginResponse Deserialize method:
LoginResponse deserialize(Serializers serializers, Iterable serialized,
{FullType specifiedType: FullType.unspecified}) {
final result = new LoginResponseBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'data':
result.data.replace(serializers.deserialize(value, specifiedType: const FullType(LoginResponseData)) as LoginResponseData);
break;
case 'error':
result.error.replace(serializers.deserialize(value,
specifiedType: const FullType(ErrorMessage)) as ErrorMessage);
break;
}
}
return result.build();
}
abstract class LoginResponseData implements Built<LoginResponseData, LoginResponseDataBuilder> {
factory LoginResponseData([void updates(LoginResponseDataBuilder b)]) = _$LoginResponseData;
LoginResponseData._();
BuiltList<CompanyEntity> get accounts;
String get version;
static Serializer<LoginResponseData> get serializer => _$loginResponseDataSerializer;
}
What really hurts me is that the debugging mode of android studio seems some problem? some variable always shows "Collecting data... it's hard to me to fix this problem cause i can't got some key variable's value.just like:specifiedType.
There is some screenshot when debuging.
i'm great appreciate if any one could give me some tips or answers!!! thanks!!!!
I am expanding on the flutter_gallery example.
I try to create new Gallery Item
new GalleryItem(
title: 'Journal',
subtitle: 'Example app coding',
category: 'Apps',
routeName: JournalDemo.routeName,
buildRoute: (BuildContext context) => new JournalDemo()
),
and I imported import '../journal/journal_all.dart';
Inside I have export 'journal_demo.dart';
JournalDemo class is the same class as ListDemo, I only changed the class name and state name:
class JournalDemo extends StatefulWidget {
JournalDemo({ Key key }) : super(key: key);
static const String routeName = '/journal';
#override
JournalDemoState createState() => new JournalDemoState();
}
class JournalDemoState extends State<JournalDemo> {
.......
This is the exception I get
I/flutter : ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter : The following NoSuchMethodError was thrown building GalleryApp(dirty; state:
I/flutter : GalleryAppState(48280642)):
I/flutter : No top-level getter 'JournalDemo' declared.
I/flutter : NoSuchMethodError: method not found: 'JournalDemo'
I/flutter : Receiver: top-level
I/flutter : Arguments: [...]
I/flutter : When the exception was thrown, this was the stack:
I/flutter : #0 NoSuchMethodError._throwNew (dart:core-patch/errors_patch.dart:184)
I/flutter : #1 kAllGalleryItems (/Users/matej/IdeaProjects/flutter/journal/lib/gallery/item.dart:51)
I/flutter : #2 kAllGalleryItems (/Users/matej/IdeaProjects/flutter/journal/lib/gallery/item.dart:45)
What should I change?
Thank you
This looks like you have either a missing import or a parse error in your code. I would recommend checking with flutter analyze as one of the posters above suggests.
No top-level getter 'JournalDemo' declared means that it cannot find the value JournalDemo in the global scope. Either because it's not imported, or because there is a parse error before this error.
I have a property with custom data binding like this:
class User {
// Custom data binding for the image
#BindUsing({ obj, source ->
def imageFile = source['image']
if (imageFile && imageFile.size > 0) {
Document image = obj.image ?: new Document()
image.setFile(imageFile)
if(!image.save()) {
throw new Exception('Non localizable message')
}
return image
}
})
Document image
...
}
If an exception is thrown (like in my example) it is converted to a ValidationException with always the same generic error codes for typeMismatch:
[com.example.security.User.image.typeMismatch.error,com.example.security.User.image.typeMismatch,user.image.typeMismatch.error,user.image.typeMismatch,typeMismatch.com.example.security.User.image,typeMismatch.image,typeMismatch.com.example.common.Document,typeMismatch]
The defaultMessage of the ValidationException is the message of the exception that was thrown in #BindUsing. So to get localized messages one would have to inject messageSource somehow into #BindUsing and localize the message of the exception that is thrown.
What is the correct way to return an error or an error code from #BindUsing?
I am using core-ajax-dart to fetch some data and put it in core-list-dart. And i keep getting this error. I am able to successfully pass heading which is String but I am not able to pass contacts. It fails with the following error
Exception: Uncaught Error: type 'List' is not a subtype of type
'ObservableList' of 'value'.
main page
<core-ajax-dart auto id="_ajax" url="https://polymer-contacts.firebaseio.com/{{category}}.json" handleAs="json"></core-ajax-dart>
<contacts-page class="page" id="contacts" contacts="{{contacts}}" heading="{{heading}}" flex></contacts-page>
List contacts;
ContactsPage cp = $['contacts'] as ContactsPage;
var ajax = $['_ajax'] as CoreAjax;
ajax.on["core-response"].listen((event) {
var detail = event.detail;
var response = detail['response'];
cp.contacts = response;
});
element definition
<div id="title" flex>{{heading}}</div>
<core-list-dart id="list" data="{{contacts}}">
#published List contacts;
#published String heading;
Stack trace:
Exception: Uncaught Error: type 'List' is not a subtype of type 'ObservableList' of 'value'.
Stack Trace:
#0 CoreList.data= (package:core_elements/core_list_dart.dart:48:124)
#1 main.<anonymous closure> (http://localhost:8080/index.html_bootstrap.dart:114:27)
#2 GeneratedObjectAccessorService.write (package:smoke/static.dart:114:11)
#3 write (package:smoke/smoke.dart:34:40)
#4 _updateNode (package:polymer/src/instance.dart:1412:16)
#5 _convertAndCheck (package:polymer_expressions/polymer_expressions.dart:302:16)
#6 _RootZone.runUnaryGuarded (dart:async/zone.dart:1093)
#7 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341)
#8 _DelayedData.perform (dart:async/stream_impl.dart:595)
#9 _StreamImplEvents.handleNext (dart:async/stream_impl.dart:711)
#10 _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:671)
#11 _asyncRunCallbackLoop (dart:async/schedule_microtask.dart:41)
#12 _asyncRunCallback (dart:async/schedule_microtask.dart:48)
#13 _handleMutation (dart:html:41817)
Almost full source
The data attribute of <core-list-dart> requires an ObservableList instead of List.
What you can do is to change the field to a getter/setter where a passed List is automatically converted to a ObservableList like
class Model extends Object with Observable {
// or class SomeElement extends PolymerElement {
ObservableList _contacts;
#observable ObservableList get contacts => _contacts;
set contacts(List contacts) {
final old = _contacts;
if(contacts is ObservableList) {
_contacts = contacts;
}
_contacts = toObservable(contacts);
notifyPropertyChange(#contacts, old, _contacts);
}
}