Android Question Firebase Realtime database error

trueboss323

Active Member
Licensed User
Longtime User
I am running out the example program contained here:
https://www.b4x.com/android/forum/threads/firebase-realtimedatabase.69773/

I replaced one of the lines with this:
B4X:
    msgref.Initialize("Reference",realtime.Reference.Child("users/"),"users/")

Without making any other changes, I run the app and immediately get an error.
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
lib1:Raising.. queryresult_ondatachange()
QueryResult_onDataChange()
Error occurred on line: 75 (Starter)
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
at anywheresoftware.b4a.keywords.Common.GetType(Common.java:743)
at db.test.starter._queryresult_ondatachange(starter.java:217)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:735)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:357)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:260)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
at anywheresoftware.b4a.BA$2.run(BA.java:365)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
** Activity (main) Pause, UserClosed = true **

So this is how my database looks. I'm not sure if I'm doing it right.
upload_2019-12-8_0-24-0.png
 

DonManfred

Expert
Licensed User
Longtime User
The provided example is based on MY databasestructure.

Note that the value(s) inside users should be just the ID. And additional information for this user should be in a tree under the ID.

This is how the struct looks for me (and my example).
fbrtdbstruct013.png


You should upload a project to run and test it. Hard to help with this infos you provided.
 
Upvote 0

trueboss323

Active Member
Licensed User
Longtime User
Thank you , this is my updated database.
upload_2019-12-11_12-54-8.png


How can I explicitly read and write an object?
So for example I want to create a new child under "users" , with value "person5" and key "Mike"
Then later I want to read the key under users/person2.
 

Attachments

  • ExampleProject.zip
    9.8 KB · Views: 261
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
with value "person5" and key "Mike"
your complete structure is wrong then.

NOW you have
KEY person4 and
VALUE "Steve"

I can´t help on how to create a KEY person5. As far as i know one need to push a value to the tree users and FIREBASE is creating the KEY.

See my Examplecode on how i do add a new dummy message to the users messages tree.

B4X:
msgref.Initialize("Reference",realtime.Reference.Child("users/"&Starter.phone.GetSettings("android_id")&"/Messages"),"users/"&Starter.phone.GetSettings("android_id")&"/Messages")

    Dim users() As String
    users = Array As String("Someone", "ErelClone", "AnotherUser")
    Dim rnduser As Int = Rnd(0,users.Length)
    Dim msgs() As String
    msgs = Array As String("Hello there", "Hi Master", "You are great")
    Dim rndmsg As Int = Rnd(0,msgs.Length)
    Dim tit() As String
    tit = Array As String("My subject", "this is the subject", "MyGreatSubject")
    Dim rndtit As Int = Rnd(0,tit.Length)
    msgref.push.setValue(CreateMap("From":users(rnduser),"Title":tit(rndtit),"Message":msgs(rndmsg),"time":DateTime.Now),"MSG","Reference") ' This adds a new key to the tree users/userid/messages/ like seen above in my Screenshot
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
How can I explicitly read and write an object?
to write see my last answer.

To read you need to get a reference to the sers tree and fetch all data. Or, to limit unwanted datatransfer you should directly get the tree users/userid/messages/messageid to get the stored values in this subtree.

Note that you should define your database AS FLAT as possible because you´ll fetch unwanted additional data using a deep tree structure.
And it also results in a lot of more traffic.

Using with realtimedatabase it is really helpful if you split the use into using the library and for other things you should consider using the rest api. Getting a list of keys inside a tree is more effective using REST. Especially in therms of Datatraffic generated.

PS: To be honest. Since Firestore is available i do not use realtimedatabase any longer.
 
Last edited:
Upvote 0

trueboss323

Active Member
Licensed User
Longtime User
Thank you. I got the write working , but for reading I'm not sure how to pass the received values to a message box, CLV , etc.
For example I want to write:
B4X:
Msgbox("This message is from: " + from, "")

This is the code I have:
B4X:
msgref.Initialize("Reference",realtime.Reference.Child("users/"& phone.GetSettings("android_id")&"/Messages"),"users/"& phone.GetSettings("android_id")&"/Messages")
Dim qry As FBQuery
qry.Initialize("QueryResult",msgref.orderByChild("users").QueryObj)
qry.limitToFirst(10).addListenerForSingleValueEvent

Which raises the QueryResult_OnDataChange event. But anyway to get this value during onCreate / Resume/ or other events?
In other words, I am trying to get the "AnotherUser" From value.
upload_2019-12-13_19-34-28.png
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Which raises the QueryResult_OnDataChange event
because you are using a ListenerForSingleValueEvent. You can use another listener which gets the complete tree instead of the single values. But you´ll get the HOLE tree then. If you store a lot of data in any of the subtrees

The problem is that Firebase stores the data in a way you can not use directly. The returning data is a java.util.hasmap.
With a small helper you can convert a single hasmap to a Map. But nested values inside are hashmaps too. One need to write a recursive routine to convert such a hashmap (and it´s content).

Another problem is that Firebase usually want special java classes for the values. I used it only partially with the realtime DB.

For example the GeoLocation object.
B4X:
import com.firebase.geofire.GeoLocation;
import anywheresoftware.b4a.AbsObjectWrapper;
import anywheresoftware.b4a.BA;

@BA.ShortName("GeoLocation")
public final class GeoLocationWrapper extends AbsObjectWrapper<GeoLocation> {

    public GeoLocationWrapper(GeoLocation loc) {
        setObject(loc);
    }
    public void Initialize(double lat, double lon) {
        setObject(new GeoLocation(lat,lon));
    }
    public double getlatitude(){
        return getObject().latitude;
    }
    public double getlongitude(){
        return getObject().longitude;
    }
}
Using such java-classes makes it more easy to use FBRTDB. The classes must be written with java though. Never tried to build them using inlinejava.
 
Last edited:
Upvote 0
Top