[Flutter必备]-Flutter中的网络访问

首先将依赖加上


1.巧妇难为无米之炊

首先咱们须要找写测试的url连接,有一个好地方,那就是Github提供了不少api
但在此以前咱们须要先行处理一些事,好比注册Github帐号,获取一个token
下面的Github帐号是我专门为Flutter准备的,token值就不加密了,你们不要乱玩。html


1.1:如何获取token

小头像-->Settings-->Developer settings -->Personal access tokens-->Generate new tokennode


1.2:如何经过post请求在你的github项目中添加一个文件

api:https://api.github.com/repos/用户名/项目名/contents/文件路径?access_token=token值
请求头:Content-Type=application/json,请求体以下,注意文件内容须要用base64
能够用wanandroid里的工具转化,该请求的其余参数能够详见Github的相应apiandroid

{
  "message": "commit from toly ",//提交信息
  "content": "aGVsbG8="//数据内容
}
复制代码

  • Flutter中发送put请求,在github项目中添加一个文件
import 'package:http/http.dart' as client;

main() {
  put();
}

void put() {
  var baseUrl="https://api.github.com/";
  var operate="repos/toly-flutter/flutter_journey/contents/";
  var path="http-put-file.txt";
  var params="?access_token=4514388836f6da9f6c6cf7ba0721f2a6d1e89528";//请求参数

  var api =baseUrl+operate+path+params;//url

  Map<String ,String> headers = {"Content-Type":"application/json"};//请求头
  var reqBody=""" { "message": "commit from commit from toly", "content": "aGVsbG8=" } """;//请求体

  client.put(api,headers:headers,body: reqBody).then((rep){
    print(rep.statusCode);
    print(rep.body);
  });
}
复制代码

注,Dart中将字符串转换base64能够:base64Encode(utf8.encode("hello"));git


1.3:经过put请求修改一个github文件

api:https://api.github.com/repos/用户名/项目名/contents/文件路径?access_token=token值
请求头:Content-Type=application/json,请求体以下,注意文件内容须要用base64
关于sha值,在添加的时候,响应体中有,见上图。每次修改也会返回新的sha值github

{
  "message": "update by toly ",//提交信息
  "content": "aGVsbG8="//数据内容
  "sha":"文件所对应的sha值"
}
复制代码

  • Flutter中发送put请求,在github项目中修改一个文件
void update() {
  var baseUrl="https://api.github.com/";
  var operate="repos/toly-flutter/flutter_journey/contents/";
  var path="http-put-file.txt";
  var params="?access_token=4514388836f6da9f6c6cf7ba0721f2a6d1e89528";//请求参数

  var api =baseUrl+operate+path+params;//url

  Map<String ,String> headers = {"Content-Type":"application/json"};//请求头
  var reqBody=""" { "message": "update by toly", "content": "5byg6aOO5o2354m554OI", "sha":"b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0" } """;//请求体

  client.put(api,headers:headers,body: reqBody).then((rep){
    print(rep.statusCode);
    print(rep.body);
  });
}
复制代码


1.4:经过delete请求删除一个github文件

api:https://api.github.com/repos/用户名/项目名/contents/文件路径?access_token=token值
请求头:Content-Type=application/json,能够要当前文件的sha值json

{
  "message": "delete by toly ",//提交信息
  "sha":"文件所对应的sha值"
}
复制代码

http库的delete请求竟然不能加请求体?!这里用PostMan演示一下后端


1.5:用post提交一个issue

api:https://api.github.com/repos/用户名/项目名/issues?access_token=token值
请求头:Content-Type=application/json,能够要当前文件的sha值api

{
  "title": "一块儿来Flutter之旅吧",
  "body": "Flutter,你们感受怎么样?应该不难吧!"
}
复制代码

  • Flutter中发送post请求,在github项目中添加一条issue
void post() {
  var baseUrl="https://api.github.com/";
  var operate="repos/toly-flutter/flutter_journey/issues";
  var params="?access_token=4514388836f6da9f6c6cf7ba0721f2a6d1e89528";//请求参数

  var api =baseUrl+operate+params;//url

  Map<String ,String> headers = {"Content-Type":"application/json"};//请求头
  var reqBody=""" { "title": "一块儿来Flutter之旅吧", "body": "Flutter,你们感受怎么样?应该不难吧!" } """;//请求体

  client.post(api,headers:headers,body: reqBody).then((rep){
    print(rep.statusCode);
    print(rep.body);
  });
}
复制代码

