老师,请教个问题initState方法重复调用的问题

来源:6-4 轮播图Banner组件封装

Kevin_Choi

2021-05-06

老师,请教个问题:
点击HomeTabPage页面的 banner 进入 VideoDetailPage页面,为什么都会调用 BottomNavigator 的 initState 方法,我认为不应该重新创建的?
图片描述

在VideoDetailPage页面点击 左上角 返回icon,为什么会调用 HomePage 的 initState 方法?应该已经创建过了,不应该重新创建了图片描述

import 'package:flutter/material.dart';
import 'package:vione_bll/navigator/hi_navigator.dart';
import 'package:vione_bll/page/index/favorite_page.dart';
import 'package:vione_bll/page/index/home_page.dart';
import 'package:vione_bll/page/index/profile_page.dart';
import 'package:vione_bll/page/index/ranking_page.dart';
import 'package:vione_bll/utils/color.dart';

class BottomNavigator extends StatefulWidget {
  @override
  _BottomNavigatorState createState() => _BottomNavigatorState();
}

class _BottomNavigatorState extends State<BottomNavigator>
    with AutomaticKeepAliveClientMixin {
  final Color _defaultColor = Colors.grey;
  final Color _activeColor = primary;
  int _current = 0;
  final PageController _controller = PageController(initialPage: 0);
  List<Widget> _pages;
  bool _hasBuild = false;

  @override
  void initState() {
    super.initState();
    print("---_BottomNavigatorState---initState");
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    _pages = [HomePage(), RankingPage(), FavoritePage(), ProfilePage()];
    if (!_hasBuild) {
      HiNavigator.getInstance().onBottomTagChange(_current, _pages[_current]);
      _hasBuild = true;
    }
    return Scaffold(
      body: PageView(
        controller: _controller,
        children: _pages,
        onPageChanged: (index) {
          HiNavigator.getInstance().onBottomTagChange(index, _pages[index]);
          this.setState(() {
            this._current = index;
          });
        },
        physics: NeverScrollableScrollPhysics(),
      ),
      bottomNavigationBar: BottomNavigationBar(
        onTap: (index) {
          _controller.jumpToPage(index); //回调用PageView的onPageChanged方法
          // HiNavigator.getInstance().onJumpTo(RouteStatus.detail, args: {"videoMo": VideoMo(vid: "112")});
        },
        type: BottomNavigationBarType.fixed,
        items: [
          _bottomItem('首页', Icons.home, 0),
          _bottomItem('排行', Icons.local_fire_department, 1),
          _bottomItem('收藏', Icons.favorite, 2),
          _bottomItem('我的', Icons.live_tv, 3)
        ],
        currentIndex: _current,
        unselectedItemColor: _defaultColor,
        selectedItemColor: _activeColor,
      ),
    );
  }

  _bottomItem(String title, IconData iconData, int index) {
    return BottomNavigationBarItem(
        icon: Icon(
          iconData,
          color: _defaultColor,
        ),
        activeIcon: Icon(
          iconData,
          color: _activeColor,
        ),
        label: title);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  bool get wantKeepAlive => true;
}

import 'package:flutter/material.dart';
import 'package:vione_bll/core/hi_state.dart';
import 'package:vione_bll/dao/home_dao.dart';
import 'package:vione_bll/http/core/hi_error.dart';
import 'package:vione_bll/modle/home_mo.dart';
import 'package:vione_bll/navigator/hi_navigator.dart';
import 'package:vione_bll/page/index/home_tab_page.dart';
import 'package:vione_bll/utils/color.dart';
import 'package:vione_bll/utils/toast.dart';

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends HiState<HomePage>
    with AutomaticKeepAliveClientMixin, TickerProviderStateMixin {
  RouteChangeListener _listener;
  TabController _controller;
  List<BannerMo> bannerList = [];
  List<CategoryMo> categoryList = [];
  @override
  void initState() {
    print("---_HomePageState -initState-----");
    super.initState();
    _controller = TabController(length: categoryList.length, vsync: this);
    // HiNavigator.getInstance().addListener(this._listener = (current, pre) {
    //   print('home:current:${current.page}');
    //   print('home:pre:${pre.page}');
    //   if (widget == current.page || current.page is HomePage) {
    //     print('打开了首页:onResume');
    //   } else if (widget == pre?.page || pre?.page is HomePage) {
    //     print('首页:onPause');
    //   }
    // });
    loadData();
  }

  @override
  void dispose() {
    HiNavigator.getInstance().removeListener(_listener);
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scaffold(
      body: Column(
        children: [
          Container(
            color: Colors.white,
            padding: EdgeInsets.only(top: 30),
            child: _tabBar(),
          ),
          Flexible(
            child: TabBarView(
                controller: _controller,
                children: categoryList.map((tab) {
                  return HomeTabPage(
                    name: tab.name,
                    bannerList: tab.name == '推荐' ? bannerList : null,
                  );
                }).toList()),
          ),
        ],
      ),
    );
  }

  @override
  bool get wantKeepAlive => true;

  _tabBar() {
    return TabBar(
        controller: _controller,
        isScrollable: true,
        labelColor: Colors.black,
        indicator: UnderlineTabIndicator(
          borderSide: BorderSide(color: primary, width: 3),
          insets: EdgeInsets.only(left: 20, right: 20),
        ),
        tabs: categoryList.map<Tab>(
          (tab) {
            return Tab(
              child: Padding(
                padding: EdgeInsets.only(left: 5, right: 5),
                child: Text(
                  tab.name,
                  style: TextStyle(fontSize: 16, color: Colors.black),
                ),
              ),
            );
          },
        ).toList());
  }

  void loadData() async {
    try {
      HomeMo ret = await HomeDao.get('推荐');
      if (ret.categoryList != null) {
        _controller =
            TabController(length: ret.categoryList.length, vsync: this);
      }
      this.setState(() {
        categoryList = ret.categoryList;
        bannerList = ret.bannerList;
      });
    } on NeedAuth catch (e) {
      showWarnToast(e.message);
    } on HiNetError catch (e) {
      showWarnToast(e.message);
    }
  }
}

import 'package:flutter/material.dart';
import 'package:vione_bll/modle/home_mo.dart';
import 'package:vione_bll/widget/hi_banner.dart';

class HomeTabPage extends StatefulWidget {
  final String name;
  final List<BannerMo> bannerList;

  const HomeTabPage({Key key, this.name, this.bannerList}) : super(key: key);

  @override
  _HomeTabPageState createState() => _HomeTabPageState();
}

class _HomeTabPageState extends State<HomeTabPage>
    with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Container(
      child: ListView(
        children: [
          if (widget.bannerList != null) _banner(),
        ],
      ),
    );
  }

  _banner() {
    return Padding(
      padding: EdgeInsets.only(left: 8, right: 8),
      child: HiBanner(widget.bannerList),
    );
  }

  @override
  bool get wantKeepAlive => true;
}

