Intereting Posts
Аутентификация API Firebase Rest Android-браузер отключает схему https: // из полного квалификатора Возможно ли резервное копирование и RESTORE файл базы данных в android? Не root-устройства Тестирование биллинга в приложении: «Издатель не может купить этот товар» Приложение не станет предпочтительным MediaButtonReceiver при вызове setActive (true) второй раз Как показать диалоговое окно из класса, который расширяет приложение в Android? Установите alpha на ImageView без setAlpha Быстрая отмена / повтор с использованием шаблона памяти / команды? Почему мягкая клавиатура показывает или нет, когда начинается действие? Webview загружает html из каталога ресурсов Масштабный коэффициент для xxhdpi android? AppCompatActivity.onCreate можно вызывать только из одной и той же группы библиотек Android UI вопрос. Руководство по внедрению Почему я получаю сообщения о java.lang.UnsatisfiedLinkError с рынка Когда android срабатывает ACTION_BATTERY_LOW

Установка значения свойства Singleton в Firebase Listener

В настоящее время я тестирую Firebase вместе с моделью Singleton, которую планирую использовать для доступа во время жизненного цикла всего приложения. Я теперь застрял с чем-то, что кажется действительно тривиальным, но я не могу понять это для жизни меня. У меня есть образец модели, которую я использую: Закладки в firebase.

