Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I catch exceptions thrown when flutter resolves a NetworkImage?

Tags:

flutter

dart

My use-case here is to show a snackbar if there's an error, but I can't catch the SocketException since I'm not calling load: flutter is.

Update (example stacktrace):

I/flutter (11702): ══╡ EXCEPTION CAUGHT BY SERVICES ╞══════════════════════════════════════════════════════════════════
I/flutter (11702): The following SocketException was thrown resolving a single-frame image stream:
I/flutter (11702): Connection failed (OS Error: Network is unreachable, errno = 101), address = (( snip )), port
I/flutter (11702): = 443
I/flutter (11702): When the exception was thrown, this was the stack:
I/flutter (11702): #0      IOClient.send (package:http/src/io_client.dart:30:23)
I/flutter (11702): <asynchronous suspension>
I/flutter (11702): #1      BaseClient._sendUnstreamed (package:http/src/base_client.dart:171:38)
I/flutter (11702): <asynchronous suspension>
I/flutter (11702): #2      BaseClient.get (package:http/src/base_client.dart:34:5)
I/flutter (11702): #3      NetworkImage._loadAsync (package:flutter/src/services/image_provider.dart:431:54)
I/flutter (11702): <asynchronous suspension>
I/flutter (11702): #4      NetworkImage.load (package:flutter/src/services/image_provider.dart:417:7)
I/flutter (11702): #5      ImageProvider.resolve.<anonymous closure>.<anonymous closure> (package:flutter/src/services/image_provider.dart:253:61)
like image 644
perlatus Avatar asked Aug 11 '17 23:08

perlatus


People also ask

How do you catch exceptions in flutter?

In order to catch all the exceptions in a block of code you wrap the code in try block and use multiple on-catch instructions to handle some specific exceptions, then use catch to handle all other unexpected exceptions, and finally use finally to run the code that should be invoked after the code in try block and in ...

What is exception handling error in Dart and flutter?

It is thrown when a schedule timeout happens while waiting for an async result. The main objective of the exception is to handle the run-time error and prevent the program from terminating abruptly. Every exception in the Dart is a subtype of the pre-defined class Exception.

What is try catch in flutter?

Dart try-catch is used to execute a block of code that could throw an exception, and handle the exception without letting the program terminate. If an exception, thrown by any of the code, is not handled via catch block, then the program could terminate because of the exception.


1 Answers

I'm relatively certain it is not possible using NetworkImage and this is because as I understand exceptions can only be caught if you are awaiting the result of what is throwing an exception.

Fortunately with a little F12 action it seems the code is pretty simple. So my solution was to copy NetworkImage's _loadAsync functionality to my own class with a few small tweeks. (Like rturning a Uint8List instead of a codec)

utils/network_image_loader.dart

import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:typed_data';

class NetworkImageLoader {
    String url;
    Map<String, String> headers;

    NetworkImageLoader(this.url, {this.headers});

    static final http.Client _httpClient = createHttpClient();

    Future<Uint8List> load() async {
        final Uri resolved = Uri.base.resolve(this.url);
        final http.Response response = await _httpClient.get(resolved, headers: headers);
        if (response == null || response.statusCode != 200)
        throw new Exception('HTTP request failed, statusCode: ${response?.statusCode}, $resolved');

        final Uint8List bytes = response.bodyBytes;
        if (bytes.lengthInBytes == 0)
        throw new Exception('NetworkImage is an empty file: $resolved');

        return bytes;
    }
}

A simple way to use this would be (I used it differently since I was loading a loop of images and displaying a default, so I haven't tested this way, but it should work, or be close):

Widget img = new Text("Loading");

...
    //Some function, ex constructor, init state, or a callback after you've done an http call
    loadImage('http://imawesome.com');
...

@override
build(BuildContext context) {
    return img;
}

Future<Uint8List> loadImage(String url) async {
    try {
        var netImg = new NetworkImageLoader(url);
        var res = await netImg.load();
        setState(() {
            img = new Image(image: new MemoryImage(data),
                height: 100.0,
                width: 100.0,
                fit: BoxFit.contain,
            );
        });
    }
    on Exception {
        setState(() {
            img = new Text("Load Failed");
        }
    }
}

So my class is nice if you want to do any of the following:

  • Display something in place of the image until it loads
  • Handle exceptions loading images (or event just ignore them)
  • Listen to "events" about image loading (ex. do something when it's loaded)

Edit:

You may want to look into fade in images as well, which allow specifying a placeholder and may be sufficient for many cases: https://flutter.io/cookbook/images/fading-in-images/

like image 94
csga5000 Avatar answered Oct 30 '22 09:10

csga5000