In the test shown (selected for demonstration of the issue), main() instantiates Class ReadWrite() and then calls method readwrite(). Method readwrite() calls getmap() to create img.Image maptrack and then saves it via saveimage() method successfully. Next, Method readwrite() calls THE SAME saveimage() METHOD and fails on CastError (Null check operator used on a null value)
How can an object, start as NULL, convert to NON-NULL in a method and then suddenly appear as NULL in a subsequent method? Its as if the method created its own version, and did not change the class object. If the object is global, I get the same result.
// maptrack is NULL in calling program but is NOT NULL
// in called program
import 'package:image/image.dart' as img;
import 'dart:io'; //for file read/write
import 'package:path_provider/path_provider.dart' as path_provider;
import 'package:path/path.dart' as path;
import 'dart:typed_data'; // for Uint8List types
import 'timestamp.dart'; // prints elapsed seconds + message - code not shown here
main() {
ReadWrite r = new ReadWrite();
Time t = new Time();
String mapid = '041a10.png';
Pixel p = Pixel(3380, 2211);
t.timestamp('#0 hello world from main()');
r.readwrite(t, p, mapid).then((_) {
print("Hello There - Finished Normally");
});
}
class ReadWrite {
img.Image? maptrack;
Future<void> readwrite(t, p, mapid) async {
await getmap(t, mapid);
maptrack != null
? print("#6 maptrack NOT NULL")
: print('#6 maptrack IS NULL'); //NULL
await saveimage(t, 'maptrack.png', maptrack!); // CRASH!!
//_CastError (Null check operator used on a null value)
}
Future<bool> getmap(Time t, String mapid) async {
t.timestamp("#3 start getmap() ");
Directory appDir = await path_provider.getApplicationDocumentsDirectory();
String thepath = path.join(appDir.path, mapid); // 031e01.jpg
img.Image? maptrack = await img.decodePngFile(thepath);
t.timestamp("#4 getmap done. loaded maptrack ");
maptrack != null
? print("#5 maptrack NOT NULL") //NOT NULL
: print('#5 maptrack IS NULL');
await saveimage(t, 'maptrack.png', maptrack!);
return (true); // not used - enables an await call in readwrite()
}
/* save marked map as 031e01.png*/
Future<bool> saveimage(Time t, String mapid, img.Image map) async {
Directory appDir = await path_provider.getApplicationDocumentsDirectory();
String pngPath = path.join(appDir.path, mapid); // 031e01.png
Uint8List markedmap = img.encodePng(map); //convert image to list
await File(pngPath).writeAsBytes(markedmap);
t.timestamp('#8a $mapid SAVED');
return (true); // not used - enables an await call in readwrite()
}
}
class Pixel {
int x;
int y;
Pixel(this.x, this.y); //constructor
/* https://coflutter.com/dart-how-to-print-an-object/ */
@override
String toString() {
return 'Pixel: {x: ${x}, y: ${y} }';
}
}`
```
The code outputs the following before it crashes.
flutter: #0 hello world from main() = 0 seconds
flutter: #3 start getmap() = 0 seconds
flutter: #4 getmap done. loaded maptrack = 8 seconds
flutter: #5 maptrack NOT NULL
flutter: #8a maptrack.png SAVED = 24 seconds
flutter: #6 maptrack IS NULL
```
```
Within your getMap
method you are declaring a new local variable maptrack
instead of assigning to the class/instance variable maptrack
.
Future<bool> getmap(Time t, String mapid) async {
t.timestamp("#3 start getmap() ");
Directory appDir = await path_provider.getApplicationDocumentsDirectory();
String thepath = path.join(appDir.path, mapid); // 031e01.jpg
img.Image? maptrack = await img.decodePngFile(thepath); // declaring a new variable here
t.timestamp("#4 getmap done. loaded maptrack ");
maptrack != null
? print("#5 maptrack NOT NULL") //NOT NULL
: print('#5 maptrack IS NULL');
await saveimage(t, 'maptrack.png', maptrack!);
return (true); // not used - enables an await call in readwrite()
}
Remove the type img.Image?
before maptrack
to refer instead to the instance variable.
Future<bool> getmap(Time t, String mapid) async {
t.timestamp("#3 start getmap() ");
Directory appDir = await path_provider.getApplicationDocumentsDirectory();
String thepath = path.join(appDir.path, mapid); // 031e01.jpg
maptrack = await img.decodePngFile(thepath); // removed img.Image?
t.timestamp("#4 getmap done. loaded maptrack ");
maptrack != null
? print("#5 maptrack NOT NULL") //NOT NULL
: print('#5 maptrack IS NULL');
await saveimage(t, 'maptrack.png', maptrack!);
return (true); // not used - enables an await call in readwrite()
}