Search code examples
flutterbloc

"Tried to paint a RenderObject reentrantly." error arise in flutter?


I'm trying to fetch the names of countries from an API and display it in a drop-down box. I'm using the bloc library for state management.

Here's my Code.

select_input_field.dart - Custom wrapper widget for DropdownButtonField

import 'package:flutter/material.dart';

class SelectInputField extends StatelessWidget {
  final String label;
  final List<String> options;
  final TextEditingController controller;
  final EdgeInsets padding;

  const SelectInputField(this.label, this.options,
      { Key? key,
        required this.controller,
        this.padding =
          const EdgeInsets.only(top: 8, bottom: 8, left: 30, right: 30)})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: padding,
      child: DropdownButtonFormField(
        decoration: InputDecoration(
            labelText: label,
            labelStyle: Theme.of(context).textTheme.bodyMedium,
            border: OutlineInputBorder(
              borderSide: BorderSide(
                color: Theme.of(context).primaryColorDark,
                width: 1,
              ),
            ),
            enabledBorder: OutlineInputBorder(
              borderSide: BorderSide(
                color: Theme.of(context).primaryColorDark,
                width: 1,
              ),
            ),
            focusedBorder: OutlineInputBorder(
              borderSide: BorderSide(
                color: Theme.of(context).colorScheme.secondary,
                width: 1,
              ),
            ),
            fillColor: Theme.of(context).primaryColorLight),
        style: Theme.of(context).textTheme.bodyMedium,
        items: options.map((String value) {
          print(value);
          return DropdownMenuItem<String>(
            value: value,
            child: Text(value),
          );
        }).toList(),
        onChanged: (String? value) {
          controller.text = value ?? '';
        },
      ),
    );
  }
}

This is the method I'm using to build it.

  Widget _countriesDropDown(BuildContext context, TextEditingController controller){
    return BlocProvider(
      create: (context) => _signupBloc,
      child: BlocBuilder<SignupBloc,SignupState>(
        buildWhen: ((previous, current) => previous is! Loaded && current is Loaded),
        builder: (context, state){
          if (state is Initial){
            _signupBloc.add(LoadEvent());
          }
          else if (state is Loaded){
              countries = state.countries;
              return SelectInputField("Country", countries, controller: controller);
          }
          return CircularProgressIndicator(color: Theme.of(context).colorScheme.secondary,);

        },
      )

    );
  }

And my bloc class is as follows.

class SignupBloc extends Bloc<SignupEvent, SignupState> {
  static const String countriesUrl = "https://api.first.org/data/v1/countries";

  SignupBloc() : super(Initial()) {

    on<LoadEvent>((event, emit) async{
      emit(Loading());

      List<String> countries = [];

      try{
        final response = await http.get(Uri.parse(countriesUrl));
        if(response.statusCode == 200){
          var responseJson = jsonDecode(response.body);
          responseJson['data'].values.forEach((element) {
           countries.add(element['country']);
          });
          emit(Loaded(countries));
        }
        else{
          emit(Failed("Error in getting data"));
        }
      }
      catch(e){
        print(e);
        emit(Failed("Failed to access internet. Try again later!"));
      }
    });
}

The error appears to look like this. I cannot understand where this error occurs

======== Exception caught by rendering library =====================================================
The following assertion was thrown during paint():
Tried to paint a RenderObject reentrantly.

The following RenderObject was already being painted when it was painted again: RenderPointerListener#c100e relayoutBoundary=up20 NEEDS-PAINT
...  needs compositing
...  parentData: <none> (can use size)
...  constraints: BoxConstraints(0.0<=w<=351.4, 0.0<=h<=Infinity)
...  size: Size(351.4, 64.0)
...  behavior: opaque
...  listeners: down, panZoomStart
Since this typically indicates an infinite recursion, it is disallowed.
The relevant error-causing widget was: 
  DropdownButtonFormField<String> DropdownButtonFormField:file:///D:/Projects/sem5/iblock/lib/widgets/forms/select_input_field.dart:20:14
When the exception was thrown, this was the stack: 
#0      RenderObject._paintWithContext.<anonymous closure> (package:flutter/src/rendering/object.dart:2693:9)
#1      RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2706:6)
#2      PaintingContext.paintChild (package:flutter/src/rendering/object.dart:239:13)
#3      RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
#4      RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2796:7)
#5      PaintingContext.paintChild (package:flutter/src/rendering/object.dart:239:13)
#6      RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
#7      RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2796:7)

I need an explanation about what's wrong with my code and how to fix this.

Output of flutter doctor

[√] Flutter (Channel stable, 3.3.2, on Microsoft Windows [Version 10.0.22621.608], locale en-US)
    • Flutter version 3.3.2 on channel stable at C:\flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision e3c29ec00c (3 weeks ago), 2022-09-14 08:46:55 -0500
    • Engine revision a4ff2c53d8
    • Dart version 2.18.1
    • DevTools version 2.15.0

[√] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at C:\Users\ISHAD\AppData\Local\Android\sdk
    • Platform android-32, build-tools 30.0.3
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)
    • All Android licenses accepted.

[√] Chrome - develop for the web
    • CHROME_EXECUTABLE = C:\Program Files\BraveSoftware\Brave-Browser\Application\brave.exe

[√] Visual Studio - develop for Windows (Visual Studio Build Tools 2019 16.11.18)
    • Visual Studio at C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools
    • Visual Studio Build Tools 2019 version 16.11.32802.440
    • Windows 10 SDK version 10.0.19041.0

[√] Android Studio (version 2021.3)
    • Android Studio at C:\Program Files\Android\Android Studio
    • 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.13+0-b1751.21-8125866)

[√] IntelliJ IDEA Ultimate Edition (version 2022.2)
    • IntelliJ at C:\Program Files\JetBrains\IntelliJ IDEA 2022.1.2
    • Flutter plugin version 70.2.5
    • Dart plugin version 222.4167.21

[√] VS Code (version 1.71.2)
    • VS Code at C:\Users\ISHAD\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.48.0

[√] Connected device (3 available)
    • Windows (desktop) • windows • windows-x64    • Microsoft Windows [Version 10.0.22621.608]
    • Chrome (web)      • chrome  • web-javascript • unknown
    • Edge (web)        • edge    • web-javascript • Microsoft Edge 105.0.1343.53
    ! Device DRGGAM5890805202 is not authorized.
      You might need to check your device for an authorization dialog.

[√] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!

PS: I'm not much familiar with Flutter/ bloc library.


Solution

  • Converting the SelectInputField to a StatefulWidget solved the issue. I think DropdownButtonFormField need to be rendered itself upon activities on it. So, StatelessWidget cannot rerender itself causing this problem.