This is the 8th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

Json transfer model

class ChatModel { final String? name; final String? message; final String? imageUrl; ChatModel({this.name, this.message, this.imageUrl}); FromMap (Map Map) {return ChatModel(name: Map ['name'], message: Map ['message'], imageUrl: map['imageUrl'], ); }}Copy the code
final chatMap = { 'name' : 'ChenXi', 'message' : 'Hello! '}; //Map to json final chatJson = json.encode(chatMap); print(chatJson); // Json to Map final newChatMap = json.decode(chatJson); print(chatJson); final chatModel = ChatModel.fromMap(newChatMap as Map); print(chatModel);Copy the code

Here we simply define a map object, code examples are given in json and map to convert each other, and map to model. We define a ChatModel, add the fromMap method, and pass in an object of Map type from the outside. Open source also has some model turning framework, here we first implement ourselves.

The Future use

void initState() { super.initState(); / / access network data _getDatas (). Then (value) ({print (' $value); }); } Future<List<ChatModel>> _getDatas() async {// URL link final URL = Uri.parse('http://rap2api.taobao.org/app/mock/294394/api/chat/list'); // Send the request final response = await http.get(url); If (response.statusCode == 200) {// Get the response data and convert json to Map. Final bodyMap = json.decode(response.body); // Select * from bodyMap; // Select * from bodyMap; ToList final chatList = (bodyMap['chat_list'] as List).map((item) => chatModel.frommap (item)).tolist (); return chatList; } else { throw Exception('statusCode:${response.statusCode}'); }Copy the code

Here Future represents Future data, which needs to be used in conjunction with asynchronous methods. We wrap the data that we return, Future >, with a then method, and then has an external closure attribute passed in, The closure is called when the data request completes, and here we get the value of the value, which is the model array.

FutureBuilder asynchronous rendering

body: Container( child: FutureBuilder( future: _getDatas(), builder: (BuildContext context, If (snapshot.connectionState == connectionstate.waiting) {return Container(child: Text(' Loading! ')); } return ListView(children: snapshot.data.map<Widget>((ChatModel item) {return ListTile(title: Text(item.name as String), subtitle: Container( alignment: Alignment.bottomCenter, height: 25, child: Text(item.message as String, overflow: TextOverflow.ellipsis,), ), leading: Container( width: 44, height: Circular (6.0), image: DecorationImage(image: DecorationImage) NetworkImage(item.imageUrl as String)), ), ), ); }).toList(), ); },))Copy the code

Here we load the network data through the FutureBuilder widget, which supports asynchronous rendering, and the Future property is data of type Future. The Builder method will be called twice every time we enter the wechat page, connectionstate. waiting means that the data is being loaded, here we can do some processing of empty page display. Connectionstate. done indicates that data has been loaded. Snapshot. data is the list data returned by _getDatas. In the ListView, we use the ListTile as the cell. The ListTile contains the main title, subtitle, head leading and other properties. It is very convenient to use.

Network request data processing

List<ChatModel> _datas = []; void initState() { super.initState(); _getDatas(). Then (value) {if (! _cancelConnect) { setState(() { _datas = value; }); } }).catchError((e) { _cancelConnect = true; Print (e); }). WhenComplete (() {print(' data request end '); }).timeout(Duration(seconds: 5)).catchError((timeout) { _cancelConnect = true; Print (' Request timed out! $timeout'); }); }Copy the code

Here we create an external member variable, _datas, to hold the data of the network request. After the network request is successful, we call the setState method and define a property, _cancelConnect, to indicate whether the network request is cancelled. CatchError means that the request fails, whenComplete means that the request ends, and timeout means that the request ends. Here we can use it to display loading pages and error pages.

Container( child: _datas.length == 0 ? Center(child: Text('Loading... ')) : ListView.builder(itemCount: _datas.length ,itemBuilder: (BuildContext context, int index) { return ListTile( title: Text(_datas[index].name as String), subtitle: Container( alignment: Alignment.bottomCenter, height: 25, child: Text(_datas[index].message as String, overflow: TextOverflow.ellipsis,), ), leading: Container( width: 44, height: 44, decoration: BoxDecoration( borderRadius: BorderRadius. Circular (6.0), image: DecorationImage(image: NetworkImage(_datas[index].imageurl as String)),),); }),)Copy the code

For the list display, we switch back to ListView and use FutureBuilder. If there is a large amount of data, the loading problem will be affected.

Page stay state

class _ChatPageState extends State<ChatPage> with AutomaticKeepAliveClientMixin<ChatPage>
Copy the code
Widget build(BuildContext context) {
    super.build(context);
}
Copy the code
class _RootPageState extends State<RootPage> { int _currentIndex = 0; List <Widget>_pages = [ChatPage(), FriendsPage(), DiscoverPage(), MinePage()]; final PageController _controller = PageController(); @override Widget build(BuildContext context) {return Container(Child: Scaffold(body: PageView) NeverScrollableScrollPhysics(), onPageChanged: (int index) { setState(() { _currentIndex = index; }); }, controller: _controller, children: _pages, ),Copy the code

Every time when we switch on the bottom of the tabBar, enter the page will reload, here we adopt AutomaticKeepAliveClientMixin to keep state, let the page will be loaded only once, chat page, for example, _ChatPageState followed by with AutomaticKeepAliveClientMixin < ChatPage >, and in the build method called super. Build (context). In RootPage, we use the _pages array to hold the bottom child pages, the body uses the PageView widget, controller is assigned to the _controller we defined, and children is assigned to _pages.