Skip to content

TabBarView crashes when switching index before layout #86222

Closed

Description

@tomgilder

TabBarView crashes if you try to switch index before it's been laid out.

Steps to Reproduce

  1. Create a TabBarView with a TabController
  2. Try to switch tabs programatically using the controller - but before the TabBarView has been laid out

Tested on stable 2.2.3 and dev 2.4.0-0.0.pre.

Repro

Run this repro and click the button.

The reason the TabBarView hasn't been laid out is due to using Navigator 2.0 - imagine that this state has been restored on startup, with two pages already in the stack.

import 'package:flutter/material.dart';

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

// This allows switching tabs from anywhere
class NavigationManager extends ChangeNotifier {
  int _index = 0;
  int get index => _index;
  set index(int newIndex) {
    _index = newIndex;
    notifyListeners();
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: HomePage());
  }
}

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

class _HomePageState extends State<HomePage> {
  final _navManager = NavigationManager();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Navigator(
        onPopPage: (route, result) {
          return route.didPop(result);
        },
        pages: [
          MaterialPage(child: TabPage(navManager: _navManager)),
          MaterialPage(child: SubPage(navManager: _navManager)),
        ],
      ),
    );
  }
}

class TabPage extends StatefulWidget {
  final NavigationManager navManager;

  TabPage({required this.navManager});

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

class _TabPageState extends State<TabPage> with SingleTickerProviderStateMixin {
  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 2, vsync: this);

    widget.navManager.addListener(() {
      // Global navigation has updated, change controller

      // This is where the crash occurs, because the TabBarView has not
      // yet been laid out
      _tabController.index = widget.navManager.index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: TabBarView(
        controller: _tabController,
        children: [
          Scaffold(body: Text('One')),
          Scaffold(body: Text('Two')),
        ],
      ),
    );
  }
}

class SubPage extends StatelessWidget {
  final NavigationManager navManager;

  SubPage({required this.navManager});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            // Switch the tab
            navManager.index = 1;
          },
          child: Text('Change tab'),
        ),
      ),
    );
  }
}

Expected results: On eventually showing the TabBarView, the index is correct.

Actual results: Crashes due to viewportDimension being null.

