#flutter #dart
#flutter #dart
Вопрос:
Подведение итогов проблемы
Я был в stack и много видел этот вопрос, я перепробовал все решения, которые мог найти, но у меня это не сработало. Я извлекаю некоторые данные из своей sqflite
базы данных, и иногда он извлекает результаты, а иногда и нет, что кажется довольно странным. Я читал, что вы не должны вызывать init()
функцию в конструкторе Database
.
Говорят, что это неправильно
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
class TaskDbProvider {
Database db;
TaskDbProvider(){
init()
}
init() async {...}
}
Как бы то ни было, у меня есть рабочий пример приведенного выше кода. (Хотя в моем новом подходе это, похоже, не работает)
Их решение
Прослушивание Completer()
потока
class TaskDbProvider {
Database db;
var readyCompleter = Completer();
Future get ready => readyCompleter.future;
TaskDbProvider(){
init().then((_) {
// mark the provider ready when init completes
readyCompleter.complete();
});
}
}
Хотя это запускает новую цепочку исключений, которые я мог бы предоставить при необходимости.
Ошибка
[ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: NoSuchMethodError: The method 'query' was called on null.
E/flutter (29065): Receiver: null
E/flutter (29065): Tried calling: query("Task")
E/flutter (29065): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
E/flutter (29065): #1 TaskDbProvider.fetchTaskList (package:oppo/resources/db_provider.dart:51:47)
Строка 51
Future<List<Task>> fetchTaskList() async{
List<Map<String,dynamic>> list = await db.query('Task'); //line 51 (db is null?)
return List.generate(list.length, (i) {
return Task.fromDb(list[i]);
});
}
Как я инициализирую БД
Создание блока (некоторые дополнительные функции будут добавлены позже)
class BlocSpeech {
final cache = TaskDbProvider();
}
Сделайте его доступным через InheritedWidget
(он же поставщик)
class SpeechProvider extends InheritedWidget{
final BlocSpeech bloc ;
static BlocSpeech of(BuildContext context){
return (context.inheritFromWidgetOfExactType(SpeechProvider) as SpeechProvider).bloc;
}
SpeechProvider({Key key, Widget child})
: bloc = BlocSpeech(),
super(key: key,child: child);
@override
bool updateShouldNotify(covariant InheritedWidget oldWidget) {
// TODO: implement updateShouldNotify
return true;
}
}
Виджеты пользовательского интерфейса
Оберните виджет поставщиком
SpeechProvider(child: Work())
и создайте виджет:
class Work extends StatefulWidget {
@override
_Work createState() => _Work();
}
class _Work extends State<Work> {
List<Task> allTasks=[];
@override
Widget build(BuildContext context) {
final SpeechBloc = SpeechProvider.of(context); //initialize the BLoC
final Future<List<Task>> future = SpeechBloc.cache.fetchTaskList(); //wait to fetch the items
future.then((value) => allTasks=value); //assign them to local variable
return ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: (allTasks.length),
itemBuilder: (BuildContext context, int index) {
return Container(
margin: EdgeInsets.only(top: 10, bottom: 10),
child: _taskWidget(index,SpeechBloc));
});
}
При необходимости я добавлю любую дополнительную информацию.
Ответ №1:
«Вызывается при null» обычно означает, что вы поторопились с будущим вызовом. Убедитесь, что все в API, в котором указано «возвращает будущее» или «асинхронно», находится в методе, который возвращает будущее, и каждый вызов метода, который возвращает будущее, защищен ожиданием. Есть некоторые места, которые вы можете опустить, если разберетесь более тщательно, но это хороший первый шаг.
Комментарии:
1. Я обернул
ListView.Builder
с помощью StreamBuilder, данные получены, и они каким-то образом становятся нулевыми.snapshot.hasData
istrue
(извлекает элементы), а затем этоfalse
. Может ли быть так, что это проблема рендеринга с StatefulWidget?2. Возможно, вы перестроите поток во что-то другое, кроме initState?
3. Я вызываю его внутри метода виджета
build
, именно там у меня есть доступ кBuildContext
тому, что требуется дляProvider
4. Да, это взорвется. Это одна из многих причин, по которой я перешел от поставщика к Riverpod (наследнику поставщика).
5. Я посмотрю на это. Хотя у меня есть рабочие примеры
Provider
, которые используются правильно. Возможно, я что-то упускаю