Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

_CastError (type 'Null' is not a subtype of type 'List<int>' in type cast) when having Network Image inside Listview

Tags:

flutter

dart

i have an error that i just dont find a solution for. I created a little messenger thingy in flutter and have a problem when using a NetworkImage inside one of my chat bubbles.

When i send the image as message, it is displayed without problem in the bubble. Also when i send multiple images, it is no problem and they extend beyond the screen and i can just scroll up and down without any problems.

Though when i reopen the room screen and there are multiple images and they extend over the visible screen i get _CastError (type 'Null' is not a subtype of type 'List' in type cast) from network_image dart file. BUT this only happens after a hot restart. If i just navigate back and then reopen the room screen its also all fine, but as soon as i hot restarted once i always get the error when trying to open a room, which has images extending the visible space.

Iam still kinda new to flutter, so i know my code sucks mostly but this time i just dont even find a "dirty" way to solve it.

Flutter 2.2.0 (beta channel)
Dart 2.13.0 On Android Emulator Pixel 4a API 30

Edit 1: i removed a lot to make it easier to read.

Edit 2: i found it to be somehow connected to using the downloadURL from Firebase Storage. When i replace the url with just some test png url it doesnt seem to be a problem.

import 'package:bubble/bubble.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:app/src/app/provider/firestore_provider.dart';

class MessageRoomCopy extends ConsumerWidget {
  final String roomName;
  final String roomID;
  MessageRoomCopy(this.roomName, this.roomID);

  @override
  Widget build(BuildContext context, ScopedReader watch) {
    final firestoreServ = watch(firestoreServiceProvider);
    return Scaffold(
      backgroundColor: Color(0xFFECE5DD),
      appBar: AppBar(title: Text("$roomName", style: TextStyle(color: Colors.white))),
      body: StreamBuilder(
          stream: firestoreServ.messagesOfRoom("$roomID"),
          builder: (BuildContext context, AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) {
            if (snapshot.hasError) {
              return Center(
                child: Text("Error"),
              );
            } else if (snapshot.connectionState == ConnectionState.waiting) {
              return Center(child: CircularProgressIndicator());
            } else {
              final List<QueryDocumentSnapshot<Map<String, dynamic>>> messagesList = snapshot.data!.docs;

              return ListView.separated(
                reverse: true,
                //shrinkWrap: true,
                itemBuilder: (BuildContext context, int index) {
                  var _messageBubble;
                  double? _elevation = 2.0;
                  BubbleEdges? _margin = BubbleEdges.only(top: 10);
                  BubbleNip? _nip = BubbleNip.rightTop;
                  bool? _showNip = true;
                  Alignment? _alignment = Alignment.topRight;
                  Color? _color = Color.fromRGBO(225, 255, 199, 1.0);
                  Widget? _messageChild;

                  if (messagesList[index].get("messagetype") == "text") {
                    _messageChild = Text(
                      messagesList[index].get("content"),
                      style: Theme.of(context).textTheme.bodyText2,
                    );
                  } else if (messagesList[index].get("messagetype") == "image") {
                    _messageChild = Image.network(
                      messagesList[index].get("content"),
                      errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) {
                        return Text("Error Wdiget");
                      },
                    );
                  }

                  _messageBubble = Bubble(
                    elevation: _elevation,
                    margin: _margin,
                    nip: _nip,
                    showNip: _showNip,
                    alignment: _alignment,
                    color: _color,
                    child: _messageChild,
                  );

                  return Container(
                    child: Column(
                      children: [
                        _messageBubble,
                      ],
                    ),
                  );
                },
                separatorBuilder: (BuildContext context, int index) => Divider(
                  height: 1,
                  color: Colors.transparent,
                ),
                itemCount: messagesList.length,
              );
            }
          }),
    );
  }
}

Also this is where the error rethrow is coming from inside _network_image_io.dart

Future<ui.Codec> _loadAsync(
    NetworkImage key,
    StreamController<ImageChunkEvent> chunkEvents,
    image_provider.DecoderCallback decode,
  ) async {
    try {
      assert(key == this);

      final Uri resolved = Uri.base.resolve(key.url);

      final HttpClientRequest request = await _httpClient.getUrl(resolved);

      headers?.forEach((String name, String value) {
        request.headers.add(name, value);
      });
      final HttpClientResponse response = await request.close();
      if (response.statusCode != HttpStatus.ok) {
        // The network may be only temporarily unavailable, or the file will be
        // added on the server later. Avoid having future calls to resolve
        // fail to check the network again.
        await response.drain<List<int>>();
        throw image_provider.NetworkImageLoadException(statusCode: response.statusCode, uri: resolved);
      }

      final Uint8List bytes = await consolidateHttpClientResponseBytes(
        response,
        onBytesReceived: (int cumulative, int? total) {
          chunkEvents.add(ImageChunkEvent(
            cumulativeBytesLoaded: cumulative,
            expectedTotalBytes: total,
          ));
        },
      );
      if (bytes.lengthInBytes == 0)
        throw Exception('NetworkImage is an empty file: $resolved');

      return decode(bytes);
    } catch (e) {
      // Depending on where the exception was thrown, the image cache may not
      // have had a chance to track the key in the cache at all.
      // Schedule a microtask to give the cache a chance to add the key.
      scheduleMicrotask(() {
        PaintingBinding.instance!.imageCache!.evict(key);
      });
      rethrow; // here this one
    } finally {
      chunkEvents.close();
    }
  }
like image 831
Kilian Avatar asked Jun 09 '21 17:06

Kilian


1 Answers

Ok, i kind of found the problem. I took the Firebase servertimestamp as variable for the filename in the Firebase Storage. That of course only resulted in the filename being

FieldValue(Instance of 'MethodChannelFieldValue')

Though i dont really understand why that was a problem, but now with a normal Datetime toString timestamp it all works perfectly fine. Maybe its some special character escaping in the generated downloadURL from Firebase Storage with this kind of filename.

like image 54
Kilian Avatar answered Oct 12 '22 13:10

Kilian