天天看點

post json背景處理資料_Flutter 中文文檔:在背景處理 JSON 資料解析使用步驟1. 添加 http 包2. 發起一個網絡請求 備忘3. 解析并将 json 轉換成一列圖檔

post json背景處理資料_Flutter 中文文檔:在背景處理 JSON 資料解析使用步驟1. 添加 http 包2. 發起一個網絡請求 備忘3. 解析并将 json 轉換成一列圖檔

在後頭處理JSON資料解析

Dart 應用通常隻會在單線程中處理它們的工作。并且在大多數情況中,這種模式不但簡化了代碼而且速度也夠快,基本不會出現像動畫卡頓以及性能不足這種「不靠譜」的問題。

但是,當你需要進行一個非常複雜的計算時,例如解析一個巨大的 JSON 文檔。如果這項工作耗時超過了 16 毫秒,那麼你的使用者就會感受到不靠譜。

為了避免這種不靠譜的情況,像上面那樣消耗性能的計算就應該放在背景處理。在 Android 平台上,這意味着在一個不同的線程中排程工作。而在 Flutter 中,你可以使用一個單獨的 Isolate。如下圖示例:

post json背景處理資料_Flutter 中文文檔:在背景處理 JSON 資料解析使用步驟1. 添加 http 包2. 發起一個網絡請求 備忘3. 解析并将 json 轉換成一列圖檔

isolate使用demo

使用步驟

  1. 添加 http 包
  2. 使用 http 包發起一個網絡請求
  3. 将響應轉換成一列照片
  4. 将這個工作移交給一個單獨的 isolate

1. 添加 http 包

首先,在你的項目中添加 http 包,http 包會讓網絡請求變的像從 JSON 端點擷取資料一樣簡單。

dependencies: http:            

2. 發起一個網絡請求

在這個例子中,你将會使用 http.get() 方法通過 JSONPlaceholder REST API 擷取到一個包含 5000 張圖檔對象的超大 JSON 文檔。

Future fetchPhotos(http.Client client) async { return client.get('https://jsonplaceholder.typicode.com/photos');}           

備忘

在這個例子中你需要給方法添加了一個 http.Client 參數。這将使得該方法測試起來更容易同時也可以在不同環境中使用。

3. 解析并将 json 轉換成一列圖檔

接下來,根據 Flutter 中文文檔:擷取網絡資料 的說明,為了讓接下來的資料處理更簡單,你需要将 http.Response 轉換成一列 Dart 對象。

3.1 建立一個 Photo 類

首先,建立一個包含圖檔資料的 Photo 類。還需要一個 fromJson 的工廠方法,使得通過 json 建立 Photo 變的更加友善。

class Photo { final int id; final String title; final String thumbnailUrl; Photo({this.id, this.title, this.thumbnailUrl}); factory Photo.fromJson(Map json) { return Photo( id: json['id'] as int, title: json['title'] as String, thumbnailUrl: json['thumbnailUrl'] as String, ); }}           

3.2 将響應轉換成一列圖檔

現在,為了讓 fetchPhotos() 方法可以傳回一個 Future>,我們需要以下兩點更新:

  • 建立一個可以将響應體轉換成 List 的方法:parsePhotos()
  • 在 fetchPhotos() 方法中使用 parsePhotos() 方法
// A function that converts a response body into a List.List parsePhotos(String responseBody) { final parsed = json.decode(responseBody).cast>(); return parsed.map((json) => Photo.fromJson(json)).toList();}Future> fetchPhotos(http.Client client) async { final response = await client.get('https://jsonplaceholder.typicode.com/photos'); return parsePhotos(response.body);}           

4. 将這部分工作移交到單獨的 isolate 中

如果你在一台很慢的手機上運作 fetchPhotos() 函數,你或許會注意到應用會有點卡頓,因為它需要解析并轉換 json。顯然這并不好,是以你要避免它。

那麼我們究竟可以做什麼呢?那就是通過 Flutter 提供的 compute() 方法将解析和轉換的工作移交到一個背景 isolate 中。這個 compute() 函數可以在背景 isolate 中運作複雜的函數并傳回結果。在這裡,我們就需要将 parsePhotos() 方法放入背景。

Future> fetchPhotos(http.Client client) async { final response = await client.get('https://jsonplaceholder.typicode.com/photos'); // Use the compute function to run parsePhotos in a separate isolate. return compute(parsePhotos, response.body);}           

4.1 使用 Isolates 需要注意的地方

Isolates 通過來回傳遞消息來交流。這些消息可以是任何值,它們可以是 null、num、bool、double 或者 String,哪怕是像這個例子中的 List 這樣簡單對象都沒問題。

當你試圖傳遞更複雜的對象時,你可能會遇到錯誤,例如在 isolates 之間的 Future 或者 http.Response。

完整樣例

import 'dart:async';import 'dart:convert';import 'package:flutter/foundation.dart';import 'package:flutter/material.dart';import 'package:http/http.dart' as http;Future> fetchPhotos(http.Client client) async { final response = await client.get('https://jsonplaceholder.typicode.com/photos'); // Use the compute function to run parsePhotos in a separate isolate. return compute(parsePhotos, response.body);}// A function that converts a response body into a List.List parsePhotos(String responseBody) { final parsed = json.decode(responseBody).cast>(); return parsed.map((json) => Photo.fromJson(json)).toList();}class Photo { final int albumId; final int id; final String title; final String url; final String thumbnailUrl; Photo({this.albumId, this.id, this.title, this.url, this.thumbnailUrl}); factory Photo.fromJson(Map json) { return Photo( albumId: json['albumId'] as int, id: json['id'] as int, title: json['title'] as String, url: json['url'] as String, thumbnailUrl: json['thumbnailUrl'] as String, ); }}void main() => runApp(MyApp());class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { final appTitle = 'Isolate Demo'; return MaterialApp( title: appTitle, home: MyHomePage(title: appTitle), ); }}class MyHomePage extends StatelessWidget { final String title; MyHomePage({Key key, this.title}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(title), ), body: FutureBuilder>( future: fetchPhotos(http.Client()), builder: (context, snapshot) { if (snapshot.hasError) print(snapshot.error); return snapshot.hasData ? PhotosList(photos: snapshot.data) : Center(child: CircularProgressIndicator()); }, ), ); }}class PhotosList extends StatelessWidget { final List photos; PhotosList({Key key, this.photos}) : super(key: key); @override Widget build(BuildContext context) { return GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, ), itemCount: photos.length, itemBuilder: (context, index) { return Image.network(photos[index].thumbnailUrl); }, ); }}