日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

json阅读器_Flutter小说阅读器系列一:使用Bloc模式获取起点小说关键字提示

發布時間:2025/3/12 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 json阅读器_Flutter小说阅读器系列一:使用Bloc模式获取起点小说关键字提示 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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] 用于接收傳遞過來的字符串
    /// 保存為 suggestion_event.dartabstract class SuggestionEvent {}class SuggestionFetch extends SuggestionEvent {final String query;SuggestionFetch({this.query});@overrideString toString() => '獲取關鍵字提示事件'; }

    實現了SuggestionEvent之后再把SuggestionState實現,思路與代碼如下。

    • SuggestionUninitialized:還未初始化時返回的狀態。
    • SuggestionLoading:表示當前正處于加載中的狀態。
    • SuggestionLoaded:獲取關鍵字成功后返回的狀態。
    • SuggestionError:獲取關鍵字出錯時返回的狀態。
    /// 保存為 suggestion_state.dartabstract class SuggestionState {}class SuggestionError extends SuggestionState {@overrideString toString() => 'SuggestionError:獲取失敗'; }class SuggestionUninitialized extends SuggestionState {@overrideString toString() => 'SuggestionUninitialized:未初始化'; }class SuggestionLoading extends SuggestionState {@overrideString toString() => 'SuggestionLoading :正在加載'; }class SuggestionLoaded extends SuggestionState {final List<String> res;SuggestionLoaded({this.res,});@overrideString toString() => 'SuggestionLoaded:加載完畢'; }

    順帶一提,之所以要重寫toString,僅僅是為了后續能夠看到字符串提示,你也可以不重寫。

    現在已經實現了一個負責事件的SuggestionEvent和一個負責狀態的SuggestionState,接下來就可以實現負責管理事件與狀態的SuggestionBloc了。

    先說下要注意的兩點:

  • initialState:也就是說未接收任何事件時返回的初始狀態,上面寫SuggestionState時已經添加了一個狀態SuggestionUninitialized表示還未初始化,這樣就可以針對不同的狀態改變小部件的布局,比如處于未初始化狀態時可以放一個加載指示器在屏幕上。
  • mapEventToState:只要接收到事件就會觸發,因為寫SuggestionEvent的時候只寫了SuggestionFetch這一個事件,因此只需要針對SuggestionFetch進行處理就行。當觸發SuggestionFetch事件之后返回一個SuggestionLoading狀態表示正在加載中,然后就開始獲取關鍵字提示列表,獲取成功則返回一個包含結果列表的SuggestionLoaded狀態,否則返回一個表示錯誤的SuggestionError狀態。
  • /// 保存為 suggestion_bloc.dartimport 'dart:async'; import 'package:bloc/bloc.dart'; import './suggestion_api.dart'; import './suggestion_event.dart'; import './suggestion_state.dart';class SuggestionBloc extends Bloc<SuggestionEvent, SuggestionState> {@overrideSuggestionState get initialState => SuggestionUninitialized();@overrideStream<SuggestionState> mapEventToState(SuggestionState currentState,SuggestionEvent event,) async* {if (event is SuggestionFetch) {try {yield SuggestionLoading();final res = await api.suggestion(event.query);yield SuggestionLoaded(res: res);} catch (_) {yield SuggestionError();}}} }

    到此,業務邏輯層都已經實現,接下來只需要實現一下界面就可以了。

    // 替換 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.dart

    2019年3月23日 第二篇已更新

    路過的冒險者:Flutter小說閱讀器系列二:使用Bloc模式實現小說搜索的基本功能(略微有點長)?zhuanlan.zhihu.com

    2019年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模式获取起点小说关键字提示的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。