Logs
[   +1 ms] An Observatory debugger and profiler on macOS is available at: http://127.0.0.1:51581/6xepRBr4z90=/
[ +110 ms] Activating Dart DevTools...
[+1585 ms] [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: Null check operator used on a null value
[        ] #0      ScrollPosition.viewportDimension (package:flutter/src/widgets/scroll_position.dart:172:53)
[        ] #1      _PagePosition.getPixelsFromPage (package:flutter/src/widgets/page_view.dart:382:19)
[        ] #2      PageController.animateToPage (package:flutter/src/widgets/page_view.dart:197:16)
[        ] #3      _TabBarViewState._warpToCurrentIndex (package:flutter/src/material/tabs.dart:1417:29)
[        ] #4      _TabBarViewState._handleTabControllerAnimationTick (package:flutter/src/material/tabs.dart:1403:7)
[        ] #5      AnimationLocalListenersMixin.notifyListeners (package:flutter/src/animation/listener_helpers.dart:136:19)
[        ] #6      AnimationController.value= (package:flutter/src/animation/animation_controller.dart:366:5)
[        ] #7      TabController._changeIndex (package:flutter/src/material/tab_controller.dart:232:29)
[        ] #8      TabController.index= (package:flutter/src/material/tab_controller.dart:250:5)
[        ] #9      _TabPageState.initState.<anonymous closure> (package:tab_crash/main.dart:70:22)
[        ] #10     ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:243:25)
[        ] #11     NavigationManager.index= (package:tab_crash/main.dart:13:5)
[        ] #12     SubPage.build.<anonymous closure> (package:tab_crash/main.dart:101:24)
[        ] #13     _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:989:21)
[        ] #14     GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
[        ] #15     TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:607:11)
[        ] #16     BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:296:5)
[        ] #17     BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:230:7)
[        ] #18     PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:475:9)
[        ] #19     PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:93:12)
[        ] #20     PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:138:9)
[        ] #21     _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:397:8)
[        ] #22     PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:136:18)
[        ] #23     PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:122:7)
[        ] #24     GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:439:19)
[        ] #25     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:419:22)
[        ] #26     RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:287:11)
[        ] #27     GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:374:7)
[        ] #28     GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:338:5)
[        ] #29     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:296:7)
[        ] #30     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:279:7)
[        ] #31     _rootRunUnary (dart:async/zone.dart:1370:13)
[        ] #32     _CustomZone.runUnary (dart:async/zone.dart:1265:19)
[        ] #33     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1170:7)
[        ] #34     _invoke1 (dart:ui/hooks.dart:182:10)
[        ] #35     PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:282:7)
[        ] #36     _dispatchPointerDataPacket (dart:ui/hooks.dart:96:31)
[+3413 ms] Activating Dart DevTools... (completed in 5.0s)
[ +562 ms] The Flutter DevTools debugger and profiler on macOS is available at: http://127.0.0.1:9104?uri=http%3A%2F%2F127.0.0.1%3A51581%2F6xepRBr4z90%3D%2F
No issues found! (ran in 1.6s)
[✓] Flutter (Channel stable, 2.2.3, on macOS 11.4 20F71 darwin-x64, locale en-FI)
    • Flutter version 2.2.3 at /Users/tom/fvm/versions/stable
    • Framework revision f4abaa0735 (9 days ago), 2021-07-01 12:46:11 -0700
    • Engine revision 241c87ad80
    • Dart version 2.13.4

[!] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
    • Android SDK at /Users/tom/Library/Android/sdk
    • Platform android-30, build-tools 30.0.2
    • ANDROID_HOME = /Users/tom/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.

[✓] Xcode - develop for iOS and macOS
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 12.5.1, Build version 12E507
    • CocoaPods version 1.10.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)

[✓] VS Code (version 1.58.0)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.24.0

[✓] Connected device (2 available)
    • macOS (desktop) • macos  • darwin-x64     • macOS 11.4 20F71 darwin-x64
    • Chrome (web)    • chrome • web-javascript • Google Chrome 91.0.4472.114

! Doctor found issues in 1 category.

