Flutter报错:type '_Type' is not a subtype of type 'BuildContext'求解
Flutter中添加TasksCubit后触发type '_Type' is not a subtype of type 'BuildContext'错误的解决方法
错误概述
添加TasksCubit类后,运行Flutter项目触发类型错误:type '_Type' is not a subtype of type 'BuildContext',无法定位错误触发点,以下是问题分析与解决步骤。
错误堆栈
═══════ Exception caught by widgets library ═══════════════════════════════════ The following _TypeError was thrown building MyApp(dirty): type '_Type' is not a subtype of type 'BuildContext' The relevant error-causing widget was MyApp package:my_first_app/main.dart:15 When the exception was thrown, this was the stack #0 TasksCubit.get package:my_first_app/…/mycubitclasses/taskscubit_class.dart:14 #1 new HomeLayout package:my_first_app/layout/homelayout.dart:29 #2 MyApp.build package:my_first_app/main.dart:24 #3 StatelessElement.build package:flutter/…/widgets/framework.dart:4876 #4 ComponentElement.performRebuild package:flutter/…/widgets/framework.dart:4806 #5 Element.rebuild package:flutter/…/widgets/framework.dart:4529 #6 ComponentElement._firstBuild package:flutter/…/widgets/framework.dart:4787 #7 ComponentElement.mount package:flutter/…/widgets/framework.dart:4781 #8 Element.inflateWidget package:flutter/…/widgets/framework.dart:3817 #9 Element.updateChild package:flutter/…/widgets/framework.dart:3551 #10 RenderObjectToWidgetElement._rebuild package:flutter/…/widgets/binding.dart:1202 #11 RenderObjectToWidgetElement.mount package:flutter/…/widgets/binding.dart:1171 #12 RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> package:flutter/…/widgets/binding.dart:1119 #13 BuildOwner.buildScope package:flutter/…/widgets/framework.dart:2597 #14 RenderObjectToWidgetAdapter.attachToRenderTree package:flutter/…/widgets/binding.dart:1118 #15 WidgetsBinding.attachRootWidget package:flutter/…/widgets/binding.dart:953 #16 WidgetsBinding.scheduleAttachRootWidget.<anonymous closure>
相关代码
main.dart
import 'package:bloc/bloc.dart'; import 'package:flutter/material.dart'; import 'package:my_first_app/layout/homelayout.dart'; import 'package:my_first_app/moduls/login/login.dart'; import 'package:my_first_app/moduls/messanger/messangerscreen.dart'; import 'package:my_first_app/moduls/counter/counter_screen.dart'; import 'package:my_first_app/moduls/messanger/mydesign.dart'; import 'moduls/homescreen/HomeScreen.dart'; import 'moduls/counter/counter_screen.dart'; import 'moduls/bmiscreen/ibm_calculator.dart'; import 'shared/bloc_observ.dart'; void main() { // Bloc.observer = MyBlocObserver(); return runApp(MyApp()); } //========================================================= class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false , home: HomeLayout(), ); } }
HomeLayout页面代码
// ignore_for_file: prefer_const_constructors import 'dart:ffi'; import 'package:conditional_builder_null_safety/conditional_builder_null_safety.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; import 'package:my_first_app/moduls/archive_task_screen/archive_task.dart'; import 'package:my_first_app/moduls/done_task_screen/done_task.dart'; import 'package:my_first_app/moduls/new_task_screen/new_task.dart'; import 'dart:async'; import 'package:flutter/widgets.dart'; import 'package:my_first_app/shared/componants/componants.dart'; import 'package:my_first_app/shared/mycubitclasses/taskscubit_class.dart'; import 'package:my_first_app/shared/mycubitclasses/taskstates.dart'; import 'package:path/path.dart'; import 'package:sqflite/sqflite.dart'; import '../shared/componants/constants.dart'; class HomeLayout extends StatelessWidget { //======================variables=============================== var scaffoldkey = GlobalKey<ScaffoldState>(); var formkey = GlobalKey<FormState>(); var titleController = TextEditingController(); var timeController = TextEditingController(); var dateController = TextEditingController(); TasksCubit cubitt = TasksCubit.get(context); // scaffold contain in this screen : // 1. appBar 2. FAB floatingActionButton 3. body 4. bottomNavigationBar //================================================================= //================================================================= @override Widget build(BuildContext context) { return BlocProvider ( create: (context) { return TasksCubit()..creatDataBase(); }, child: Scaffold( key: scaffoldkey, //========================app bar ================================= appBar: AppBar( title: Text( cubitt.titls[cubitt.currentindex], ), ), //===========================body ====================================== body: BlocBuilder<TasksCubit,TasksStates>( builder: (BuildContext context, TasksStates state) { if (state is InsertDataBase) { Navigator.pop(context); } return cubitt.screens[cubitt.currentindex]; }), //===========================FAB====================================== floatingActionButton: FloatingActionButton( onPressed: () { if (cubitt. isBottomSheetShown) { cubitt.InserttTODataBase( titel: titleController.text, date: dateController.text, time: timeController.text, status: 'new', ).then((value) { print( '*************************** Insert succesfully **************************'); cubitt.ChangeBottomState(false,Icons.edit); }); } else // if bottomsheet closed { scaffoldkey.currentState!.showBottomSheet( (context) => Container( padding: EdgeInsets.all(20.0), color: Colors.grey[200], child: Column( mainAxisSize: MainAxisSize.min, children: [ DefoultFormField( controller: titleController, label: 'input title', prefix: Icons.title, type: TextInputType.text, validate: ((String value) {}), // validate: (String? value){ // if(value!.isEmpty) // { // return' must title not empty '; // } // return null ; // }, ), SizedBox( height: 5.0, ), ////////////////////////////////////////////////////////////////////// DefoultFormField( controller: timeController, label: 'input time', prefix: Icons.watch, type: TextInputType.datetime, validate: ((String value) {}), // validate: (String? value){ // if(value!.isEmpty) // { // return' must time not empty '; // } // // return null ; // }, ontap: () { showTimePicker( context: context, initialTime: TimeOfDay.now(), ).then((value) { return timeController.text = value!.format(context); }); }, ), ///////////////////////////// formfied date ///////////////////////////////////////// SizedBox( height: 5.0, ), DefoultFormField( controller: dateController, label: 'input date', prefix: Icons.calendar_today, type: TextInputType.datetime, validate: ((String value) {}), // validate: (String value){ // if(value.isEmpty) // return' must date not empty '; // return null ; // }, ontap: () { showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime.now(), lastDate: DateTime.parse('2023-05-05'), ).then((value) { return dateController.text = DateFormat.yMMMd().format(value!); }); }, ), ////////////////////////////////////////////////////////////////////// ], ), ), // if i closed the bottomSheet in my hand not in FAB will give error so i did this : ) .closed .then((value) { cubitt.ChangeBottomState(false,Icons.edit); }); // closed func cubitt.ChangeBottomState(true,Icons.add); } }, child: Icon( cubitt. fabicon, ), ), //======================== BottomNavigationBar ========================================= bottomNavigationBar: BottomNavigationBar( type: BottomNavigationBarType.fixed, elevation: 50.0, currentIndex: cubitt.currentindex, onTap: (index) { cubitt.ChangeIndex(index); }, backgroundColor: Colors.blue[200], items: [ BottomNavigationBarItem( icon: Icon( Icons.menu, ), label: 'NEW TASK', ), BottomNavigationBarItem( icon: Icon( Icons.done_all, ), label: 'DONE TASK', ), BottomNavigationBarItem( icon: Icon( Icons.archive, ), label: 'ARCHIVE TASK', ), ], ), ), ); } //============================ finish scaffold ======================================= }
TasksCubit类代码
import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:my_first_app/moduls/new_task_screen/new_task.dart'; import 'package:my_first_app/shared/mycubitclasses/taskstates.dart'; import 'package:sqflite/sqflite.dart'; import '../../moduls/archive_task_screen/archive_task.dart'; import '../../moduls/done_task_screen/done_task.dart'; class TasksCubit extends Cubit<TasksStates> { TasksCubit():super ( InitailTasksState()); static TasksCubit get(context)=>BlocProvider.of(context); ////////////////////////////////////////////////////////////////////// int currentindex = 0; List<Widget> screens = [ NewTask(), DoneTask(), ArchiveTask(), ]; List<String> titls = [ 'new task', 'done task ', 'archive task', ]; void ChangeIndex (index) { currentindex =index; emit(changBottomNavBar()); } var isBottomSheetShown = false; IconData fabicon = Icons.add; void ChangeBottomState ( bool isShow ,IconData icon ) { isBottomSheetShown=isShow; fabicon=icon; emit(changBottomSheet()); } // **************************** DataBase ************************************ late Database Mydatabase; List<Map> tasks =[]; void creatDataBase() { openDatabase( 'todo.db', version: 1, onCreate: (db, version) { print( '************************** daataBase Created ****************************'); db .execute( 'CREATE TABLE tasks (id INTEGER PRIMARY KEY,titel TEXT,date TEXT,time TEXT,status TEXT)') .then((value) { print( '************************** table creaated ****************************'); }).catchError((err) { print( '************************** error in create table ****************************${err.toString()}'); }); }, onOpen: (db) { // ignore: avoid_print print( '************************** daataBase opened ****************************'); GetDataFromDataBase(db).then((value) { tasks=value; emit(GetFromDataBase()); print( '************************** your table next ****************************'); print(tasks); print( '************************** your table above ****************************'); } ).catchError((err){ print( '************************** error when get data ${err.toString()} ****************************'); }); }, ).then((value) { Mydatabase=value; emit(CreatDataBase()); }); } //============================================================================================ //========================== insert data to dataBase ========================================= InserttTODataBase( { required String titel, required String date, required String time, required String status }) async { await Mydatabase.transaction((txn) { return txn.rawInsert('INSERT INTO tasks (titel,date,time,status) VALUES ("$titel","$date","$time","$status")') .then((value) { print('************************** inserted successfulyt to id ${value} ****************************'); emit(InsertDataBase()); GetDataFromDataBase(Mydatabase).then((value) { tasks=value; emit(GetFromDataBase()); print( '************************** your table next ****************************'); print(tasks); print('************************** your table above ****************************'); }); }).catchError((err) { print('************************** error when inserted to record ****************************${err.toString()}'); }); }); } /////////////////////////// get data from dataBase//////////////////////////////////// //============================================================================================ Future<List<Map>> GetDataFromDataBase (database) async { return await database.rawQuery('SELECT * FROM tasks'); } }
问题定位
从错误堆栈和代码可以看出,错误根源在HomeLayout类的成员变量定义处:
TasksCubit cubitt = TasksCubit.get(context);
在StatelessWidget的类成员级别,context并不是可用的BuildContext实例——此时Widget还未被构建,没有上下文对象,这里的context实际引用的是BuildContext这个类型(Type对象),而非具体的上下文实例。调用TasksCubit.get(context)时,将Type类型传入了需要BuildContext的方法,导致类型转换错误。
另外,即使这里的context是有效实例,当前代码中BlocProvider是在build方法内创建的,类成员初始化时BlocProvider还未存在,也无法通过context获取到Cubit实例。
解决步骤
步骤1:移除错误的类成员变量
删除HomeLayout类中的这一行:
TasksCubit cubitt = TasksCubit.get(context);
步骤2:在BuildContext有效范围内获取Cubit实例
在build方法内部或者BlocBuilder的回调中,通过有效BuildContext获取Cubit:
- 方法一:在build方法开头获取实例,后续复用:
@override Widget build(BuildContext context) { return BlocProvider ( create: (context) { return TasksCubit()..creatDataBase(); }, child: Builder(builder: (context) { final cubitt = TasksCubit.get(context); return Scaffold( // ... 后续代码中直接使用cubitt即可 appBar: AppBar( title: Text(cubitt.titls[cubitt.currentindex]), ), // ... 其他部分代码同理替换 ); }), ); }
- 方法二:在BlocBuilder的builder回调中获取:
body: BlocBuilder<TasksCubit,TasksStates>( builder: (BuildContext context, TasksStates state) { final cubitt = TasksCubit.get(context); if (state is InsertDataBase) { Navigator.pop(context); } return cubitt.screens[cubitt.currentindex]; }),
对于AppBar、FAB等其他需要使用Cubit的地方,可以用Builder包裹,或者将BlocProvider移到HomeLayout的父级(比如main.dart的MaterialApp内部)。
步骤3:修复SQL语句中的转义错误
TasksCubit的InserttTODataBase方法
相关产品推荐
相关产品推荐

