【问题标题】:Can't convert JSON list to list of photos in flutter无法将 JSON 列表转换为颤振中的照片列表
【发布时间】:2020-12-10 20:26:39
【问题描述】:

我通过从 unsplash 服务创建一个简单的照片库并尝试从 https://api.unsplash.com/photos 获取照片列表来学习 Flutter。

我收到运行时错误:

type 'Future<dynamic>' is not a subtype of type 'FutureOr<List<Photo>>'

虽然如果我打印一个列表而不是返回它,我会在控制台中获得 Photo 实例的列表。 我的代码有什么问题以及如何正确处理?

我的照片模型如下所示:

class Photo {
  final String id;
  final String title;
  final String username;
  final String url;

  Photo({this.id, this.title, this.username, this.url});

  factory Photo.fromJson(Map<String, dynamic> json) {
    return Photo(
        id: json['id'],
        title: json['alt_description'],
        username: json['user']['name'],
        url: json['urls']['raw']);
  }
}

我的api数据源:

import 'package:http/http.dart' as http;
import 'dart:convert';

class UnsplashApi {
  final String _clientId =
      "84y4hgje4ac868c2646c0eddjhfedihdhff612b04c264f3374c97fff98ed253dc9";

  Future<String> _fetch(String url) async {
    try {
      url = buildUrl(url);
      var response = await http.get(url);
      if (response.statusCode == 200) {
        return response.body;
      }
    } catch (e) {
      print(e);
    }
  }

  Future<dynamic> fetchDataByUrl(String url) async {
    var data = await _fetch(url);
    try {
      return json.decode(data);
    } catch (e) {
      print('Bad content, could not decode JSON');
    }
  }

  String buildUrl(url) {
    return url.contains('?')
        ? url + '&client_id=$_clientId'
        : url + '?client_id=$_clientId';
  }
}

我的仓库合约(接口):

import 'package:unsplash/domain/models/photo.dart';

abstract class PhotosRepository {
  Future<List<Photo>> getPhotosList();
}

我的 Unsplash 照片存储库:

import 'package:unsplash/domain/models/photo.dart';
import 'package:unsplash/domain/repositories/photos_repository.dart';
import 'package:unsplash/infrastructure/data_sources/unsplash_api.dart';

class UnsplashPhotosRepository implements PhotosRepository {
  final UnsplashApi _api;
  final String _url = 'https://api.unsplash.com/photos';

  UnsplashPhotosRepository(this._api);

  @override
  Future<List<Photo>> getPhotosList() async {
    var result = _api.fetchDataByUrl(_url).then((data) {
      var list = data?.map((el) => Photo.fromJson(el)).toList();
      return list;
    });
    return result;
  }
}

我的测试:

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:unsplash/infrastructure/data_sources/unsplash_api.dart';
import 'package:unsplash/infrastructure/repositories/unsplash_photos_repository.dart';

    void main() {
      group('Unsplash api', () {
        test('should get search results', () async {
          final api = UnsplashApi();
          var result = await UnsplashPhotosRepository(api).getPhotosList();
          print(result.runtimeType);
          expect(result.isEmpty, false);
        });
      });

}

【问题讨论】:

  • 错误在哪一行?哪个文件?
  • 错误出在 UnsplashPhotosRepository 的 getPhotosList 方法上,该行是我们返回结果的地方(方法的最后一行)。

标签: json flutter dart async-await future


【解决方案1】:

问题最有可能来自这一行。

@override
  Future<List<Photo>> getPhotosList() async {
    var result = _api.fetchDataByUrl(_url).then((data) {
      var list = data?.map((el) => Photo.fromJson(el)).toList();
      return list;
    });
    return result;
  }

正如我所见,then() 中的 data 的类型是动态的,并且您希望 .map 覆盖它,因此您可能需要为它显式转换类型,因为它没有推断。

所以改成

 @override
  Future<List<Photo>> getPhotosList() async {
    final dynamic result = await _api.fetchDataByUrl(_url);
    return (result as List<dynamic>).map((dynamic el) => Photo.fromJson(el as Map<String, dynamic>)).toList();
  }