1.6:使用get请求获取一个issue

api:https://api.github.com/repos/用户名/项目名/issues/第几个?access_token=token值bash

void get(){
  //GET /repos/:owner/:repo/issues/:issue_number
  var baseUrl="https://api.github.com/";
  var operate="repos/toly-flutter/flutter_journey/issues/1";
  var params="?access_token=4514388836f6da9f6c6cf7ba0721f2a6d1e89528";//请求参数

  var api =baseUrl+operate+params;//url
  client.get(api).then((rep){
    print(rep.statusCode);
    print(rep.body);
  });
}
复制代码

好了,Http的几种经常使用的请求方式基本都会了吧。服务器


2. Json的解析

2.0:简介

Dart中的Map<String,String>对象和Json很是类似,因此能够用其做为转换媒介
经过convert包中的json.decode方法,能够将Json字符串转化成一个Map对象
在实体类中能够根据这个Map对象的属性对实体类进行实例化。

import 'dart:convert';

main() {
  String jsonStr = """ { "name":"Flutter之旅", "author":"张风捷特烈" } """;

  var book = Book.fromMap(json.decode(jsonStr));
  print(book.name);//Flutter之旅
  print(book.author);//张风捷特烈
}

class Book {
  String name;
  String author;

  Book.fromMap(Map<String, dynamic> json) {//根据Map穿件实例
    name = json["name"];
    author = json["author"];
  }
}
复制代码

2.1: 获取json

Github的https://api.github.com/users/用户名能够获取用户基本信息
这里就先解析个人https://api.github.com/users/toly1994328

{
  "login": "toly1994328",
  "id": 26687012,
  "node_id": "MDQ6VXNlcjI2Njg3MDEy",
  "avatar_url": "https://avatars3.githubusercontent.com/u/26687012?v=4",
  "gravatar_id": "",
  "url": "https://api.github.com/users/toly1994328",
  "html_url": "https://github.com/toly1994328",
  "followers_url": "https://api.github.com/users/toly1994328/followers",
  "following_url": "https://api.github.com/users/toly1994328/following{/other_user}",
  "gists_url": "https://api.github.com/users/toly1994328/gists{/gist_id}",
  "starred_url": "https://api.github.com/users/toly1994328/starred{/owner}{/repo}",
  "subscriptions_url": "https://api.github.com/users/toly1994328/subscriptions",
  "organizations_url": "https://api.github.com/users/toly1994328/orgs",
  "repos_url": "https://api.github.com/users/toly1994328/repos",
  "events_url": "https://api.github.com/users/toly1994328/events{/privacy}",
  "received_events_url": "https://api.github.com/users/toly1994328/received_events",
  "type": "User",
  "site_admin": false,
  "name": "张风捷特烈(toly)",
  "company": "捷特王国",
  "blog": "http://www.toly1994.com",
  "location": "China",
  "email": null,
  "hireable": null,
  "bio": "The king of coder.",
  "public_repos": 64,
  "public_gists": 0,
  "followers": 238,
  "following": 9,
  "created_at": "2017-03-26T09:55:25Z",
  "updated_at": "2019-07-15T08:05:52Z"
}
复制代码

2.2:实体类的生成

你也能够一点一点写出这个实体类,不过推荐用生成的方法,比较有时候字段太多,比较费劲
这里给一个用起来还不错的地方JSON to Dart,有时间本身写个转换插件来玩玩

class User {
  String login;
  int id;
  String nodeId;
  String avatarUrl;
  String gravatarId;
  String url;
  String htmlUrl;
  String followersUrl;
  String followingUrl;
  String gistsUrl;
  String starredUrl;
  String subscriptionsUrl;
  String organizationsUrl;
  String reposUrl;
  String eventsUrl;
  String receivedEventsUrl;
  String type;
  bool siteAdmin;
  String name;
  String company;
  String blog;
  String location;
  String email;
  String hireable;
  String bio;
  int publicRepos;
  int publicGists;
  int followers;
  int following;
  String createdAt;
  String updatedAt;

