json阅读器_Flutter小说阅读器系列一:使用Bloc模式获取起点小说关键字提示
最近難得有些閑暇時間,所以我又打算做一個小說閱讀器,以前倒是用RN+Golang寫了一個,不過當時太過放飛自我導致自己看起來都很費力,這次我準備換成Flutter試一下。
先簡單將小說閱讀器分為以下幾個部分:
其中書架和書庫最容易卻也最繁瑣,所以將這兩個放到后面,第一步的話先實現搜索中的關鍵字提示功能。
百度關鍵字提示起點關鍵字提示對于小說關鍵字提示的數據來源,最開始的時候我選擇的是百度,但通過對比后發現起點的關鍵字提示似乎更合適,通過上面的兩張圖片可以明顯的看出來。
一:獲取起點小說關鍵字接口并實現對應的Suggestion類
確定選擇起點,那就只需要把起點的關鍵字提示接口扒出來,起點關鍵字提示接口如下:
鏈接:https://www.qidian.com/ajax/Search/AutoComplete 參數:query 方法:get 示例:https://www.qidian.com/ajax/Search/AutoComplete?query=驚悚示例鏈接返回結果如下(因為JSON太長刪掉了一部分):
{"query": "Unit","suggestions": [{"data": {"category": "書名"},"value": "驚悚樂園"}, {"data": {"category": "書名"},"value": "驚悚樂園:夜鴉"}],"code": 0 }知道起點關鍵字接口的JSON數據格式后,我們就可以針對的寫一個Suggestion類用于解析這串JSON數據,當然我建議直接通過在線轉換工具進行轉換。
/// 保存為 suggestion_model.dartclass Suggestion {String query;List<Suggestions> suggestions;int code;Suggestion({this.query, this.suggestions, this.code});Suggestion.fromJson(Map<String, dynamic> json) {query = json['query'];if (json['suggestions'] != null) {suggestions = new List<Suggestions>();json['suggestions'].forEach((v) {suggestions.add(new Suggestions.fromJson(v));});}code = json['code'];}Map<String, dynamic> toJson() {final Map<String, dynamic> data = new Map<String, dynamic>();data['query'] = this.query;if (this.suggestions != null) {data['suggestions'] = this.suggestions.map((v) => v.toJson()).toList();}data['code'] = this.code;return data;} }class Suggestions {Data data;String value;Suggestions({this.data, this.value});Suggestions.fromJson(Map<String, dynamic> json) {data = json['data'] != null ? new Data.fromJson(json['data']) : null;value = json['value'];}Map<String, dynamic> toJson() {final Map<String, dynamic> data = new Map<String, dynamic>();if (this.data != null) {data['data'] = this.data.toJson();}data['value'] = this.value;return data;} }class Data {String category;Data({this.category});Data.fromJson(Map<String, dynamic> json) {category = json['category'];}Map<String, dynamic> toJson() {final Map<String, dynamic> data = new Map<String, dynamic>();data['category'] = this.category;return data;} }上面的Suggestion模型用于解析獲取到的JSON數據,接下來我們只需要實現一個用于發起請求獲取數據的函數就行了,這里用到了官方的http庫:dart-lang/http
/// 保存為 suggestion_api.dartimport 'dart:async'; import 'dart:convert'; import 'package:http/http.dart' as http;import './suggestion_model.dart';class Api {/// 關鍵字提示(起點)Future<List<String>> suggestion(String query) async {http.Response response = await http.get("https://www.qidian.com/ajax/Search/AutoComplete?siteid=1&query=$query");var data = Suggestion.fromJson(json.decode(response.body));List<String> suggestion = [];data.suggestions.forEach((k) {suggestion.add(k.value);});return suggestion;} }Api api = Api();為了演示方便所以只有一個簡單的異步函數,獲取到結果后返回一個包含了與關鍵字相關的小說列表。
正常情況下應該要將這一類的請求封裝好,并與業務邏輯層分離開來。
對于一些會消耗大量資源可能會造成主線程卡頓的數據請求,比如緩存大量章節時就不要簡單的使用異步了,這時應該要用isolate對數據進行處理。
二:使用Bloc模式實現業務邏輯
關于Flutter上的狀態管理我就不多說了,各種各樣的包都有,這里我使用的是所有Bloc包中star最多的包:felangel/bloc
選擇好bloc包之后,現在可以開始實現業務邏輯中的event與state,因為只需要實現關鍵詞提示,所以其中的事件暫時只需要一個就行。
首先要實現的是SuggestionEvent,思路與代碼如下。
- SuggestionFetch:獲取關鍵字提示的事件,其中參數 [query] 用于接收傳遞過來的字符串
實現了SuggestionEvent之后再把SuggestionState實現,思路與代碼如下。
- SuggestionUninitialized:還未初始化時返回的狀態。
- SuggestionLoading:表示當前正處于加載中的狀態。
- SuggestionLoaded:獲取關鍵字成功后返回的狀態。
- SuggestionError:獲取關鍵字出錯時返回的狀態。
順帶一提,之所以要重寫toString,僅僅是為了后續能夠看到字符串提示,你也可以不重寫。
現在已經實現了一個負責事件的SuggestionEvent和一個負責狀態的SuggestionState,接下來就可以實現負責管理事件與狀態的SuggestionBloc了。
先說下要注意的兩點:
到此,業務邏輯層都已經實現,接下來只需要實現一下界面就可以了。
// 替換 main.dartimport 'package:flutter/material.dart'; import 'package:bloc/bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import './suggestion_bloc.dart'; import './suggestion_event.dart'; import './suggestion_state.dart';void main() {runApp(App()); }class App extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(title: '關鍵字提示',home: Scaffold(appBar: AppBar(title: Text('關鍵字提示'),),body: AppHome(),),);} }class AppHome extends StatefulWidget {@override_AppHomeState createState() => _AppHomeState(); }class _AppHomeState extends State<AppHome> {final SuggestionBloc _suggestion = SuggestionBloc();@overrideWidget build(BuildContext context) {return Material(child: Column(children: [TextField(autofocus: true,textAlign: TextAlign.center,onSubmitted: (text) {_suggestion.dispatch(SuggestionFetch(query: text));},),Expanded(child: BlocBuilder(bloc: _suggestion,builder: (BuildContext context, SuggestionState state) {if (state is SuggestionUninitialized) {return Center(child: Text('暫無內容'),);} else if (state is SuggestionLoading) {return Center(child: CircularProgressIndicator(),);} else if (state is SuggestionError) {return Center(child: Text('出現錯誤'),);} else if (state is SuggestionLoaded) {return ListView.builder(itemBuilder: (BuildContext context, int index) {return ListTile(title: Text(state.res[index]));},itemCount: state.res.length,);}},),),],),);}@overridevoid dispose() {_suggestion.dispose();super.dispose();} }界面很簡單,就是一個文本輸入框加上一個用于展示的列表,下面是效果圖
Bloc模式下的小說關鍵字提示效果圖上面的效果只是用于演示,搭配官方的搜索頁面效果更好,只是懶得去弄了,后續的抽時間在寫。
順帶一提,上面的目錄結構只是為了演示,實際使用bloc模式的過程中最好規劃好文件層次,比如使用如下目錄結構:
libmain.dartblocs/suggestion/suggestion_bloc.dart2019年3月23日 第二篇已更新
路過的冒險者:Flutter小說閱讀器系列二:使用Bloc模式實現小說搜索的基本功能(略微有點長)?zhuanlan.zhihu.com2019年4月6日 添加
我寫文章的時候bloc版本還是0.10.0,這個版本的mapEventToState是有兩個參數的,目前從bloc0.11.0開始只有一個參數了,因此只需要傳入事件就行。
Stream<S> mapEventToState(S currentState, E event) -> Stream<S> mapEventToState(E event)
總結
以上是生活随笔為你收集整理的json阅读器_Flutter小说阅读器系列一:使用Bloc模式获取起点小说关键字提示的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: go 字符串替换_Go语言爱好者周刊:第
- 下一篇: html编译圣诞情缘,H5+JS+CSS