gpt4 book ai didi

java - 在 Firebase 监听器中设置 Singleton 属性值

转载 作者:IT老高 更新时间:2023-10-28 20:46:23 26 4
gpt4 key购买 nike

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

现在,当我使用 Singleton 集的实例启动 mainActivity 时,我得到一个 null 错误,因为显然我编写的从 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 异步加载和同步数据。因此,您的 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);
}

与您可能期望的相反,日志语句的顺序将是:

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 error) { throw error.toException(); }
});
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 error) { throw error.toException(); }
});
}

在上面的代码中,我们不只是等待单个值事件,而是处理所有事件。这意味着无论何时更改书签,都会执行 onDataChange 并且我们(重新)加载示例数据(或任何其他适合您的应用程序需要的操作)。

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

关于java - 在 Firebase 监听器中设置 Singleton 属性值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33203379/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com