Flutter 在屏幕打开时进行屏幕相关的 API 调用(实时 API 调用)

问题描述 投票:0回答:1

在我的材质应用小部件中,路由子小部件中定义了许多屏幕,例如:

MaterialApp(
   ..........
   home: new Screen0(),
   routes: <String, WidgetBuilder>{
        Screen0.routeName: (BuildContext context) => new Screen0(),
        Screen1.routeName: (BuildContext context) => new Screen1(),
        Screen2.routeName: (BuildContext context) => new Screen2(),
        Screen3.routeName: (BuildContext context) => new Screen3(),
         ......
        ScreenN.routeName: (BuildContext context) => new ScreenN()
   }
}

所有这些屏幕都有很多 API 调用。我的问题是,当应用程序启动时,所有这些屏幕都会同时加载,并且所有 API 调用都会被触发。我希望在应用程序中打开实际屏幕时执行必要的 API 调用。但不知道如何做到这一点,甚至不知道是否可能。

提前欢迎任何建议/信息/教程!

示例如何在屏幕中处理 API 调用。

class Screen1 extends StatefulWidget {
 .............
} 

class Screen1State extends State<Screen1> {
..............
    @override
    void initState() {
        super.initState();
        .......
        checkLoggedIn();
    }

    Future checkLoggedIn() async {
        var prefs = await SharedPreferences.getInstance();
        setState(() {
            KEY = prefs.getString("apiKey");
            USERID = prefs.getString("userId");
        });
        ......
        makeAnAPICall();
    }

    Future makeAnAPICall() async { 
        var response = await http.get(
            Uri.parse("<URI>"),
            headers: {"X-API-KEY" : <KEY>}
        );
        ........
   }

}

添加 Screen0 屏幕如何工作和处理其他屏幕的示例 - 当然还有 MaterialApp 的主页。相关的不是 BottomNavigationBar,而是使用 Drawer 小部件的右侧。

..........
import 'package:Screen1.dart';
import 'package:Screen2.dart';
import 'package:Screen3.dart';
.....
import 'package:ScreenN.dart';


final _scaffoldKey = GlobalKey<ScaffoldState>();
var _KEY;
int? _indexRHSMenu;
String? _currentPage;
late List<OurNavigationDestination> _RHSMenu;


class Screen0 extends StatefulWidget {
    .......

}

class Screen0State extends State<Screen0> {
    Screen0State();
    
    @override
    void initState() {
        checkLoggedIn();
        _RHSMenu = <OurNavigationDestination>[];
        _indexRHSMenu = 0;
        _currentPage = "Screen1";   
    }

    @override
    Widget build(BuildContext context) {
        return new Scaffold(
            ......
            endDrawer: Theme(
                .........
                child: Drawer (
                    child: Container(
                        child: ListView (
                            children: getRHSMenu(),
                        ),                  
                    ),
                ),
            ),
            
           .....
            
            body: SafeArea(
                child: Column(
                    children: <Widget>[
                        ........
                        Expanded(
                            child: IndexedStack(
                                children: _RHSMenu.map((destination) => destination.page).toList(),
                                index: _indexRHSMenu,
                            ),
                        ),
                    ], 
                    .....
                ),
            ),
        );
    } /* build */


 
    Widget getPage(String page){
        switch(page){
            case "screen1" :
                return Screen1();
            case "screen2":
                return Screen2();
            case "screen3": 
                return Screen3();
            
            .....
                
            case "screenN": 
                return ScreenN();
        }
    }
    
    
    
    Widget getIcon(String page, bool active) {
        ......
    }

    void navigateToMenu(String page, screen){
        Navigator.of(context).pop();
        
        setState(() {
            _currentPage = page;
        });   
        
        Navigator.push(context,
            MaterialPageRoute(
                builder: (context) {
                    return screen;
                },
            ),
        );        
    }

