本文将带您了解关于从功能返回之前,等待Firebase加载的新内容,另外,我们还将为您提供关于android–com.google.firebase.database.DatabaseExceptio
本文将带您了解关于从功能返回之前,等待Firebase加载的新内容,另外,我们还将为您提供关于android – com.google.firebase.database.DatabaseException:必须在FirebaseDatabase实例的任何其他用法之前调用setPersis、android-FIrebase Cloud Messaging,无法解析依赖项com.google.firebase:firebase-core:9.0.2、angularjs – 当解析返回$firebaseArray需要首先返回$firebaseObject服务?、Firebase / Android:将从Firebase检索到的值添加到arraylist返回空指针异常的实用信息。
本文目录一览:- 从功能返回之前,等待Firebase加载
- android – com.google.firebase.database.DatabaseException:必须在FirebaseDatabase实例的任何其他用法之前调用setPersis
- android-FIrebase Cloud Messaging,无法解析依赖项com.google.firebase:firebase-core:9.0.2
- angularjs – 当解析返回$firebaseArray需要首先返回$firebaseObject服务?
- Firebase / Android:将从Firebase检索到的值添加到arraylist返回空指针异常
从功能返回之前,等待Firebase加载
我有一个简单的功能,可以从Firebase加载数据。
func loadFromFireBase() -> Array<Song>? { var songArray:Array<Song> = [] ref.observe(.value, with: { snapshot in //Load songArray }) if songArray.isEmpty { return nil } return songArray}
当前nil
,即使有要加载的数据,此函数也会始终返回。之所以这样做,是因为它永远不会执行执行完成块,在函数返回之前,它不会在数组中加载数组。我正在寻找一种使函数仅在调用完成块后才返回的方法,但不能将return放在完成块中。
答案1
小编典典(关于此问题的变化经常出现在SO上。我永远找不到一个好的,全面的答案,因此下面尝试提供这样的答案)
你不能那样做。Firebase是异步的。其功能采用完成处理程序并立即返回。您需要重写loadFromFirebase函数以获取完成处理程序。
我在Github上有一个名为 Async_demo
(link)的示例项目,它是一个正在运行的(Swift 3)应用程序,说明了该技术。
其中的关键部分是function downloadFileAtURL
,它需要一个完成处理程序并进行异步下载:
typealias DataClosure = (Data?, Error?) -> Void/** This class is a trivial example of a class that handles async processing. It offers a single function, `downloadFileAtURL()` */class DownloadManager: NSObject { static var downloadManager = DownloadManager() private lazy var session: URLSession = { return URLSession.shared }() /** This function demonstrates handling an async task. - Parameter url The url to download - Parameter completion: A completion handler to execute once the download is finished */ func downloadFileAtURL(_ url: URL, completion: @escaping DataClosure) { //We create a URLRequest that does not allow caching so you can see the download take place let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 30.0) let dataTask = URLSession.shared.dataTask(with: request) { //------------------------------------------ //This is the completion handler, which runs LATER, //after downloadFileAtURL has returned. data, response, error in //Perform the completion handler on the main thread DispatchQueue.main.async() { //Call the copmletion handler that was passed to us completion(data, error) } //------------------------------------------ } dataTask.resume() //When we get here the data task will NOT have completed yet! } }
上面的代码使用Apple的URLSession
类从异步服务器异步下载数据。创建时dataTask
,您传入一个完成处理程序,该处理程序在数据任务完成(或失败)时被调用。但是请注意:您的完成处理程序在后台线程上被调用。
很好,因为如果您需要执行诸如解析大型JSON或XML结构之类的耗时的处理,则可以在完成处理程序中进行处理而不会导致应用程序的UI冻结。但是,结果是,如果不将这些UI调用发送到主线程,就无法在数据任务完成处理程序中进行UI调用。上面的代码使用调用在主线程上调用了整个完成处理程序DispatchQueue.main.async(){}
。
返回OP的代码:
我发现以闭包作为参数的函数很难读取,因此我通常将闭包定义为类型别名。
通过@ Raghav7890的答案重做代码以使用typealias:
typealias SongArrayClosure = (Array<Song>?) -> Voidfunc loadFromFireBase(completionHandler: @escaping SongArrayClosure) { ref.observe(.value, with: { snapshot in var songArray:Array<Song> = [] //Put code here to load songArray from the FireBase returned data if songArray.isEmpty { completionHandler(nil) }else { completionHandler(songArray) } })}
我已经很久没有使用Firebase了(然后只修改了别人的Firebase项目),所以我不记得它是在主线程还是在后台线程上调用它的完成处理程序。如果它在后台线程上调用完成处理程序,那么您可能希望将对完成处理程序的调用包装在对主线程的GCD调用中。
编辑:
根据 这个SO问题的答案,听起来Firebase确实在后台线程上进行网络调用,但是在主线程上调用了侦听器。
在那种情况下,您可以忽略以下有关Firebase的代码,但是对于那些阅读此线程以寻求其他种类的异步代码帮助的人,可以按照以下方法重写代码以在主线程上调用完成处理程序:
typealias SongArrayClosure = (Array<Song>?) -> Voidfunc loadFromFireBase(completionHandler:@escaping SongArrayClosure) { ref.observe(.value, with: { snapshot in var songArray:Array<Song> = [] //Put code here to load songArray from the FireBase returned data //Pass songArray to the completion handler on the main thread. DispatchQueue.main.async() { if songArray.isEmpty { completionHandler(nil) }else { completionHandler(songArray) } } })}
android – com.google.firebase.database.DatabaseException:必须在FirebaseDatabase实例的任何其他用法之前调用setPersis
当我尝试在fIREBASE中设置持久性时遇到问题,有人可以解释一下如何去做,
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_meal_details);
if (mDatabase == null) {
mDatabase = FirebaseDatabase.getInstance().getReference();
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
// ...
}
// FirebaseDatabase.getInstance().setPersistenceEnabled(true);
mDatabase = FirebaseDatabase.getInstance().getReference();
解决方法:
像这样的东西(iirc):
if (mDatabase == null) {
FirebaseDatabase database = FirebaseDatabase.getInstance();
database.setPersistenceEnabled(true);
mDatabase = database.getReference();
// ...
}
android-FIrebase Cloud Messaging,无法解析依赖项com.google.firebase:firebase-core:9.0.2
我试图按照here给出的指南使用Firebase Cloud Messaging编写应用程序,但我为添加实现FCM的依赖项而感到惊讶(com.google.firebase:firebase-core:9.0.2).每次我尝试通过项目结构添加它时,它都不会在搜索结果中列出依赖项.当我尝试将其添加到应用程序级别gradle中时,它给我一个错误,导致无法解决依赖关系.我不知道我要去哪里错了,但是请帮我解决这个问题.
解决方法:
从您的SDK管理器下载更新.我遇到过同样的问题.从SDK经理更新Google Play服务和Google Repository对我来说很有效.
angularjs – 当解析返回$firebaseArray需要首先返回$firebaseObject服务?
var chatRef = firebase.database().ref('messages/'+thisGroup.groupId+'/main');
这是我只能通过解决方案解开一个承诺的情况,或者我是否接近这样做(ActiveGroup是一个返回用户当前所选组的$firebaSEObject的服务):
.state('tab.chats-main',{ url: '/chats/main',cache: true,views: { 'tab-chats': { templateUrl: 'templates/tab-chatsTopic.html',controller: 'ChatsTopicCtrl' } },resolve: { currentAuth: authRequire,posts: function($firebaseArray,currentAuth,ActiveGroup){ var thisGroup = ActiveGroup(currentAuth.uid); thisGroup.$loaded().then(function(){ var chatRef = firebase.database().ref('messages/'+thisGroup.groupId+'/main'); return $firebaseArray(chatRef.limitToLast(100)).$loaded(); }) } } })
然后这是我在控制器中注入帖子的地方:
.controller('ChatsTopicCtrl',function($scope,thisGroup,posts,profile,chatName,chatMessages,ActiveGroup,$cordovaCamera,$ionicScrollDelegate,$ionicModal,$ionicActionSheet,$timeout,$state,moment) { console.log("what are posts? ",posts); // posts is undefined
提前致谢!
解决方法
.state('tab.chats-main',{ url: '/chats/main',views: { 'tab-chats': { templateUrl: 'templates/tab-chatsTopic.html',controller: 'ChatsTopicCtrl' } },resolve: { currentAuth: authRequire,thisGroup: function(ActiveGroup,currentAuth){ return ActiveGroup(currentAuth.uid).$loaded(); },thisGroup){ var chatRef = firebase.database().ref('messages/'+thisGroup.groupId+'/main'); return $firebaseArray(chatRef.limitToLast(100)).$loaded(); } } })
然后是你注入它的控制器:
.controller('ChatsTopicCtrl',moment) { console.log("what is posts? ",posts); // gives proper result
如果有更好/更推荐的方式,我仍然非常感谢听到它.
Firebase / Android:将从Firebase检索到的值添加到arraylist返回空指针异常
我正在尝试从Firebase数据库中将检索到的值添加到Arraylist,再从那里添加到String数组。我的检索方法工作正常。我可以将所有值打印在烤面包上。但是显然它不会被添加到arraylist中。
这是我的代码,用于在片段类的onActivityCreated()中进行检索。
ArrayList<String> allBrands = new ArrayList<>();brandRef=FirebaseDatabase.getInstance().getReferenceFromUrl("https://stockmanager-142503.firebaseio.com/Brands"); q=brandRef.orderByChild("brandName"); q.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String s) { allBrands.add((dataSnapshot.getValue(Brand.class)).getBrandName()); Toast.makeText(getActivity(),(dataSnapshot.getValue(Brand.class)).getBrandName(), Toast.LENGTH_SHORT).show(); } @Override public void onChildChanged(DataSnapshot dataSnapshot, String s) { } @Override public void onChildRemoved(DataSnapshot dataSnapshot) { } @Override public void onChildMoved(DataSnapshot dataSnapshot, String s) { } @Override public void onCancelled(DatabaseError databaseError) { } });
这就是我试图在Fragment类的OnActivityResult()方法中使用arrayList的地方,但是我认为不会执行迭代器循环。没有看到烤面包。当我尝试使用数组时,出现了空指针异常。我假设这些值不会复制到brands数组中。
count=allBrands.size(); String[] brands=new String[count]; Iterator<String> itemIterator = allBrands.iterator(); if(itemIterator.hasNext()){ //brands[i] = itemIterator.next(); Toast.makeText(getActivity(), itemIterator.next(), Toast.LENGTH_SHORT).show(); // i++; } for( i=0;i<count;i++){ if(brands[i].compareTo(Brand)==0){ f=1;break; } }
这是我的数据库,以防万一。但是我可以毫无问题地将所有检索到的值打印在Toast中。
答案1
小编典典从共享的代码中很难确定,因为我怀疑您可能会从Firebase异步加载所有数据的事实中感到困惑。另外,您可能根本无权读取数据。我会给两个答案。
数据异步加载
将一些日志语句添加到最小代码段中时,最容易理解此行为:
System.out.println("Before attaching listener");q.addChildEventListener(new ChildEventListener() { public void onChildAdded(DataSnapshot dataSnapshot, String s) { System.out.println("In onChildAdded"); } public void onChildChanged(DataSnapshot dataSnapshot, String s) { } public void onChildRemoved(DataSnapshot dataSnapshot) { } public void onChildMoved(DataSnapshot dataSnapshot, String s) { } public void onCancelled(DatabaseError databaseError) { }});System.out.println("After attaching listener");
该代码段的输出将是:
附加监听器之前
附加监听器后
在onChildAdded中(可能多次)
这可能不是您期望输出的顺序。这是因为Firebase(与大多数云API一样)异步地从数据库加载数据:它不等待数据返回,而是继续在主线程中运行代码,并且然后ChildEventListener.onChildAdded
在数据可用时回叫您。
无法在Android上等待数据。如果这样做,您的用户将得到令人生畏的“应用程序无响应”对话框,并且您的应用程序将
被杀死。
因此,处理此API异步特性的唯一方法是将需要具有新数据的代码放入onChildAdded()
回调中(并
可能在某些时候也放入其他回调中):
q.addChildEventListener(new ChildEventListener() { public void onChildAdded(DataSnapshot dataSnapshot, String s) { allBrands.add((dataSnapshot.getValue(Brand.class)).getBrandName()); System.out.println(allBrands.length); }
您需要获得读取数据的权限
您需要权限才能从某个位置读取数据。如果您没有权限,Firebase将立即取消监听器。您需要
在代码中处理这种情况,否则您将一无所知。
public void onCancelled(DatabaseError databaseError) { throw databaseError.toException();}
今天关于从功能返回之前,等待Firebase加载的分享就到这里,希望大家有所收获,若想了解更多关于android – com.google.firebase.database.DatabaseException:必须在FirebaseDatabase实例的任何其他用法之前调用setPersis、android-FIrebase Cloud Messaging,无法解析依赖项com.google.firebase:firebase-core:9.0.2、angularjs – 当解析返回$firebaseArray需要首先返回$firebaseObject服务?、Firebase / Android:将从Firebase检索到的值添加到arraylist返回空指针异常等相关知识,可以在本站进行查询。
本文标签: