用 Bloc 实现简单的 rxDart 没有得到结果

Posted

技术标签:

【中文标题】用 Bloc 实现简单的 rxDart 没有得到结果【英文标题】:implementing simple rxDart with Bloc don't get result 【发布时间】:2019-09-28 12:13:15 【问题描述】:

来自我的网络服务器上的这个链接

http://instamaker.ir/api/v1/getPersons

我正在尝试从该结果中获取结果并打印 avatar,不幸的是,我使用 rxDartBloc 的实现没有从该响应中得到结果,我没有收到任何错误

服务器响应这个简化的结果:


  "active": 1,
  "name": "my name",
  "email": " 3 ",
  "loginType": " 3 ",
  "mobile_number": " 3 ",

  ...

  "api_token": "1yK3PvAsBA6r",
  "created_at": "2019-02-12 19:06:34",
  "updated_at": "2019-02-12 19:06:34"

main.dart 文件:(点击按钮从服务器获取结果)

StreamBuilder(
  stream: bloc.login,
  builder: (context,
      AsyncSnapshot<UserInfo>
      snapshot) 
    if (snapshot.hasData) 
      parseResponse(snapshot);
    
  ,
);
void parseResponse(AsyncSnapshot<UserInfo> snapshot) 
  debugPrint(snapshot.data.avatar);

LoginBlock类:

class LoginBlock
  final _repository = Repository();
  final _login_fetcher = PublishSubject<UserInfo>();

  Observable<UserInfo> get login=>_login_fetcher.stream;

  fetchLogin() async
    UserInfo userInfo = await _repository.userInfo();
    _login_fetcher.sink.add(userInfo);
  

  dispose()
    _login_fetcher.close();
  


final bloc = LoginBlock();

Repository类:

class Repository 
  final userInformation = InstagramApiProviders();

  Future<UserInfo> userInfo() => userInformation.checkUserLogin();

我的模特:

class UserInfo 
  int _active;
  String _name;
  ...

  UserInfo.fromJsonMap(Map<String, dynamic> map)
      : _active = map["active"],
        _name = map["name"],
        ...

  Map<String, dynamic> toJson() 
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['active'] = _active;
    data['name'] = _name;
    ...

    return data;
  

  //GETTERS

BaseUrl类:

class BaseUrl 
  static const url = 'http://instamaker.ir';

然后InstagramApiProviders类:

class InstagramApiProviders 
  Client client = Client();

  Future<UserInfo> checkUserLogin() async 
    final response = await client.get(BaseUrl.url+'/api/v1/getPersons');
    print("entered  "+BaseUrl.url+'/api/v1/getPersons');
    if (response.statusCode == 200) 
      return UserInfo.fromJsonMap(json.decode(response.body));
     else
      throw Exception('Failed to load');
  

【问题讨论】:

当你说“不要从这个响应中得到结果并且我没有得到任何错误”是因为你无法从服务器获取数据或者是因为你看不到任何变化在你的用户界面中? @Marcos Boaventura 是的,对于简单的显示结果,我想使用此代码 void parseResponse(AsyncSnapshot&lt;UserInfo&gt; snapshot) debugPrint(snapshot.data.avatar); 嗯,你需要把你的 StreamBuilder 小部件放在一个小部件树中,以便调用 StreamBuilder **builder 方法我认为这就是你看不到任何结果的原因。我在这里做了一些测试,我得到了它的工作。 【参考方案1】:

这里的答案是我为完成这项工作所做的测试的一部分。我可以在这里进行所有测试,但我认为问题的原因是因为 StreamBuilder 是一个小部件,所以他的 builder 方法回调仅在小部件位于颤振小部件树中时调用。在您的示例中,您只是创建了一个 StreamBuilder,因此永远不会调用构建器方法,因为此小部件不在小部件树中。

作为建议,首先测试您的代码仅更改 UI 层...执行以下操作:

@override
  Widget build(BuildContext context) 

    return Scaffold(
      appBar: AppBar(
        actions: <Widget>[
          IconButton(icon: Icon(Icons.assessment), onPressed: () => loginBlock.fetchLogin()),
        ],
      ),
      body: StreamBuilder<UserInfo>(
        stream: loginBlock.login,
        builder: (context, snapshot)
          if (snapshot.hasData)
            parseResponse(snapshot);
            return Text('user: $snapshot.data.name ');
          
          if (snapshot.hasError)
            return Text('$snapshot.error');
          else return Text('There is no data');
        ,
      ),
    );

在这里,我们将 StreamBuilder 放在小部件树中,以便调用 builder 回调,也许您会看到结果。如果失败,请评论说我用我的完整测试代码更新了我的答案。

使用我进行测试的来源更新答案。

基本模型

class UserInfo 
  int _active;
  String name;

  UserInfo.fromJsonMap(Map<String, dynamic> map) 
    _active = map["active"];
    name = map["name"];
  

  Map<String, dynamic> toJson() => 
    'active' : _active,
    'name' : name,
  ;
 

提供者类

class InstagramApiProviders 
  Future<UserInfo> checkUserLogin() async 

    UserInfo info;

    try 
      http.Response resp = await http.get("http://instamaker.ir/api/v1/getPersons");
      if (resp.statusCode == 200)
        print('get response');
        print( resp.body );
        info = UserInfo.fromJsonMap(  Map.from(  json.decode(resp.body ) ));
      
    
    catch (ex) 
      throw ex;
    
    print('returning $info');
    return info;
  

存储库

class Repository 
  final userInformation = InstagramApiProviders();
  Future<UserInfo> userInfo() => userInformation.checkUserLogin().then((user) => user);

BLoC 类

class LoginBlock
  final _repository = Repository();
  final _login_fetcher = PublishSubject<UserInfo>();

  Observable<UserInfo> get login=>_login_fetcher.stream;

  fetchLogin() async 
    UserInfo info = await _repository.userInfo();
      _login_fetcher.sink.add(info);
  

  dispose()
    _login_fetcher.close();
  

小部件用户界面

这会开始显示There is no data 消息,但是当您点击 appBar 按钮时稍等片刻,然后会获取数据并更新 UI。

class WidgetToShowData extends StatelessWidget 

  final LoginBlock bloc = LoginBlock();

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        actions: <Widget>[
          IconButton(icon: Icon(Icons.assessment), onPressed: () => loginBlock.fetchLogin()),
        ],
      ),
      body: StreamBuilder<UserInfo>(
        stream: loginBlock.login,
        builder: (context, snapshot)
          if (snapshot.hasData)
            parseResponse(snapshot);
            return Text('user: $snapshot.data.name ');
          
          if (snapshot.hasError)
            return Text('$snapshot.error');
          else return Text('There is no data');
        ,
      ),
    );
  

  void parseResponse(AsyncSnapshot<UserInfo> snapshot) 
    debugPrint(snapshot.data.name);
  

【讨论】:

不幸的是,我收到了There is no data 消息。看来代码是正确的 你点击appBar图标获取数据了吗? 能否请您在帖子中填写您的代码?我得到错误 我收到 MediaQuery.of() called with a context that does not contain a MediaQuery. 错误 嗯,这个错误在你的源代码的其他部分,我没有看到。尝试创建一个简单的屏幕来仅使用 WidgetToShowData 进行测试。此测试已成功从您的网络服务器获取并显示数据。

以上是关于用 Bloc 实现简单的 rxDart 没有得到结果的主要内容,如果未能解决你的问题,请参考以下文章

没有 BLoC 的 Flutter 状态管理

如何过滤 rxdart 中的 observable 列表

练习bloc , 动画

Flutter状态管理:RxDart

Flutter状态管理:RxDart

错误:错误状态:流已被收听