所以我完善了你的代码,希望对你有帮助。

abstract class PhotosRepository {
  Future<List<Photo>> getPhotosList();
}

class Photo {
  Photo({
    this.id,
    this.title,
    this.username,
    this.url,
  });

  factory Photo.fromJson(Map<String, dynamic> json) {
    return Photo(
      id: json['id'] as String,
      title: json['alt_description'] as String,
      username: json['user']['name'] as String,
      url: json['urls']['raw'] as String,
    );
  }

  final String id;
  final String title;
  final String username;
  final String url;

  @override
  String toString() {
    return '''$id, $title, $username, $url''';
  }
}

class UnsplashApi {
  final String _clientId = "84y4hgje4ac868c2646c0eddjhfedihdhff612b04c264f3374c97fff98ed253dc9";

  Future<String> _fetch(String url) async {
    try {
      url = buildUrl(url);
      final http.Response response = await http.get(url);
      if (response.statusCode == 200) {
        return response.body;
      }
      return null;
    } catch (e) {
      print(e);
      return null;
    }
  }

  Future<dynamic> fetchDataByUrl(String url) async {
    final String data = await _fetch(url);
    try {
      return json.decode(data);
    } catch (e) {
      print('Bad content, could not decode JSON $e');
    }
  }

  String buildUrl(String url) {
    return url.contains('?') ? '$url&client_id=$_clientId' : '$url?client_id=$_clientId';
  }
}

class UnsplashPhotosRepository implements PhotosRepository {
  UnsplashPhotosRepository(this._api);

  final UnsplashApi _api;
  final String _url = 'https://api.unsplash.com/photos';

  @override
  Future<List<Photo>> getPhotosList() async {
    final dynamic result = await _api.fetchDataByUrl(_url);
    return (result as List<dynamic>)?.map((dynamic el) => Photo.fromJson(el as Map<String, dynamic>))?.toList();
  }
}

结果是

[nV8K0uguyiw, man in green zip up jacket beside woman in black shirt, XPS, https://images.unsplash.com/photo-1593643946890-b5b85ade6451?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjE1OTU4N30, YE_2tlbi-IM, woman in black and white striped long sleeve shirt wearing black framed eyeglasses, Hans Mendoza, https://images.unsplash.com/photo-1597982178640-358c9e03bfae?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjE1OTU4N30, cHRDevKFDBw, green palm trees near city buildings during daytime, Cameron Venti, https://images.unsplash.com/photo-1597982087634-9884f03198ce?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjE1OTU4N30, -O0kKUPxDAM, green and blue lighted building during night time, ZQ Lee, https://images.unsplash.com/photo-1597991840620-cecdef61763b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjE1OTU4N30, F_-Ehgu36_8, person holding red disposable cup with black straw, jo jo ◡̈, https://images.unsplash.com/photo-1597922650352-77f42b5b6571?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjE1OTU4N30, 3_SeMFFlNvU, woman in brown t-shirt and black shorts <…>

你也可以在这里查看完整的代码

https://gist.github.com/mhadaily/d721979393dd031062d9e1674747762d

【讨论】:

  • 嗨,@Majid,我尝试替换您提供的行,但出现编译错误:位置参数过多:预期 1 个,但找到了 2 个。
  • 我已经尝试了这条线,但错误是一样的.. type 'Future' is not a subtype of type 'FutureOr>' Ill立即查看您的链接..
  • 哦,谢谢,它起作用了,我的错,我错过了(结果为 List)部分,只替换了其余部分。但是无论如何根据flutter文档为什么不习惯,我通过查看flutter.dev/docs/cookbook/networking/background-parsing了解到
  • 好的,我明白了,我的 getDataByUrl() 方法显式返回 Future 因为我不仅想获取 json 列表,还想获取 json 对象。因此 dart 无法从中推断出列表。非常感谢,Majid!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-23
  • 2021-01-24
  • 2021-09-20
  • 1970-01-01
  • 2021-10-07
  • 2021-12-23
相关资源
最近更新 更多