猿问

在Firebase侦听器中设置Singleton属性值

在Firebase侦听器中设置Singleton属性值

我目前正在测试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) {

        }
    });

现在,当我使用Singleton集合的实例启动mainActivity时,我会得到一个空错误,因为很明显,我编写的函数从Firebase集中加载模型数据时没有。

就像这样:MainActivity

public class MainActivity extends AppCompatActivity {private BookSingleton theModel;@Overrideprotected 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);

我该怎么做呢?


慕的地8271018
浏览 426回答 3
3回答

拉风的咖菲猫

加载和同步数据异步..所以你的loadModelWithDataFromFirebase()不等待加载完成,它只是开始从数据库加载数据。当你loadModelWithDataFromFirebase()函数返回,加载尚未完成。您可以轻松地使用一些位置良好的日志语句来测试这一点:public&nbsp;void&nbsp;loadModelWithDataFromFirebase(){ &nbsp;&nbsp;&nbsp;&nbsp;Firebase&nbsp;db&nbsp;=&nbsp;new&nbsp;Firebase(//url); &nbsp;&nbsp;&nbsp;&nbsp;Firebase&nbsp;bookmarksRef&nbsp;=&nbsp;fb.child(//access&nbsp;correct&nbsp;child); &nbsp;&nbsp;&nbsp;&nbsp;Log.v("Async101",&nbsp;"Start&nbsp;loading&nbsp;bookmarks"); &nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;ArrayList<Bookmark>&nbsp;loadedBookmarks&nbsp;=&nbsp;new&nbsp;ArrayList<Bookmark>(); &nbsp;&nbsp;&nbsp;&nbsp;bookmarksRef.addListenerForSingleValueEvent(new&nbsp;ValueEventListener()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;onDataChange(DataSnapshot&nbsp;dataSnapshot)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Log.v("Async101",&nbsp;"Done&nbsp;loading&nbsp;bookmarks"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//getting&nbsp;all&nbsp;properties&nbsp;from&nbsp;firebase... &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bookmark&nbsp;bookmark&nbsp;=&nbsp;new&nbsp;Bookmark(//properties&nbsp;here); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loadedBookmarks.add(bookmark); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;onCancelled(FirebaseError&nbsp;firebaseError)&nbsp;{&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;Log.v("Async101",&nbsp;"Returning&nbsp;loaded&nbsp;bookmarks"); &nbsp;&nbsp;&nbsp;&nbsp;setBookmarks(loadedBookmarks);}与您可能预期的相反,日志语句的顺序为:Start&nbsp;loading&nbsp;bookmarksReturning&nbsp;loaded&nbsp;bookmarksDone&nbsp;loading&nbsp;bookmarks对于处理这种加载的异步性质,您有两种选择:压制异步错误(通常伴随着这样的短语:“这是个错误,这些人不知道自己在做什么”)拥抱异步野兽(通常伴随着几个小时的诅咒,但经过一段时间的和平和行为良好的应用程序)采取蓝色药丸-使异步调用同步运行。如果您想选择第一个选项,那么一个放置良好的同步原语就可以做到这一点:public&nbsp;void&nbsp;loadModelWithDataFromFirebase()&nbsp;throws&nbsp;InterruptedException&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;Firebase&nbsp;db&nbsp;=&nbsp;new&nbsp;Firebase(//url); &nbsp;&nbsp;&nbsp;&nbsp;Firebase&nbsp;bookmarksRef&nbsp;=&nbsp;fb.child(//access&nbsp;correct&nbsp;child); &nbsp;&nbsp;&nbsp;&nbsp;Semaphore&nbsp;semaphore&nbsp;=&nbsp;new&nbsp;Semaphore(0); &nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;ArrayList<Bookmark>&nbsp;loadedBookmarks&nbsp;=&nbsp;new&nbsp;ArrayList<Bookmark>(); &nbsp;&nbsp;&nbsp;&nbsp;bookmarksRef.addListenerForSingleValueEvent(new&nbsp;ValueEventListener()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;onDataChange(DataSnapshot&nbsp;dataSnapshot)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bookmark&nbsp;bookmark&nbsp;=&nbsp;new&nbsp;Bookmark(//properties&nbsp;here); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loadedBookmarks.add(bookmark); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;semaphore.release(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;onCancelled(FirebaseError&nbsp;firebaseError)&nbsp;{&nbsp;throw&nbsp;firebaseError.toException();&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;semaphore.acquire(); &nbsp;&nbsp;&nbsp;&nbsp;setBookmarks(loadedBookmarks);}更新(20160303)当我刚刚在Android上测试这个时,它屏蔽了我的应用程序。它在常规JVM上正常工作,但是Android在线程处理方面更挑剔。你可以试着让它发挥作用.。或采用红色药丸-处理Firebase中数据同步的异步性质如果您选择采用异步编程,则应该重新考虑应用程序的逻辑。您现在有“首先加载书签,然后加载样本数据,然后加载更多”。使用异步加载模型时,您应该这样想:“无论何时书签加载,我都希望加载示例数据,只要加载了样本数据,我就想加载更多。”这种想法的好处是,当数据可能不断变化并因此多次同步时,它也能工作:“每当书签发生变化时,我也希望加载样本数据。每当样本数据发生变化时,我希望加载更多。”在代码中,这会导致嵌套调用或事件链:public&nbsp;void&nbsp;synchronizeBookmarks(){ &nbsp;&nbsp;&nbsp;&nbsp;Firebase&nbsp;db&nbsp;=&nbsp;new&nbsp;Firebase(//url); &nbsp;&nbsp;&nbsp;&nbsp;Firebase&nbsp;bookmarksRef&nbsp;=&nbsp;fb.child(//access&nbsp;correct&nbsp;child); &nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;ArrayList<Bookmark>&nbsp;loadedBookmarks&nbsp;=&nbsp;new&nbsp;ArrayList<Bookmark>(); &nbsp;&nbsp;&nbsp;&nbsp;bookmarksRef.addValueEventListener(new&nbsp;ValueEventListener()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;onDataChange(DataSnapshot&nbsp;dataSnapshot)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bookmark&nbsp;bookmark&nbsp;=&nbsp;new&nbsp;Bookmark(//properties&nbsp;here); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loadedBookmarks.add(bookmark); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setBookmarks(loadedBookmarks); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loadSampleData(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;onCancelled(FirebaseError&nbsp;firebaseError)&nbsp;{&nbsp;throw&nbsp;firebaseError.toException();&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;});}在上面的代码中,我们不只是等待单个值事件,而是处理所有这些事件。这意味着,每当书签被更改时,onDataChange执行,我们(重新)加载示例数据(或任何其他适合应用程序需要的操作)。为了使代码更可重用,您可能需要定义自己的回调接口,而不是在onDataChange..看一看这个答案一个很好的例子。

LEATH

加载类时,必须初始化Singleton。把这个放在你的代码上:private&nbsp;static&nbsp;BookSingleton&nbsp;&nbsp;model&nbsp;=&nbsp;new&nbsp;BookSingleton();private&nbsp;BookSingleton()&nbsp;{}public&nbsp;static&nbsp;BookSingleton&nbsp;getModel()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp;model&nbsp;==&nbsp;null&nbsp;?&nbsp;new&nbsp;BookSingleton()&nbsp;:&nbsp;model;}
随时随地看视频慕课网APP

相关分类

Android
Java
我要回答