import 'package:flutter/material.dart';
import 'package:vione_bll/modle/home_mo.dart';

class VideoDetailPage extends StatefulWidget {
  final Map args;

  const VideoDetailPage({
    Key key,
    this.args,
  }) : super(key: key);

  @override
  _VideoDetailPageState createState() => _VideoDetailPageState();
}

class _VideoDetailPageState extends State<VideoDetailPage> {
  @override
  void initState() {
    super.initState();
    print("---_VideoDetailPageState -- initState");
  }

  @override
  Widget build(BuildContext context) {
    VideoMo videoMo = widget.args['videoMo'];
    return Scaffold(
      appBar: AppBar(),
      body: Container(
        child: Text("视频详情页: vid: ${videoMo.vid}"),
      ),
    );
  }
}

import 'package:flutter/material.dart';
import 'package:vione_bll/dao/login_dao.dart';
import 'package:vione_bll/db/hi_cache.dart';
import 'package:vione_bll/navigator/bottom_navigator.dart';
import 'package:vione_bll/navigator/hi_navigator.dart';
import 'package:vione_bll/page/launcher/login_page.dart';
import 'package:vione_bll/page/launcher/registration_page.dart';
import 'package:vione_bll/page/video_detail_page.dart';
import 'package:vione_bll/utils/color.dart';
import 'package:vione_bll/utils/toast.dart';

void main() {
  runApp(BiliApp());
}

class BiliApp extends StatefulWidget {
  @override
  _BiliAppState createState() => _BiliAppState();
}

class _BiliAppState extends State<BiliApp> {
  BiliRouterDelegate _routerDelegate = BiliRouterDelegate();

