Android Firebase, как обрабатывать соединение сервера с локальной базой данных в реальном времени - PullRequest
0 голосов
/ 13 января 2019

Что касается похожих вопросов по этой теме и по ChildEventListener, то ответа нет, поэтому здесь мой.

У меня есть локальная SQLite БД, которая содержит все данные, у меня также есть база данных Firebase в реальном времени, которую я обновляю новыми записями или изменениями в реальном времени для всех пользователей. В настоящее время я делаю это с использованием ChildEventListener следующим образом:

DatabaseReference rootRef = FirebaseDatabase.getInstance().getDatabase().getReference();
    DatabaseReference childRef = rootRef.child("my_root");

    ChildEventListener eventListener = new ChildEventListener()
    {
        ....
    };
    childRef.addChildEventListener(eventListener);

Что касается функциональности, с помощью этого кода я могу в реальном времени получать изменения для дочерних элементов, получать новые записи, удаленные дочерние элементы и все, что мне нужно, но есть одна проблема. Когда эта конкретная операция со слушателем загружается, слушатель onChildAdded вызывается огромное количество раз для каждого дочернего элемента в этом корне, как указано в документации:

child_added запускается один раз для каждого существующего дочернего элемента, а затем снова каждый раз, когда к указанному пути добавляется новый дочерний элемент

Итак, я хочу сосредоточиться на вещах, которые мне действительно нужны, и я сделал это с:

rootRef.orderByKey().startAt("-WhatTF123456789")...

Но потом я потерял свои возможности CRUD, потому что он слушает новые записи, а не все.

Итак, я придумал решение. Сохраните узел со всеми изменениями, внесенными в базу данных FireBase, и узел со всеми пользователями, которые прочитали и внесли изменения в локальную БД, чтобы узнать, кому нужно обновление, затем используйте addChildEventListener для этого конкретного узла. Но это кажется излишним.

Какие у меня есть варианты, чтобы справиться с такой ситуацией?

Ответы [ 3 ]

0 голосов
/ 18 января 2019

Я бы сделал корневой узел с именем, например, MaintenanceUpdate. Все клиенты подписаны на изменения здесь. Как только MaintenanceUpdate становится = true, все клиенты отписываются от изменений в основной «базе данных». А затем (когда MaintenanceUpdate = false) снова подписаться снова. В это время вы обновляете базу данных.

0 голосов
/ 19 января 2019

У меня аналогичные требования, с Firebase и Room, хотя я решил это так:

public class BaseModel extends BaseObservable implements IDataModel {

    /** Sqlite default PK */
    private int itemId = 0;

    /** Firebase uniqueId */
    @ColumnInfo(name = SqliteBaseHelper.KEY_FIREBASE_UNIQUE_ID)
    protected String uniqueId = null;

    /** Firebase lastSync */
    @ColumnInfo(name = SqliteBaseHelper.KEY_FIREBASE_LAST_SYNC)
    protected long lastSync = 0;

    ...
}

это означает, что когда локальная запись имеет KEY_FIREBASE_UNIQUE_ID, равный null, а KEY_FIREBASE_LAST_SYNC равна 0, ее необходимо вставить в Firebase, иначе она будет проверяться при запуске синхронизации AsyncTask, если необходимо обновить локальную или удаленную запись. это связано с тем, что основная проблема заключается в том, что при удаленной вставке ChildEventListener будет пытаться синхронизировать дубликаты с одним и тем же клиентом - если только не установлены такие индикаторы для состояния синхронизации на месте, локально и удаленно. локальные первичные ключи могут различаться для разных клиентов (в зависимости от того, как долго они находились в автономном режиме и сколько записей было локально вставлено во время автономного состояния), тогда как для их идентификации используется синтетический KEY_FIREBASE_UNIQUE_ID; это «ключ к успеху».

0 голосов
/ 16 января 2019

Слушатель onChildAdded вызывается огромное количество раз для каждого ребенка в этом корне.

Как вы уже упоминали и как говорится в документации, это ожидаемое поведение. Обычно не рекомендуется прикреплять ChildEventListener к узлу (корневому узлу), который содержит огромное количество данных. Пожалуйста, будьте осторожны с этой практикой, потому что при загрузке большого количества данных вы можете получить ошибки вроде: OutOfMemoryError . Это происходит потому, что вы неявно загружаете весь прослушиваемый узел, а также все данные под ним. Эти данные могут быть представлены как простые свойства или как сложные объекты. Так что это можно считать пустой тратой ресурсов и пропускной способности. В этом случае наилучшим подходом является выравнивание базы данных в максимально возможной степени. Если вы новичок в базах данных NoSQL, эта практика называется денормализация и является обычной практикой, когда дело доходит до Firebase. Для лучшего понимания я рекомендую вам взглянуть на:

Обратите также внимание, что при дублировании данных необходимо учитывать одну вещь. Точно так же, как вы добавляете данные, вы должны поддерживать их. Другими словами, если вы хотите обновить / обнаружить элемент, вы должны делать это в каждом месте, где он существует.

Я также рекомендую вам увидеть последнюю часть моего ответа из следующего поста:

Это для Cloud Firestore, но те же правила применяются к базе данных Firebase в реальном времени.

Но потом я потерял свои возможности CRUD, потому что он слушает новые записи, а не все.

Все в Firebase касается слушателей. Вы не можете получать обновления в реальном времени для объектов в узле, если вы не слушаете их. Таким образом, вы не можете ограничивать результаты и ожидать получения обновлений от объектов, которые вы не слушаете. Если вам нужно получать обновления для всех объектов в узле, вам необходимо прослушать их все. Поскольку этот подход вообще не практичен, вы можете использовать денормализацию , как описано выше, или ограничить результаты с помощью запросов, которые могут помочь вам ограничить объем данных, которые вы получаете из базы данных. Что касается ваших решений, второе предпочтительнее, но вы также можете рассмотреть другой подход, который заключается в загрузке данных в меньших кусках в соответствии со свойством timestamp или в соответствии с любым другим необходимым свойством.

Редактировать: Согласно вашему комментарию:

Можете ли вы предоставить тесты для каждого решения (1.denormalization, 2.my solution), исследовать использование полосы пропускания и ресурсов, и какое из них действительно предпочтительнее?

Все данные смоделированы, чтобы разрешить варианты использования, которые требуются приложению. К сожалению, я не могу делать тесты, потому что это действительно зависит от варианта использования приложения и количества данных, которые оно содержит. Это означает, что того, что работает для одного приложения, может быть недостаточно для другого приложения. Таким образом, тесты могут не быть правильными для всех. Процесс денормализации или ваше решение полностью зависит от того, как вы собираетесь запрашивать базу данных. В приведенном выше списке я добавил новый ресурс, который является моим ответом относительно техники денормализации в базах данных NoSQL . Надеюсь, что это также поможет посетителям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...