Метод OnInit контроллера Flutter Getx не вызывается при загрузке страницы

# #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, если это поможет, спасибо за все ваши предложения до сих пор.