美文网首页
使用BLOC模式构建Flutter项目(一)

使用BLOC模式构建Flutter项目(一)

作者: 渣渣曦 | 来源:发表于2019-07-23 16:34 被阅读0次

    BLoC可视化架构图


    image.png

    上图展示了数据流如何从UI层到数据层,反之亦然。BLoC不会调用任何UI层的widget。UI层侦听(observe)BLOC类的变化。
    1、首先建立一个新项目并删掉main.dart文件中的所有代码,在终端中输入以下代码:

    flutter create my_movies
    

    在main.dart文件中输入以下代码:

    import 'package:flutter/material.dart';
    import 'src/app.dart';
    
    void main(){
      runApp(App());
    }
    

    在lib包下创建src包,并在src包下创建一个名为app.dart的文件。文件内容如下:

    import 'package:flutter/material.dart';
    import 'ui/movie_list.dart';
    
    class App extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return MaterialApp(
            theme: ThemeData.dark(),
            home: Scaffold(
              body: MovieList(),
            ),
          );
      }
    }
    

    在src包下创建名为blocs,models,resources和ui的包,下图展示项目目录结构:

    image.png
    blocs存放BLOC相关文件。models存放POJO类或服务端响应的JSON返回值。resources存放repository类和网络调用实现类。ui存放可视化用户界面组件。
    在pubspec.yaml里增加rxdart和http两个三方库:
    image.png
    创建item_model.dart。通过https://javiercbk.github.io/json_to_dart/
    把服务响应的JSON数据转为POJO响应model。 内容如下:
    class ItemModel {
      int page;
      int totalResults;
      int totalPages;
      List<Results> results;
    
      ItemModel({this.page, this.totalResults, this.totalPages, this.results});
    
      ItemModel.fromJson(Map<String, dynamic> json) {
        page = json['page'];
        totalResults = json['total_results'];
        totalPages = json['total_pages'];
        if (json['results'] != null) {
          results = new List<Results>();
          json['results'].forEach((v) {
            results.add(new Results.fromJson(v));
          });
        }
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = new Map<String, dynamic>();
        data['page'] = this.page;
        data['total_results'] = this.totalResults;
        data['total_pages'] = this.totalPages;
        if (this.results != null) {
          data['results'] = this.results.map((v) => v.toJson()).toList();
        }
        return data;
      }
    }
    
    class Results {
      int voteCount;
      int id;
      bool video;
      var voteAverage;
      String title;
      double popularity;
      String posterPath;
      String originalLanguage;
      String originalTitle;
      List<int> genreIds;
      String backdropPath;
      bool adult;
      String overview;
      String releaseDate;
    
      Results(
          {this.voteCount,
          this.id,
          this.video,
          this.voteAverage,
          this.title,
          this.popularity,
          this.posterPath,
          this.originalLanguage,
          this.originalTitle,
          this.genreIds,
          this.backdropPath,
          this.adult,
          this.overview,
          this.releaseDate});
    
      Results.fromJson(Map<String, dynamic> json) {
        voteCount = json['vote_count'];
        id = json['id'];
        video = json['video'];
        voteAverage = json['vote_average'];
        title = json['title'];
        popularity = json['popularity'];
        posterPath = json['poster_path'];
        originalLanguage = json['original_language'];
        originalTitle = json['original_title'];
        genreIds = json['genre_ids'].cast<int>();
        backdropPath = json['backdrop_path'];
        adult = json['adult'];
        overview = json['overview'];
        releaseDate = json['release_date'];
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = new Map<String, dynamic>();
        data['vote_count'] = this.voteCount;
        data['id'] = this.id;
        data['video'] = this.video;
        data['vote_average'] = this.voteAverage;
        data['title'] = this.title;
        data['popularity'] = this.popularity;
        data['poster_path'] = this.posterPath;
        data['original_language'] = this.originalLanguage;
        data['original_title'] = this.originalTitle;
        data['genre_ids'] = this.genreIds;
        data['backdrop_path'] = this.backdropPath;
        data['adult'] = this.adult;
        data['overview'] = this.overview;
        data['release_date'] = this.releaseDate;
        return data;
      }
    }
    

    在resources包中创建名为movie_api_provider.dart文件,内容如下:

    import 'dart:async';
    import 'package:http/http.dart' show Client;
    import 'dart:convert';
    import '../models/item_model.dart';
    
    class MovieApiProvider {
      Client client = Client();
      final _apiKey = '802b2c4b88ea1183e50e6b285a27696e';
    
      Future<ItemModel> fetchMovieList() async {
        print("entered");
        final response = await client
            .get("http://api.themoviedb.org/3/movie/popular?api_key=$_apiKey");
        print(response.body.toString());
        if (response.statusCode == 200) {
          // If the call to the server was successful, parse the JSON
          return ItemModel.fromJson(json.decode(response.body));
        } else {
          // If that call was not successful, throw an error.
          throw Exception('Failed to load post');
        }
      }
    }
    

    在resources包中创建名为respository.dart的文件,内容如下:

    import 'dart:async';
    import 'movie_api_provider.dart';
    import '../models/item_model.dart';
    
    class Repository {
      final moviesApiProvider = MovieApiProvider();
    
      Future<ItemModel> fetchAllMovies() => moviesApiProvider.fetchMovieList();
    }
    

    导入movie_api_provider.dart文件并调用fetchMovieList()方法。Respository类将为BLoC提供数据流出点。
    在blocs包中创建movies_bloc.dart文件,内容如下:

    import '../resources/repository.dart';
    import 'package:rxdart/rxdart.dart';
    import '../models/item_model.dart';
    
    class MoviesBloc {
      final _repository = Repository();
      final _moviesFetcher = PublishSubject<ItemModel>();
    
      Observable<ItemModel> get allMovies => _moviesFetcher.stream;
    
      fetchAllMovies() async {
        ItemModel itemModel = await _repository.fetchAllMovies();
        _moviesFetcher.sink.add(itemModel);
      }
    
      dispose() {
        _moviesFetcher.close();
      }
    }
    
    final bloc = MoviesBloc();
    

    在ui包中创建movie_list.dart文件。内容如下:

    import 'package:flutter/material.dart';
    import '../models/item_model.dart';
    import '../blocs/movies_bloc.dart';
    
    class MovieList extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        bloc.fetchAllMovies();
        return Scaffold(
          appBar: AppBar(
            title: Text('Popular Movies'),
          ),
          body: StreamBuilder(
            stream: bloc.allMovies,
            builder: (context, AsyncSnapshot<ItemModel> snapshot) {
              if (snapshot.hasData) {
                return buildList(snapshot);
              } else if (snapshot.hasError) {
                return Text(snapshot.error.toString());
              }
              return Center(child: CircularProgressIndicator());
            },
          ),
        );
      }
    
      Widget buildList(AsyncSnapshot<ItemModel> snapshot) {
        return GridView.builder(
            itemCount: snapshot.data.results.length,
            gridDelegate:
                new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
            itemBuilder: (BuildContext context, int index) {
              return Image.network(
                'https://image.tmdb.org/t/p/w185${snapshot.data
                    .results[index].posterPath}',
                fit: BoxFit.cover,
              );
            });
      }
    }
    

    运行结果如下图:


    image.png

    相关文章

      网友评论

          本文标题:使用BLOC模式构建Flutter项目(一)

          本文链接:https://www.haomeiwen.com/subject/pvlolctx.html