  @override
  Widget build(BuildContext context) {
    print("BiliApp -- build");

    return FutureBuilder<HiCache>(
      //进行初始化
      future: HiCache.preInit(),
      builder: (BuildContext context, AsyncSnapshot<HiCache> snapshot) {
        //定义路由
        var widget = snapshot.connectionState == ConnectionState.done
            ? Router(
                routerDelegate: _routerDelegate,
              )
            : Scaffold(
                body: Center(
                  child: CircularProgressIndicator(),
                ),
              );
        return MaterialApp(
          home: widget,
          theme: ThemeData(
            primarySwatch: white,
          ),
        );
      },
    );
  }
}

class BiliRouterDelegate extends RouterDelegate<BiliRoutePath>
    with ChangeNotifier, PopNavigatorRouterDelegateMixin<BiliRoutePath> {
  //为Navigator设置一个key,必要的时候可以通过navigatorKey.currentState来获取到NavigatorState对象
  @override
  GlobalKey<NavigatorState> get navigatorKey => GlobalKey();

  BiliRouterDelegate() {
    HiNavigator.getInstance().registerRouteJump(
        RouteJumpListener((RouteStatus routeStatus, {Map args}) {
      _routeStatus = routeStatus;
      this.args = args;
      notifyListeners();
    }));
  }

  List<MaterialPage> pages = [];
  RouteStatus _routeStatus = RouteStatus.home;
  Map args;

  RouteStatus get routeStatus {
    if (_routeStatus != RouteStatus.registration && !hasLogin) {
      _routeStatus = RouteStatus.login;
    }
    return _routeStatus;
  }

  bool get hasLogin => LoginDao.getBoardingPass() != null;

  @override
  Widget build(BuildContext context) {
    print("BiliRouterDelegate -- build");
    int index = getPageIndex(pages, routeStatus);
    List<MaterialPage> tempPages = pages;
    if (index != -1) {
      ///要打开的页面在栈中已存在,则将该页面和它上面的所有页面都出栈
      ///tips 具体规则可以根据需要进行调整,这里要求栈中只允许有一个同样的页面的实例
      tempPages = tempPages.sublist(0, index);
    }
    var page;
    if (routeStatus == RouteStatus.home) {
      //跳转首页时,将栈中其它页面进行出栈,因为首页不可回退
      pages.clear();
      page = pageWrap(
        BottomNavigator(),
      );
    } else if (routeStatus == RouteStatus.detail) {
      page = pageWrap(VideoDetailPage(args: args));
    } else if (routeStatus == RouteStatus.registration) {
      page = pageWrap(RegistrationPage());
    } else if (routeStatus == RouteStatus.login) {
      page = pageWrap(LoginPage());
    }
    //重建一个数组,否则pages因引用没有改变路由不会生效
    tempPages = [...tempPages, page];
    //通知路由信息变化
    HiNavigator.getInstance().notify(tempPages, pages);
    pages = tempPages;
    return WillPopScope(
      child: Navigator(
        key: navigatorKey,
        pages: pages,
        onPopPage: (route, result) {
          if (route.settings is MaterialPage) {
            //登录页未登录,返回拦截
            if ((route.settings as MaterialPage).child is LoginPage) {
              if (!hasLogin) {
                showWarnToast("请先登录");
                return false;
              }
            }
          }
          //执行返回操作
          if (!route.didPop(result)) {
            return false;
          }
          var tempPages = [...pages];
          //进行出栈
          pages.removeLast();
          //通知路由信息变化
          HiNavigator.getInstance().notify(pages, tempPages);
          return true;
        },
      ),
      onWillPop: () async => !await navigatorKey.currentState.maybePop(),
    );
  }

  @override
  void addListener(listener) {
    print("BiliRouterDelegate -- addListener");
    super.addListener(listener);
  }

  @override
  Future<bool> popRoute() {
    print("BiliRouterDelegate -- popRoute");
    return super.popRoute();
  }

  @override
  void dispose() {
    print("BiliRouterDelegate -- dispose");
    super.dispose();
  }

  @override
  Future<void> setNewRoutePath(BiliRoutePath configuration) async {
    print("BiliRouterDelegate -- setNewRoutePath");
  }
}

class BiliRoutePath {
  final String location;
  BiliRoutePath.home() : location = "/";
  BiliRoutePath.detail() : location = "/detail";
}

写回答

1回答

CrazyCodeBoy

2021-05-07

运行了课程源码看了下没发现有多次调用initState的情况,有没有对照下这块课程源码检查下你的代码实现看是否有出入的地方呢

0
0

Flutter高级进阶实战-仿哔哩哔哩-掌握Flutter高阶技能

一次性掌握Flutter高阶技能+商业级复杂项目架构设计与开发方案

1723 学习 · 870 问题

查看课程