Tried to build dirty widget in the wrong build scope - dart

What is the main cause of the above error in Flutter? I am simply using the following code, where both the pickers use same code to fetch data from different json.
if (_equipmentSwitch == equipmentType.Implement)
TractorPicker(mapNotifier: modelNotifier)
else
HarvesterPicker(mapNotifier: modelNotifier),
HarvesterPicker is working fine. But if I switch to tractorPicker, I get the above error along with this error "Duplicate GlobalKey detected in widget tree" . But I have never used a global key

Found the solution:
Since I was using the same ValueNotifier(modelNotifier) for both the pickers, this error occured.
Used dispose method to erase the memory of modelNotifier.
#override
void dispose() {
modelNotifier.dispose();
super.dispose();
}
This solved my problem.

Related

exception types in exception handling

if error handling in dart in the catch block chain applies the supertype first and then the subtypes in subsequent catch blocks, then the catch blocks corresponding to the subtypes will never work. In visual studio code, a warning is displayed in these cases. I believe a static error should be generated.
class A implements Exception {}
class B extends A {}
void main() {
try {
var x = 1;
} on A {
} on B {
// warning
} on Exception {} // warning
}
Is it possible to configure the analyzer so that an error is generated instead of a warning?
Why isn't this done by default?
Is it possible to configure the analyzer, compiler so that block reordering is performed automatically by the dart fix command, for example?
I would like to get an error with the wrong catch order, as well as the possibility of its automatic correction.
Found a way to generate an error if some of the catch blocks will never be executed due to the fact that the base class can be in the first catch block, and the child class will already be in the second.
Requires setting in analysis_options.yaml file.
analyzer:
errors:
dead_code_catch_following_catch: error
But I have not yet found a way to automatically reorder catch blocks. If someone finds it would be great. In general, it would be possible at the level of the dart compiler to consider the possibility of introducing a mechanism in which the catch blocks of child classes would always be performed first before the catch blocks of parent classes.

How to globally catch unhandled Future errors?

Best practice is of course to always attach an error handler to a Future using catchError() (or using await and try/catch). But suppose I forgot, or suppose that this error is serious enough that we want it to crash the entire application (as we could do with synchronous exceptions), or that I want to log the error, or report it to some service like Crashlytics to make me aware of my sins.
Dart's Futures are practically the same as JavaScript's Promises. In NodeJS, we can attach a handler to the global unhandledRejection event to add custom behaviour.
Does Dart offer something similar? I looked through the async and Future documentation, but couldn't find anything relevant.
Take a look at the runZonedGuarded static method. It will executing a given method in its own Zone which makes it possible to attach a method to handle any uncaught errors.
I have made a simple example here which shows what happens if a async error are throw without any handling of the error:
import 'dart:async';
import 'dart:io';
void main() {
runZonedGuarded(program, errorHandler);
}
Future<void> program() async {
final file = File('missing_file.txt');
await file.openRead().forEach(print);
}
void errorHandler(Object error, StackTrace stack) {
print('OH NO AN ERROR: $error');
}
Which returns:
OH NO AN ERROR: FileSystemException: Cannot open file, path = 'missing_file.txt'...

Flutter - Will BLoC stream instances cause memory leak when a widget is closed?

There are some scenarios where screens with their respective BLoCs are frequently created and closed. So I'm somewhat concerned about memory safety of the Streams instances created in this process, because it doesn't seem they are disposed somewhere or whether they are GC-ed. This clearly depends on the specific implementation of DART libraries and flutter. So if you know about their behavior, please let me know.
These are some scenarios I have encountered.
Multi-tab browser-like application.
Navigation through screens. (But it's not that harmful.)
showDialog() senarios when there are BLoCs inside the dialog. This is a far more common senario. There could be a lot of dialog popping up frequently in an app.
I wonder if it is necessary to override dispose() function and explicitly close all streams in BLoCProvider. It seems existing tutorials didn't mention it.
Streams will properly be cleaned as long as they aren't used anymore.
The thing is, to simply removing the variable isn't enough to unsure it's unused. It could still run in background.
You need to call Sink.close() so that it stops the associated StreamController, to ensure resources can later be freed by the GC.
To do that, you have to use StatefulWidget.dispose method:
abstract class MyBloc {
Sink foo;
Sink bar;
}
class MyWiget extends StatefulWidget {
#override
_MyWigetState createState() => _MyWigetState();
}
class _MyWigetState extends State<MyWiget> {
MyBloc bloc;
#override
void dispose() {
bloc.bar.close();
bloc.foo.close();
super.dispose();
}
#override
Widget build(BuildContext context) {
// ...
}
}

Unhandled Exception Handling

In my MonoDroid application, when an unhandled exception occurs the application terminates without any messages. If I can reproduce the error on my local device I can debug it through Visual Studio without any problems.
However, on remote devices I am stuck for a solution.
I have tried the following in the Application class but it does not actually write my log file, unless I am running through the debugger in Visual Studio.
public override void OnCreate()
{
base.OnCreate();
AndroidEnvironment.UnhandledExceptionRaiser += new EventHandler<RaiseThrowableEventArgs>(AndroidEnvironment_UnhandledExceptionRaiser);
}
void AndroidEnvironment_UnhandledExceptionRaiser(object sender, RaiseThrowableEventArgs e)
{
// Write Log File
}
I disagree with #SpiritMachine's answer.
Mono documentation tells us:
Note: You cannot rely on the AppDomain.UnhandledException event as managed exceptions are never unhandled in MonoDroid; they are always intercepted at the Android/managed boundary within a catch(Exception) block.
Instead, I recommend that you do the following:
AndroidEnvironment.UnhandledExceptionRaiser += (sender, args) =>
{
// Do something...
};
Try something like this:
EDIT : This code cannot handle caught errors. Please see #Jim G.'s answer....
Personally, I would localise error handling to where you need it. The reason being, you don't know what your application state will be when this handler is recruited - you may be without resources that you're depending on to do the handling...

Delete a row from VerticalFieldManager

I am trying to establish a PIM listener that will update a MainScreen where all the contacts of the phone are listed.
What I am doing is the following:
I am loading for one time only a form called ContactsForm and I am storing it into the RuntimeStore
I created a PIMListListener to listen for all the changes that will occur in the address book.
When a contact is added, I am adding it to the contactsForm successfully
When a contact is removed, I am facing a big problem deleting it :S!!!
I am getting this exeption: "IllegalArgumentException"; this exception's text is : UiEngine accessed without holding the event lock. I know such errors and I know how to resolve them. So I used the following code:
UiApplication.getUiApplication().invokeLater( new Runnable() { public void run() {
synchronized(UiApplication.getEventLock()) {
uiContacts.vm.delete(uiContacts.vm.getField(j));
}
}});
This should resolve the problem. But I keep getting this error again and again. How to resolve this?
Listeners, like the PIMListListener, do not receive their callbacks in the same Application context as your UiApplication. So, in your code, UiApplication.getUiApplication() doesn't really work the way you'd expect it to.
The best thing to do would be to store a reference to your UiApplication in a place where the callback can reach it (during initialization of the UiApplication, perhaps), and then replace UiApplication.getUiApplication().invokeLater(...) with myUiApp.invokeLater(...), where myUiApp is the reference to your UiApplication which you stored earlier.

Resources