  User.fromJson(Map<String, dynamic> json) {
    login = json['login'];
    id = json['id'];
    nodeId = json['node_id'];
    avatarUrl = json['avatar_url'];
    gravatarId = json['gravatar_id'];
    url = json['url'];
    htmlUrl = json['html_url'];
    followersUrl = json['followers_url'];
    followingUrl = json['following_url'];
    gistsUrl = json['gists_url'];
    starredUrl = json['starred_url'];
    subscriptionsUrl = json['subscriptions_url'];
    organizationsUrl = json['organizations_url'];
    reposUrl = json['repos_url'];
    eventsUrl = json['events_url'];
    receivedEventsUrl = json['received_events_url'];
    type = json['type'];
    siteAdmin = json['site_admin'];
    name = json['name'];
    company = json['company'];
    blog = json['blog'];
    location = json['location'];
    email = json['email'];
    hireable = json['hireable'];
    bio = json['bio'];
    publicRepos = json['public_repos'];
    publicGists = json['public_gists'];
    followers = json['followers'];
    following = json['following'];
    createdAt = json['created_at'];
    updatedAt = json['updated_at'];
  }
复制代码

2.3.网络请求+json的使用

如今彻底能够将之前写的界面改一改,而后用Github获取的数据填充进去
这里只是简单展现一下,说明网络数据和布局界面的对接,并无作得太精细
GithubPanel就是之前写得界面稍微改装一下,这里代码就不贴了。

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as client;
import 'day6/github_panel.dart';
import 'day6/user.dart';

void main() {
  var baseUrl = "https://api.github.com/";
  var operate = "users/";
  var name = "toly1994328";

  var api = baseUrl + operate + name; //url
  client.get(api).then((rep) {
    var user = User.fromJson(json.decode(rep.body));
print(user.avatarUrl);
    var scaffold = Scaffold(
        appBar: AppBar(title: Text("Flutter之旅"),),
        body: GithubPanel(user: user,)
    );

    var app = MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: scaffold,
    );
    return runApp(app);
  });
}
复制代码

2.4.组件的再封装

你会发现上面虽然能用,可是看着真的很是难受,怎么让它用起来爽一点呢,两个字封装
实现一个GithubUserPanel,用法是传入一个用户名参数就好了。而且复用之前的面板。
因为网络访问是异步的,咱们须要一个有状态的组件,当异步加载完成以后,再setState从新渲染。

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as client;
import 'github_panel.dart';
import 'user.dart';
class GithubUserPanel extends StatefulWidget {
  GithubUserPanel({
    Key key,
    this.userName,
  }) : super(key: key);
  final String userName;
  @override
  _GithubUserPanelState createState() => _GithubUserPanelState();
}
class _GithubUserPanelState extends State<GithubUserPanel> {
  var baseUrl = "https://api.github.com/";
  var operate = "users/";
  var panel;
  @override
  void initState() {
    super.initState();
    var api = baseUrl + operate + widget.userName; //url
    client.get(api).then((rep) {
      var user = User.fromJson(json.decode(rep.body));
      panel = GithubPanel(
        user: user,
      );
      setState(() {});
    });
  }
  @override
  Widget build(BuildContext context) {
    return Container(
      child: panel,
    );
  }
}
复制代码

也就这写代码就好了,是否是感觉到了GithubPanel复用的爽感。


2.5.使用

这样用起来就和往常同样,只要传个名字就好了

void main() {

    var scaffold = Scaffold(
        appBar: AppBar(title: Text("Flutter之旅"),),
        body: GithubUserPanel(userName: "toly1994328",)
    );

    var app = MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: scaffold,
    );
    return runApp(app);

}
复制代码

3.网络请求包dio的使用

dio做为JoJo的奇妙冒险的几部大boss,听名字就挺霸气,在网页搜dio根本没有Flutter的事
上来讲的那个http包相对比较原始,dio封装的更好些,用法比较多。
反正再怎么玩,都脱离不了http请求,因此要分清主次,切莫舍本逐末。

dependencies:
  dio: ^2.1.13
复制代码

3.1:get获取github用户信息
var dio=Dio();
var baseUrl = "https://api.github.com/";
var operate = "users/";
var api=baseUrl+operate+"toly1994328";
dio.get(api).then((rep)=>print(rep.data));
复制代码

