Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在Firebase侦听器中设置Singleton属性值_Java_Android_Firebase_Singleton_Firebase Realtime Database - Fatal编程技术网

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

Java 在Firebase侦听器中设置Singleton属性值,java,android,firebase,singleton,firebase-realtime-database,Java,Android,Firebase,Singleton,Firebase Realtime Database,我目前正在测试Firebase以及一个我计划在整个应用程序生命周期中访问的单例模型。我现在被一些看起来很琐碎的事情缠住了,但我一辈子都搞不清楚。我有一个我使用的模型示例:firebase中的书签 public class BookSingleton { private static BookSingleton model; private ArrayList<BookMark> bookmarks = new ArrayList<BookMark>(); pu

我目前正在测试Firebase以及一个我计划在整个应用程序生命周期中访问的单例模型。我现在被一些看起来很琐碎的事情缠住了,但我一辈子都搞不清楚。我有一个我使用的模型示例: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);
}

我如何才能做到这一点?

加载类时,必须初始化单例。 在代码中添加以下内容:

private static BookSingleton  model = new BookSingleton();

private BookSingleton() {
}

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

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 error) { throw error.toException(); }
    });
    Log.v("Async101", "Returning loaded bookmarks");
    setBookmarks(loadedBookmarks);
}
处理此加载的异步性质有两种选择:

  • 消除异步错误(通常伴随着低声说:“这是一个错误,这些人不知道他们在做什么”)

  • 拥抱异步beast(通常伴随着几个小时的诅咒,但过了一段时间,就会出现和平和性能更好的应用程序)

  • 服用蓝色药丸-使异步调用同步运行 如果您想选择第一个选项,那么一个位置良好的同步原语将起到以下作用:

    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 error) { throw error.toException(); }
        });
        semaphore.acquire();
        setBookmarks(loadedBookmarks);
    }
    
    public void loadModelWithDataFromFirebase()引发InterruptedException{
    Firebase db=新的Firebase(//url);
    Firebase bookmarksRef=fb.child(//访问正确的子对象);
    信号量信号量=新信号量(0);
    final ArrayList loadedBookmarks=新ArrayList();
    bookmarksRef.addListenerForSingleValueEvent(新值EventListener()){
    @凌驾
    公共void onDataChange(DataSnapshot DataSnapshot){
    Bookmark Bookmark=新书签(//此处为属性);
    加载书签。添加(书签);
    semaphore.release();
    }
    @凌驾
    public void onCancelled(FirebaseError错误){throw error.toException();}
    });
    semaphore.acquire();
    setBookmarks(加载的书签);
    }
    
    更新(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 error) { throw error.toException(); }
        });
    }
    
    public void同步电子书标记(){
    Firebase db=新的Firebase(//url);
    Firebase bookmarksRef=fb.child(//访问正确的子对象);
    final ArrayList loadedBookmarks=新ArrayList();
    bookmarksRef.addValueEventListener(新的ValueEventListener(){
    @凌驾
    公共void onDataChange(DataSnapshot DataSnapshot){
    Bookmark Bookmark=新书签(//此处为属性);
    加载书签。添加(书签);
    setBookmarks(加载的书签);
    loadSampleData();
    }
    @凌驾
    public void onCancelled(FirebaseError错误){throw error.toException();}
    });
    }
    
    在上面的代码中,我们不只是等待一个值事件,而是处理所有事件。这意味着每当更改书签时,都会执行
    onDataChange
    ,我们(重新)加载示例数据(或任何其他符合应用程序需要的操作)

    为了使代码更加可重用,您可能需要定义自己的回调接口,而不是在
    onDataChange
    中调用精确的代码。请看一个很好的例子。

    TL;DR:拥抱Firebase异步性 正如我在另一篇文章中提到的,您可以使用承诺来处理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);
    }
    
    既然您已经有了这个想法,那么就假设
    setBookmarks
    loadSampleData
    也是异步的。您还可以将它们创建为按顺序运行的任务(与前一个任务相同):

    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) {
            // ...
        }
    }
    
    类AppendBookmark(列表书签)实现
    
    继续就是不要使用单例。完全避免。这很快,是的,我可能会跳过使用Singleton,但我仍然想知道为什么,因为即使不使用Singleton,我可能会再次面临这个问题。信号量在我看来非常黑客,所以我没有尝试实现它。然而,您的解释确实帮助我理解了Firebase的异步本质,这让我转而考虑在事件侦听器中设置所有逻辑。非常感谢:DSo是否意味着firebase数据库中不应使用层的概念。例如,我想编写一个DataAccess层,在该层中,我将分别调用每个查询,然后在活动中的DataAccess类中调用此方法,但我开始怀疑这是否正确。所以我应该把我的查询代码粘贴到每个活动中,或者怎么样?你可以使用CountDownLatch轻松地转换成同步,只需要几行代码。有时事情不能很好地结合在一起,这是必要的。例如,这个小部件不支持异步。@AnthonyWijaya哦,不,绝对不是黑客!这是
    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);
    }
    
    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();
        }
    
    }
    
    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) {
            // ...
        }
    }