zoukankan      html  css  js  c++  java
  • Flutter 开发从 0 到 1(二)框架与网络

    框架

    之前做 APP 开发的时候,我都是担任 Android 组 leader,新项目起来,我会做技术预研,如《一套完整的 Android 通用框架》,一般会使用 MVP 模式(现在应该是 MVVM 模式),网络请求框架使用 Retrofit,图片加载使用 Glide,图片缩放和裁剪分别使用 PhotoView 和 uCrop 等,必要时,我会写个 sample 放项目里,让同事可以参考。

    这个也是个新项目,我也需要做下技术预研,Flutter 网络请求框架需要使用什么?图片加载又使用什么?文章详情,我打算使用 Markdown,这 Flutter 能实现吗?等等,这些都是需要事前做好调研。

    这个项目,代码版本管理用 GitHub,首先新建一个 Flutter 项目,GitHub 也新建个私有项目(暂时不公开吧),用如下命令将本地代码和远程 GitHub 关联起来。

    echo "# andblog" >> README.md
    git init
    git add README.md
    git commit -m "first commit"
    
    git remote add origin https://github.com/WuXiaolong/andblog.git
    git push -u origin master
    

    关联 OK,后面修改,就直接使用 Android Studio 自带的 Git 来提交代码。

    接下来来看看 Flutter 网络请求框架使用什么?怎么使用?

    网络

    数据来源

    说到网络请求框架,首先要解决数据从何而来,我没有后端(其实我可以开发),没有服务器,怎么搞?莫急,都说本系列文章是从零开发 APP,且能一个人做一个项目,我自然有办法。

    数据我使用的 Bmob,它可以创建你想要的表,支持 RestAPI,这可以为做 APP 省去后端开发成本,当然像 Bmob 提供这样的服务有很多,就不一一介绍,Bmob 如何使用,也不说了,官方有很详细的文档,你可以点击文章底部「阅读原文」注册个账号玩玩。

    http

    网络请求框架的数据有了,可以玩起来了。

    以请求文章列表接口示例,先用 Postman 看下数据结构:

    {
        "results": [
            {
                "content": "文章内容测试1",
                "cover": "http://pic1.win4000.com/wallpaper/2020-04-21/5e9e676001e20.jpg",
                "createdAt": "2020-07-05 13:50:58",
                "date": "2020.07.01",
                "objectId": "ct7BGGGV",
                "summary": "摘要1",
                "title": "标题测试1",
                "updatedAt": "2020-07-05 13:53:16"
            },
            {
                "content": "文章内容测试2",
                "cover": "http://pic1.win4000.com/wallpaper/2020-04-21/5e9e676001e20.jpg",
                "createdAt": "2020-07-05 13:52:37",
                "date": "2020.07.02",
                "objectId": "3L42777G",
                "summary": "摘要2",
                "title": "标题测试2",
                "updatedAt": "2020-07-05 13:53:10"
            }
        ]
    }
    

    Flutter 提供了网络请求框架是 http,地址:https://pub.flutter-io.cn/packages/http

    添加 http 包,在 pubspec.yaml 添加:

    dependencies:
      http: ^0.12.1
    

    项目根目录执行命令flutter pub get安装软件包。

    新建 blog_list_page.dart 用来展示文章列表,blog.dart 是文章列表的结构表,把入口 main.dart 直接加载文章列表,详细代码如下。

    main.dart:

    import 'package:flutter/material.dart';
    
    import 'andblog/list/blog_list_page.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'AndBlog',
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: new BlogListPage(),
        );
      }
    }
    
    

    blog_list_page.dart:

    import 'package:flutter/material.dart';
    import 'package:flutter_andblog/andblog/http/http_common.dart';
    import 'package:http/http.dart' as http;
    import 'blog.dart';
    
    class BlogListPage extends StatefulWidget {
      @override
      BlogListPageState createState() => new BlogListPageState();
    }
    
    class BlogListPageState extends State<BlogListPage> {
      List<Blog> blogList = [];
    
      @override
      void initState() {
        super.initState();
        //一进页面就请求接口
        getBlogListData();
      }
    
      //网络请求
      getBlogListData() async {
        var response = await http.get(HttpCommon.blog_list_url, headers: HttpCommon.headers());
        if (response.statusCode == 200) {
          // setState 相当于 runOnUiThread
          setState(() {
            blogList = Blog.decodeData(response.body);
          });
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('AndBlog'),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'You have pushed the button this many times:',
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ), // This trailing comma makes auto-formatting nicer for build methods.
        );
      }
    }
    

    把网络 url 都放在 HttpCommon,详细代码在 http_common.dart:

    class HttpCommon{
    
      static var blog_list_url = 'https://api2.bmob.cn/1/classes/ArticleTable/';
    
      static Map<String, String> headers(){
        //设置header
        Map<String, String> headers = new Map();
        headers["X-Bmob-Application-Id"] = "bmob Application-Id";
        headers["X-Bmob-REST-API-Key"] = "bmob REST-API-Key";
        headers["Content-Type"] = "application/json";
        return headers;
      }
    
    }
    

    网络请求数据解析放在 blog.dart:

    import 'dart:convert';
    
    class Blog{
      final String content;
      final String cover;
      final String date;
      final String objectId;
      final String summary;
      final String title;
    
      //构造函数
      Blog({
        this.content,
        this.cover,
        this.date,
        this.objectId,
        this.summary,
        this.title,
      });
    
      static List<Blog> decodeData(String jsonData) {
        List<Blog> blogList = new List<Blog>();
        var data = json.decode(jsonData);
        var results = data['results'];
        print('results='+results[0]['content']);
        for (int i = 0; i < results.length; i++) {
          blogList.add(fromMap(results[i]));
        }
        return blogList;
      }
    
      static Blog fromMap(Map<String, dynamic> map) {
    
        return new Blog(
          content: map['content'],
          cover: map['cover'],
          date: map['date'],
          objectId: map['objectId'],
          summary: map['summary'],
          title: map['title'],
        );
      }
    }
    

    我习惯性打印print('results='+results[0]['content']);看看数据解析对不对,多次尝试最后打印文章内容测试1,达到了预期。

    json_serializable

    在写文章列表的结构 blog.dart 需要手动一个个敲字段,然后解析,Flutter 有没有像 GsonFormat 这样自动解析的插件,当然是有,是 json_serializable,使用 json_serializable,你需要一个常规依赖,以及两个 dev 依赖:

    dependencies:
      flutter:
        sdk: flutter
      json_annotation: ^3.0.1
    
    
    dev_dependencies:
      flutter_test:
        sdk: flutter
      build_runner: ^1.10.0
      json_serializable: ^3.3.0
    

    项目根目录执行命令flutter pub get安装软件包。

    以文章详情结构体示例:

    {
        "content": "文章内容测试1",
        "cover": "http://pic1.win4000.com/wallpaper/2020-04-21/5e9e676001e20.jpg",
        "createdAt": "2020-07-05 13:50:58",
        "date": "2020.07.01",
        "objectId": "ct7BGGGV",
        "summary": "摘要1",
        "title": "标题测试1",
        "updatedAt": "2020-07-05 13:53:16"
    }
    

    根据 json 创建实体类 detail.dart:

    import 'package:json_annotation/json_annotation.dart';
    
    //为了使实体类文件找到生成文件,需要 part 'detail.g.dart'
    part 'detail.g.dart';
    
    @JsonSerializable()
    class Detail{
      final String content;
      final String cover;
      final String date;
      final String objectId;
      final String summary;
      final String title;
    
      //构造函数
      Detail({
        this.content,
        this.cover,
        this.date,
        this.objectId,
        this.summary,
        this.title,
      });
    }
    

    刚写完 detail.g.dart 会报错,这是正常的!因为我们还没生成解析文件。

    接下来解析,项目根目录执行命令flutter packages pub run build_runner build

    会发现生成一个 detail.g.dart 文件:

    // GENERATED CODE - DO NOT MODIFY BY HAND
    
    part of 'detail.dart';
    
    // **************************************************************************
    // JsonSerializableGenerator
    // **************************************************************************
    
    Detail _$DetailFromJson(Map<String, dynamic> json) {
      return Detail(
        content: json['content'] as String,
        cover: json['cover'] as String,
        date: json['date'] as String,
        objectId: json['objectId'] as String,
        summary: json['summary'] as String,
        title: json['title'] as String,
      );
    }
    
    Map<String, dynamic> _$DetailToJson(Detail instance) => <String, dynamic>{
          'content': instance.content,
          'cover': instance.cover,
          'date': instance.date,
          'objectId': instance.objectId,
          'summary': instance.summary,
          'title': instance.title,
        };
    
    

    然后把这两个方法放到 detail.dart:

    factory Detail.fromJson(Map<String, dynamic> json) => _$DetailFromJson(json);
    
    Map<String, dynamic> toJson() => _$DetailToJson(this);
    

    接下来就可以调用 fromJson 方法解析网络请求的数据:

    var data = json.decode(response.body);
    detail = Detail.fromJson(data);
    print('results='+detail.title);
    

    这样看下来,使用 json_serializable 并没有方便多少,只是把解析字段省了,最烦没有把添加字段步骤自动化,比 GsonFormat 弱爆了。

  • 相关阅读:
    (转载)VS2010/MFC编程入门之四十六(MFC常用类:MFC异常处理)
    (转载)VS2010/MFC编程入门之四十五(MFC常用类:CFile文件操作类)
    (转载)VS2010/MFC编程入门之四十四(MFC常用类:定时器Timer)
    (转载)VS2010/MFC编程入门之四十三(MFC常用类:CTime类和CTimeSpan类)
    Android笔记之ImageView
    Activity的四种launchMode
    Eclipse使用技巧
    ubuntu下使用MyEclipse以及MyEclipse Tomcat
    Android笔记之Json数据解析
    【转】[Android_机制]_Http和Socket连接区别
  • 原文地址:https://www.cnblogs.com/WuXiaolong/p/13341194.html
Copyright © 2011-2022 走看看