3.2: put请求添加github项目文件
void put() {
  var baseUrl="https://api.github.com/";
  var operate="repos/toly-flutter/flutter_journey/contents/";
  var path="http-put-file-dio.txt";
  var params="?access_token=4514388836f6da9f6c6cf7ba0721f2a6d1e89528";//请求参数
  var api =baseUrl+operate+path+params;//url
  Map<String ,String> headers = {"Content-Type":"application/json"};//请求头
  var reqBody=""" { "message": "commit from commit from toly", "content": "aGVsbG8=" } """;//请求体
  Dio().put(api,queryParameters:headers,data: reqBody).then((rep){
    print(rep.statusCode);
    print(rep.data);
  });
}
复制代码

3.3:delete请求删除github项目文件

dio中的delete是能够添加请求体的

void delete() {
  var baseUrl="https://api.github.com/";
  var operate="repos/toly-flutter/flutter_journey/contents/";
  var path="http-put-file-dio.txt";
  var params="?access_token=4514388836f6da9f6c6cf7ba0721f2a6d1e89528";//请求参数
  var api =baseUrl+operate+path+params;//url
  Map<String ,String> headers = {"Content-Type":"application/json"};
  var reqBody=""" { "message": "delete by toly", "sha": "b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0" } """;
  Dio().delete(api,queryParameters:headers,data: reqBody).then((rep){
    print(rep.data);
  });
}
复制代码

3.4:post提交一条issue
void post() {
  var baseUrl="https://api.github.com/";
  var operate="repos/toly-flutter/flutter_journey/issues";
  var params="?access_token=4514388836f6da9f6c6cf7ba0721f2a6d1e89528";//请求参数
  var api =baseUrl+operate+params;//url
  Map<String ,String> headers = {"Content-Type":"application/json"};//请求头
  var reqBody=""" { "title": "张风捷特烈", "body": "我是谁,我在哪里,我要到哪去?" } """;//请求体
  Dio().post(api,queryParameters:headers,data: reqBody).then((rep){
    print(rep.statusCode);
    print(rep.data);
  });
}
复制代码

3.5:经过dio下载

就拿掘金的app下载吧,在dio中是很方便的,一行搞定。

var url="https://landing.juejin.im/app-download?utm_source=app_download&utm_medium=yingyongbao&utm_campaign=app1808";
Dio().download(url,"./掘金.apk").then((rep){
  print(rep.statusCode);
  print(rep.data);
});
复制代码

3.6:经过dio上传

文件上传一直是个较难问题,要实现文件上传,你须要一点后端的知识
核心就是客户端将数据经过请求给服务器,服务器将请求中的内容进行操做
上传也就是服务器将数据或文件存储到了服务端指定位置。
通常经过表单提交,也能够直接将二进制流经过请求体给服务端。

FormData formData = FormData.from({//建立表单
  "name": "toly",
  "age": 25,
  "data":  UploadFileInfo(File("./data.json"), "data.json"),
  "image":  UploadFileInfo(File("./photo.png"), "photo.png"),
});
var api="/loadFile";
Dio().post(api, data: formData).then((rep){//将表单经过请求体传给服务端
});
复制代码

3.7:基本配置参数

看Dio的源码中有一个可选参数BaseOptions

---->[dio-2.1.13/lib/src/dio.dart:53]----
class Dio {
  /// Create Dio instance with default [Options].
  /// It's mostly just one Dio instance in your application. Dio([BaseOptions options]) { ---->[dio-2.1.13/lib/src/options.dart:39]---- class BaseOptions extends _RequestConfig { BaseOptions({ String method,//请求方法 int connectTimeout,//连接超时 int receiveTimeout,//接收超时 Iterable<Cookie> cookies,//cookies this.baseUrl,//基础Url this.queryParameters,//请求参数 Map<String, dynamic> extra, Map<String, dynamic> headers,//请求头 ResponseType responseType = ResponseType.json,//返回类型 ContentType contentType,//内容类型 ValidateStatus validateStatus, bool receiveDataWhenStatusError = true, bool followRedirects = true, int maxRedirects = 5, RequestEncoder requestEncoder, ResponseDecoder responseDecoder, }) : super( 复制代码

关于更多dio的用法,这里不过多介绍,能够去这里看一下,dio做者的讲解


结语

本文到此接近尾声了,若是想快速尝鲜Flutter,《Flutter七日》会是你的必备佳品;若是想细细探究它,那就跟随个人脚步,完成一次Flutter之旅。
另外本人有一个Flutter微信交流群,欢迎小伙伴加入,共同探讨Flutter的问题,本人微信号:zdl1994328,期待与你的交流与切磋。

相关文章
相关标签/搜索