    List<Widget> getRHSMenu() {
        List<Widget> rhsMenu = <Widget>[];
        
        if (_RHSMenu.length > 0) {
            for (int i = 0; i < _RHSMenu.length; i++) {
                var menu = _RHSMenu[i];
                rhsMenu.add(Container(
                    child: Row(
                        children: <Widget>[
                            OurTextButtonIcon(
                                onPressed: () => navigateToMenu(menu.name, menu.page),
                                ........
                            ),
                        ],
                    ),
                );
            }
        }
        
        return rhsMenu;
    }
    
    Future checkLoggedIn() async{
        .....
        getNavigationItems();
        .....
    }
    
    Future getNavigationItems() async{
        var response = await http.get(
            Uri.parse("<URI>"),
            headers: {"X-API-_KEY" : <_KEY>}
        );
        
        var responseBody = JsonDecoder().convert(response.body);
        
        setState(() {
            responseBody["_RHSMenu"].forEach((name, title) {
                _RHSMenu.add(
                    OurNavigationDestination(name, getIcon(name, false), getPage(name), getIcon(name, true), title)
                );
            });
        });
    }
} 
flutter routes widget screen
1个回答
0
投票

所有屏幕在应用程序启动时加载的原因是因为您在主屏幕中使用的 IndexedStack 内部工作方式。

IndexedStack 同时构建其所有子级,但仅显示 IndexedStack 的

index
属性所指向的子级。

您可以使用 IndexedStack 示例的修改代码进行测试,以更好地了解 IndexedStack 的工作原理:

import 'package:flutter/material.dart';

/// Flutter code sample for [IndexedStack].

void main() => runApp(const IndexedStackApp());

class IndexedStackApp extends StatelessWidget {
  const IndexedStackApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('IndexedStack Sample')),
        body: const IndexedStackExample(),
      ),
    );
  }
}

class IndexedStackExample extends StatefulWidget {
  const IndexedStackExample({super.key});

  @override
  State<IndexedStackExample> createState() => _IndexedStackExampleState();
}

class _IndexedStackExampleState extends State<IndexedStackExample> {
  List<String> names = <String>['Dash', 'John', 'Mary'];
  int index = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            GestureDetector(
              onTap: () {
                setState(() {
                  if (index == 0) {
                    index = names.length - 1;
                  } else {
                    index -= 1;
                  }
                });
              },
              child: const Icon(Icons.chevron_left, key: Key('gesture1')),
            ),
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                IndexedStack(
                  index: index,
                  children: <Widget>[
                    for (final String name in names) PersonTracker(name: name)
                  ],
                )
              ],
            ),
            GestureDetector(
              onTap: () {
                setState(() {
                  if (index == names.length - 1) {
                    index = 0;
                  } else {
                    index += 1;
                  }
                });
              },
              child: const Icon(Icons.chevron_right, key: Key('gesture2')),
            ),
          ],
        )
      ],
    );
  }
}

class PersonTracker extends StatefulWidget {
  const PersonTracker({super.key, required this.name});
  final String name;
  @override
  State<PersonTracker> createState() => _PersonTrackerState();
}

class _PersonTrackerState extends State<PersonTracker> {
  
  void initState(){
    super.initState();
    ///Watch this being called for every children when the app runs
    print('${widget.name} - init');
  }
  
  @override
  Widget build(BuildContext context) {
    return Container(
      key: Key(widget.name),
      decoration: BoxDecoration(
        color: const Color.fromARGB(255, 239, 248, 255),
        border: Border.all(color: const Color.fromARGB(255, 54, 60, 244)),
        borderRadius: const BorderRadius.all(Radius.circular(10)),
      ),
      padding: const EdgeInsets.all(16.0),
      child: 
          Text('Name: ${widget.name}'),
        
    );
  }
}

您需要避免使用 IndexedStack,因为它总是会同时构建所有子级,从而触发该屏幕中进行的每个 api 调用。您可以使用

setState
来更改屏幕,如本底部导航示例 所示,而不是使用 IndexedStack。

© www.soinside.com 2019 - 2024. All rights reserved.