public class BookSingleton { private static BookSingleton model; private ArrayList<BookMark> bookmarks = new ArrayList<BookMark>(); public static BookSingleton getModel() { if (model == null) { throw new IllegalStateException("The model has not been initialised yet."); } return model; } public ArrayList<Bookmark> theBookmarkList() { return this.bookmarks; } public void setBookmarks(ArrayList<Bookmark> bookmarks){ this.bookmarks = bookmarks; } public void loadModelWithDataFromFirebase(){ Firebase db = new Firebase(//url); Firebase bookmarksRef = fb.child(//access correct child); final ArrayList<Bookmark> loadedBookmarks = new ArrayList<Bookmark>(); bookmarksRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { //getting all properties from firebase... Bookmark bookmark = new Bookmark(//properties here); loadedBookmarks.add(bookmark); } } //bookmarks still exist here at this point setBookmarks(loadedBookmarks); } @Override public void onCancelled(FirebaseError firebaseError) { } }); //by now loadedBookmarks is empty //this is probably the issue? //even without this line bookmarks is still not set in mainactivity setBookmarks(loadedBookmarks); } 

Теперь, когда я запускаю mainActivity с экземпляром набора Singleton, я получаю нулевую ошибку, потому что явно функция, которую я написал для загрузки данных модели из firebase, ничего не устанавливает.

Что-то вроде этого: MainActivity

 public class MainActivity extends AppCompatActivity { private BookSingleton theModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Load the model theModel = BookSingleton.getModel(this); //manually setting this works // ArrayList<Book> bookSamples = new ArrayList<Book>; // bookSamples.add(aBookSample); theModel.loadModelWithSampleData(bookSamples); //should have set the singleton model property Bookmarks to the results from firebase theModel.loadModelWithDataFromFirebase(); //returns 0 Log.d(TAG, "" + theModel.theBookmarkList().size()); setContentView(R.layout.activity_main); //......rest of code 

Любые указатели будут очень благодарны. Я новичок в Firebase, поэтому я не уверен, почему это не работает, как я ожидаю.

Благодаря!

Solutions Collecting From Web of "Установка значения свойства Singleton в Firebase Listener"

Firebase загружает и синхронизирует данные асинхронно . Таким образом, ваш loadModelWithDataFromFirebase() не ждет завершения загрузки, он просто начинает загрузку данных из базы данных. К моменту возврата функции loadModelWithDataFromFirebase() загрузка еще не завершена.

Вы можете легко протестировать это для себя с помощью некоторых хорошо сделанных записей журнала:

 public void loadModelWithDataFromFirebase(){ Firebase db = new Firebase(//url); Firebase bookmarksRef = fb.child(//access correct child); Log.v("Async101", "Start loading bookmarks"); final ArrayList<Bookmark> loadedBookmarks = new ArrayList<Bookmark>(); bookmarksRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { Log.v("Async101", "Done loading bookmarks"); //getting all properties from firebase... Bookmark bookmark = new Bookmark(//properties here); loadedBookmarks.add(bookmark); } @Override public void onCancelled(FirebaseError firebaseError) { } }); Log.v("Async101", "Returning loaded bookmarks"); setBookmarks(loadedBookmarks); } 

Вопреки тому, что вы, вероятно, ожидаете, порядок операторов журнала будет:

 Start loading bookmarks Returning loaded bookmarks Done loading bookmarks 

У вас есть два варианта решения асинхронного характера этой загрузки:

  1. Сквош асинхронная ошибка (обычно сопровождается бормотание фразы типа: «это была ошибка, эти люди не знают, что они делают»)

  2. Обнимать асинхронного зверя (обычно сопровождаемого довольно часами проклятия, но через некоторое время мирными и лучшими заявлениями)

Возьмите синюю таблетку – сделайте синхронный асинхронный вызов

Если вам нравится выбирать первый вариант, хорошо подобранный примитив синхронизации будет делать трюк:

 public void loadModelWithDataFromFirebase() throws InterruptedException { Firebase db = new Firebase(//url); Firebase bookmarksRef = fb.child(//access correct child); Semaphore semaphore = new Semaphore(0); final ArrayList<Bookmark> loadedBookmarks = new ArrayList<Bookmark>(); bookmarksRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { Bookmark bookmark = new Bookmark(//properties here); loadedBookmarks.add(bookmark); semaphore.release(); } @Override public void onCancelled(FirebaseError firebaseError) { } }); semaphore.acquire(); setBookmarks(loadedBookmarks); } 

Обновление (20160303) : когда я только что протестировал это на Android, он заблокировал мое приложение. Он работает на обычном JVM отлично, но Android более тонкий, когда дело доходит до потоковой передачи. Не стесняйтесь попробовать и заставить его работать … или

Возьмите красную таблетку – поговорите с асинхронным характером синхронизации данных в Firebase

Если вы предпочитаете использовать асинхронное программирование, вы должны пересмотреть логику своего приложения.

В настоящее время у вас есть «Сначала загрузите закладки, затем загрузите образцы данных, а затем загрузите еще больше».

С асинхронной моделью загрузки вы должны думать, что «всякий раз, когда закладки загружаются, я хочу загрузить образцы данных. Всякий раз, когда загружаемые образцы данных загружаются, я хочу загрузить еще больше». Бонус мышления таким образом заключается в том, что он также работает, когда данные могут быть изменены и, таким образом, синхронизированы несколько раз: «Всякий раз, когда изменения закладок меняются, я хочу также загрузить образцы данных. Всякий раз, когда данные образца меняются, я хочу загрузить еще больше «.

В коде это приводит к вложенным вызовам или цепочкам событий:

 public void synchronizeBookmarks(){ Firebase db = new Firebase(//url); Firebase bookmarksRef = fb.child(//access correct child); final ArrayList<Bookmark> loadedBookmarks = new ArrayList<Bookmark>(); bookmarksRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { Bookmark bookmark = new Bookmark(//properties here); loadedBookmarks.add(bookmark); setBookmarks(loadedBookmarks); loadSampleData(); } @Override public void onCancelled(FirebaseError firebaseError) { } }); } 

В приведенном выше коде мы не просто ожидаем одно событие значения, но вместо этого имеем дело со всеми из них. Это означает, что всякий раз, когда закладки изменяются, выполняется onDataChange и мы (re) загружаем образцы данных (или любые другие действия, соответствующие потребностям вашего приложения).

TL; DR: Embrace Firebase Asynchronicity

Как я упоминал в другом посте , вы можете иметь дело с асинхронным характером Firebase, используя обещания. Это будет так:

 public Task<List<Data>> synchronizeBookmarks(List<Bookmark> bookmarks) { return Tasks.<Void>forResult(null) .then(new GetBook()) .then(new AppendBookmark(bookmarks)) .then(new LoadData()) } public void synchronizeBookmarkWithListener() { synchronizeBookmarks() .addOnSuccessListener(this) .addOnFailureListener(this); } 

com.google.android.gms.tasks

Google API для Android предоставляет платформу задач (как и Parse with Bolts ), которая похожа на концепцию обещаний JavaScript .

Сначала вы создаете Task для загрузки закладки из Firebase:

 class GetBook implements Continuation<Void, Task<Bookmark>> { @Override public Task<Bookmark> then(Task<Void> task) { TaskCompletionSource<Bookmark> tcs = new TaskCompletionSource(); Firebase db = new Firebase("url"); Firebase bookmarksRef = db.child("//access correct child"); bookmarksRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { tcs.setResult(dataSnapshot.getValue(Bookmark.class)); } }); tcs.getTask(); } } 

Теперь, когда вы получили эту идею, setBookmarks что setBookmarks и loadSampleData также асинхронны. Вы также можете создавать их как задачи Continuation (как и предыдущие), которые будут выполняться последовательно:

 class AppendBookmark(List<Bookmark> bookmarks) implements Continuation<List<Bookmark>, Task<Bookmark> { final List<Bookmark> bookmarks; LoadBookmarks(List<Bookmark> bookmarks) { this.bookmark = bookmark; } @Override Task<List<Bookmark>> then(Task<Bookmark> task) { TaskCompletionSource<List<Bookmark>> tcs = new TaskCompletionSource(); bookmarks.add(task.getResult()); tcs.setResult(this.bookmarks); return tcs.getTask(); } } class LoadSampleData implements Continuation<List<Bookmark>, List<Data>> { @Override public Task<List<Data>> then(Task<List<Bookmark>> task) { // ... } } 

Вы должны инициализировать Singleton при загрузке класса. Поместите это на свой код:

 private static BookSingleton model = new BookSingleton(); private BookSingleton() { } public static BookSingleton getModel() { return model == null ? new BookSingleton() : model; }