# #firebase #flutter #google-cloud-firestore #flutter-getx
Вопрос:
Я создал приложение для выполнения задач с помощью flutter, getx и firebase. У меня есть страница входа в систему, страница регистрации и страница задач, на которой я показываю список задач. Я использую пакет firebase_auth для аутентификации и пакет cloud_firestore для сохранения и извлечения данных из firestore. У меня есть 2 модели — одна для пользователя, а другая для todo.
Для сохранения задачи в firestore у меня есть следующий метод —
Future<void> addTodo(String content, String uid) async {
try {
await firebaseFirestore
.collection("users")
.doc(uid)
.collection("todos")
.add({
"content": content,
"dateCreated": Timestamp.now(),
"done": false,
});
} catch (e) {
print(e.toString());
rethrow;
}
}
Чтобы получить список задач из firestore, я использую приведенный ниже метод, который возвращает поток задач
Stream<List<TodoModel>> todoStream(String uid) {
return firebaseFirestore
.collection("users")
.doc(uid)
.collection("todos")
.orderBy("dateCreated", descending: true)
.snapshots()
.map((event) {
List<TodoModel> retVal = List.empty(growable: true);
event.docs.forEach((element) {
TodoModel todo = TodoModel();
todo.todoId = element.id;
todo.content = element['content'];
todo.dateCreated = element['dateCreated'];
todo.done = element['done'];
print(todo.toString());
retVal.add(todo);
});
return retVal;
});
}
Как вы можете видеть, задание для конкретного пользователя привязано к его идентификатору.
Теперь в методе OnInit моего контроллера задач я вызываю вышеуказанную функцию, чтобы получить поток задач
@override
void onInit() {
String uid = Get.find<AuthController>().user;
todoList.bindStream(DatabaseService().todoStream(uid));
super.onInit();
}
Auth controller returns the user’s id which is then fed to the todoStream function to get the todos
In the main page of the app inside the build method I am injecting the Todo controller like so
Get.put(TodoController());
In the body of the Scaffold widget I am displaying the todos using Obx like so
Obx(
() {
if (Get.find<TodoController>().todos.length > 0) {
return Expanded(
child: ListView.builder(
itemCount: Get.find<TodoController>().todos.length,
itemBuilder: (_, index) {
TodoModel todo = Get.find<TodoController>().todos[index];
return Card(
margin:
EdgeInsets.symmetric(horizontal: 20, vertical: 5),
child: Padding(
padding: EdgeInsets.all(10.0),
child: Row(
children: [
Expanded(
child: Text(
todo.content,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
Checkbox(
value: todo.done,
onChanged: (newValue) {
print(newValue);
}),
],
),
),
);
},
),
);
} else {
return Text(
"Loading....",
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
);
}
},
)
Проблема, с которой я сталкиваюсь, заключается в том, что когда приложение запускается и первый пользователь входит в систему, я вижу, что контроллер задач создан и инициализирован, а список его задач отображается на странице. Однако, когда он выходит из системы и другой пользователь входит в систему, на странице может правильно отображаться его имя, что означает, что пользователь идентифицирован правильно, но все равно отображается список задач первого пользователя.
Это говорит мне о том, что при входе второго пользователя в систему метод OnInit контроллера задач не вызывается.
Кто-нибудь знает, как это исправить?
Ниже приведен мой TodoController —
class TodoController extends GetxController {
Rxn<List<TodoModel>> todoList = Rxn<List<TodoModel>>();
List<TodoModel> get todos => todoList.value ?? [];
void clear() => todoList = Rxn<List<TodoModel>>();
@override
void onInit() {
String uid = Get.find<AuthController>().user;
print("onInit called=====================" uid);
todoList.bindStream(DatabaseService().todoStream(uid));
print("todo bind stream done=========================");
super.onInit();
}
}
Ответ №1:
функция oninit вызывает на самом деле проблема была с bindstream ToDoList.bindStream(DatabaseService().todoStream(uid)); После вызова этого bindstream требуется одна секунда, чтобы получить данные из firebase, после чего это приводит к модели, поэтому вам нужно добавить загрузчик на страницу пользовательского интерфейса, как только данные будут загружены ToDoList!=null, затем вам нужно выполнить ложный загрузчик и показать данные
Комментарии:
1. если вы видите Obx, я действительно могу проверить, превышает ли длина списка задач 0, только тогда я отображаю список, в противном случае я отображаю текст » Загрузка….»
2. Если вы проверяете array.length, он выдавал ошибку по длине, поэтому вам нужно проверить, как этот список==null, после того, как этот список не равен нулю, вам нужно проверить больше 0, иначе вы можете сделать так, чтобы вам нужно было составить список, подобный списку<todolist> = []; для того, чтобы не давать нулевую ошибку
3. Я обновил сообщение и добавил класс TodoController, в котором у меня есть этот — Список<TodoModel> get todos =<TodoModel>> ToDoList.value ?? [];
4. если(контроллер. todos == null) { центр возврата(дочерний элемент: CircularProgressIndicator(),); }остальное{ если(контроллер. todos!=ноль){ Вы можете показать пользовательский интерфейс здесь } }
5. Я попробовал вышесказанное, и проблема остается. Я не вижу кругового индикатора прогресса, что может быть связано с быстрой загрузкой данных. Еще одно интересное наблюдение состоит в том, что если я добавляю задачи для второго пользователя, я не вижу, чтобы список задач обновлялся в пользовательском интерфейсе, я все равно могу выполнить задачи для первых пользователей. Если я перезапущу приложение и войду в систему как второй пользователь, я смогу увидеть задачу, которую я добавил ранее. Это говорит мне, что поток ToDoList не обновляется после того, как я войду в систему как второй пользователь. Можете отправить ссылку на мой код на github, если это поможет, спасибо за все ваши предложения до сих пор.