Activity

  1. darshankawar commented on Jul 12, 2021

    @darshankawar
    Member

    Verified this on latest stable and I see the same behavior.

    console error log
    
    Launching lib/main.dart on iPhone 12 Pro Max in debug mode...
    Running Xcode build...
    Xcode build done.                                           22.1s
    Debug service listening on ws://127.0.0.1:52520/WIFdGTn-ZPo=/ws
    Syncing files to device iPhone 12 Pro Max...
    [VERBOSE-2:ui_dart_state.cc(199)] Unhandled Exception: Null check operator used on a null value
    #0      ScrollPosition.viewportDimension (package:flutter/src/widgets/scroll_position.dart:172:53)
    #1      _PagePosition.getPixelsFromPage (package:flutter/src/widgets/page_view.dart:382:19)
    #2      PageController.animateToPage (package:flutter/src/widgets/page_view.dart:197:16)
    #3      _TabBarViewState._warpToCurrentIndex (package:flutter/src/material/tabs.dart:1417:29)
    #4      _TabBarViewState._handleTabControllerAnimationTick (package:flutter/src/material/tabs.dart:1403:7)
    #5      AnimationLocalListenersMixin.notifyListeners (package:flutter/src/animation/listener_helpers.dart:136:19)
    #6      AnimationController.value= (package:flutter/src/animation/animation_controller.dart:366:5)
    #7      TabController._changeIndex (package:flutter/src/material/tab_controller.dart:232:29)
    #8      TabController.index= (package:flutter/src/material/tab_controller.dart:250:5)
    #9      _TabPageState.initState.<anonymous clo<…>
    
    
    
    
    
    flutter doctor -v
    [✓] Flutter (Channel stable, 2.2.3, on Mac OS X 10.15.4 19E2269 darwin-x64,
        locale en-GB)
        • Flutter version 2.2.3 at /Users/dhs/documents/fluttersdk/flutter
        • Framework revision f4abaa0735 (4 days ago), 2021-07-01 12:46:11 -0700
        • Engine revision 241c87ad80
        • Dart version 2.13.4
    
    [✓] Xcode - develop for iOS and macOS
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • Xcode 12.3, Build version 12C33
        • CocoaPods version 1.10.1
    
    [✓] Chrome - develop for the web
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [✓] VS Code (version 1.57.1)
        • VS Code at /Applications/Visual Studio Code.app/Contents
        • Flutter extension version 3.21.0
    
    [✓] Connected device (4 available)
        • SM G975F (mobile) • RZ8M802WY0X • android-arm64 • Android 10 (API 29)
        • iPhone 12 Pro Max (mobile) • A5473606-0213-4FD8-BA16-553433949729 • ios
          • com.apple.CoreSimulator.SimRuntime.iOS-14-3 (simulator)
        • macOS (desktop)            • macos                                •
          darwin-x64     • Mac OS X 10.15.4 19E2269 darwin-x64
        • Chrome (web)               • chrome                               •
          web-javascript • Google Chrome 91.0.4472.114
    
    • No issues found!
    
    
    
    
    
    
  2. added
    p: material_uimaterial_ui package in flutter/packages
    f: routesNavigator, Router, and related APIs.
    frameworkflutter/packages/flutter repository. See also f: labels.
    c: crashStack traces logged to the console
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    and removed
    in triagePresently being triaged by the triage team
    on Jul 12, 2021
  3. victor-tinoco commented on Aug 10, 2023

    @victor-tinoco

    @darshankawar wasn't it addressed by this fix?

  4. pschaffl commented on Jan 3, 2024

    @pschaffl

    Possible regression error (stable 3.16.5, web).

    Error log
    Error: Unexpected null value.
    ../dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 294:3       throw_
    ../dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 943:18  nullCheck
    ../packages/flutter/src/widgets/scroll_position.dart 260:53                          get viewportDimension
    ../packages/flutter/src/widgets/page_view.dart 379:19                                getPixelsFromPage
    ../packages/flutter/src/widgets/page_view.dart 196:15                                animateToPage
    ../packages/flutter/src/material/tabs.dart 1839:11                                   _animateToPage
    ../dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54                runBody
    ../dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 127:5                _async
    ../packages/flutter/src/material/tabs.dart 1833:30                                   [_animateToPage]
    ../packages/flutter/src/material/tabs.dart 1927:13                                   _warpToAdjacentTab
    ../dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54                runBody
    ../dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 127:5                _async
    ../packages/flutter/src/material/tabs.dart 1923:34                                   [_warpToAdjacentTab]
    ../packages/flutter/src/material/tabs.dart 1917:7                                    [_warpToCurrentIndex]
    ../packages/flutter/src/material/tabs.dart 1906:7                                    [_handleTabControllerAnimationTick]
    ../packages/flutter/src/animation/listener_helpers.dart 161:11                       notifyListeners
    ../packages/flutter/src/animation/animation_controller.dart 363:5                    set value
    ../packages/flutter/src/material/tab_controller.dart 210:7                           [_changeIndex]
    ../packages/flutter/src/material/tab_controller.dart 228:5                           set index
    

    Workaround

  5. self-assigned this
    on Aug 5, 2024
  6. added
    r: fixedIssue is closed as already fixed in a newer version
    on Aug 7, 2024
  7. github-actions commented on Aug 21, 2024

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  8. locked as resolved and limited conversation to collaborators on Aug 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

c: crashStack traces logged to the consolef: routesNavigator, Router, and related APIs.found in release: 2.2Found to occur in 2.2frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: material_uimaterial_ui package in flutter/packagesr: fixedIssue is closed as already fixed in a newer versionteam-designOwned by Design Languages teamtriaged-designTriaged by Design Languages team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions