B4A Library Firebase Realtimedatabase

DonManfred

Expert
Licensed User
This is is a wrap for the Firebase RealtimeDatabase.

Please click here to donate for my work to write the wrapper (You can donate any amount you want :) but the minimum donation should be $10 for this Library)


Please note that this version is not known as stable but - for me - it seems to be working like i expect it
I don´t know if everything works but so far i tested it today it works :D

Please note that the wrap for the Query object is NOT finished. Also others may be incomplete...

To prepare you app you need to use B4A 6+ and you need to follow the Firebase integration and download the json from the firebaseonsole!

If you have successfully connected your appwith firebase the library will know the Database used.

What you need to do is to get a reference to a specific tree in the database-tree



FirebaseRealtimeDatabase

Author: DonManfred
Version: 2.82
  • DataSnapshot
    • Functions:
      • exists As Boolean
      • getChild (child As String) As DataSnapshot
      • hasChild (paramString As String) As Boolean
      • hasChildren As Boolean
      • Initialize (paramDataSnapshot As com.google.firebase.database.DataSnapshot)
      • Value2Map (paramObject As Object) As Object
    • Properties:
      • Children As List [read only]
      • ChildrenCount As Long [read only]
      • DBRef As DatabaseReference [read only]
      • Key As String [read only]
      • Priority As Object [read only]
      • Value As Object [read only]
      • Value2 As Object [read only]
  • DatabaseError
    • Fields:
      • DATA_STALE As Int
      • DISCONNECTED As Int
      • EXPIRED_TOKEN As Int
      • INVALID_TOKEN As Int
      • MAX_RETRIES As Int
      • NETWORK_ERROR As Int
      • OPERATION_FAILED As Int
      • OVERRIDDEN_BY_SET As Int
      • PERMISSION_DENIED As Int
      • UNAVAILABLE As Int
      • UNKNOWN_ERROR As Int
      • USER_CODE_EXCEPTION As Int
      • WRITE_CANCELED As Int
    • Functions:
      • Initialize (paramDatabaseError As com.google.firebase.database.DatabaseError)
      • IsInitialized As Boolean
    • Properties:
      • Code As Int [read only]
      • Details As String [read only]
      • Message As String [read only]
  • DatabaseReference
    • Events:
      • onCancelled (errorCode As Int, errorMessage As String, error As Object, tag As Object)
      • onChildAdded (Snapshot As Object, child As String, tag As Object)
      • onChildChanged (Snapshot As Object, child As String, tag As Object)
      • onChildMoved (Snapshot As Object, child As String, tag As Object)
      • onChildRemoved (Snapshot As Object, tag As Object)
      • onComplete (resultCode As Int, resultMessage As String, result As Object)
      • onDataChange (Snapshot As Object, tag As Object)
    • Functions:
      • addChildEventListener
        Add a ChildEvent-Listener
        If a change occur on a Child then
        there are some Events which can raise.
        onChildAdded holding a DatabaseSnapshot
        of the added Child.
        onChildChanged holding a DatabaseSnapshot
        of the changed child.
        onChildMoved holding a DatabaseSnapshot
        of the moved child.
        onChildRemoved holding a DatabaseSnapshot
        of the removed child.
      • addListenerForSingleValueEvent
        Add a listener for ANY change.
        If any changes occur then the
        Event onDataChange is raised holding
        a DatabaseSnapshot in total.
      • addValueEventListener
      • Child (child As String) As DatabaseReference
      • equalTo (reference As String) As FBQuery
      • equalTo2 (child As String, reference As String) As FBQuery
      • goOffline
      • goOnline
      • Initialize (EventName As String, parref As com.google.firebase.database.DatabaseReference, tag As Object)
      • IsInitialized As Boolean
      • keepSynced (sync As Boolean)
      • LimitToFirst (limit As Int) As FBQuery
      • LimitToLast (limit As Int) As FBQuery
      • onDisconnectCancel
      • onDisconnectRemove
      • onDisconnectSetValue (value As Map)
      • orderByChild (child As String) As FBQuery
      • orderByKey As FBQuery
      • orderByPriority As FBQuery
      • orderByValue As FBQuery
      • push As DatabaseReference
      • removeValue
      • setEventname (EventName As String, Tag As Object) As DatabaseReference
      • setValue (content As Map, child As String, EventName As String)
      • updateChildren (paramMap As Map)
    • Properties:
      • BA As BA [read only]
      • EventName As String [read only]
      • Key As String [read only]
      • Parent As DatabaseReference [read only]
      • Ref As DatabaseReference [read only]
      • Root As DatabaseReference [read only]
      • Tag As Object
  • DocumentSnapshot
    • Functions:
      • exists As Boolean
      • getChild (child As String) As DocumentSnapshot
      • hasChild (paramString As String) As Boolean
      • hasChildren As Boolean
      • Initialize (paramDataSnapshot As com.google.firebase.database.DataSnapshot)
      • IsInitialized As Boolean
      • setEventname (EventName As String, Tag As Object) As DocumentSnapshot
      • Value2Map (paramObject As Object) As Object
    • Properties:
      • Children As List [read only]
      • ChildrenCount As Long [read only]
      • EventName As String [read only]
      • Key As String [read only]
      • Priority As Object [read only]
      • Ref As DatabaseReference [read only]
      • Tag As Object
      • Value As Object [read only]
      • Value2 As Object [read only]
  • FBQuery
    • Events:
      • Snapshot (sign As Object)
    • Functions:
      • addChildEventListener
      • addListenerForSingleValueEvent
      • addValueEventListener
      • Initialize (EventName As String, query As com.google.firebase.database.Query)
      • limitToFirst (limit As Int) As FBQuery
      • limitToLast (limit As Int) As FBQuery
      • orderByChild (path As String) As FBQuery
      • startAt (arg0 As String, arg1 As String) As FBQuery
    • Properties:
      • QueryObj As Object [read only]
      • Tag As Object
  • FireLayout
    • Events:
      • onFireLayoutChildClicked (view As Object)
      • onFireLayoutChildLongClicked (view As Object)
    • Functions:
      • BringToFront
      • DesignerCreateView (base As Panel, lw As Label, props As Map)
      • init
      • Initialize (EventName As String)
      • Invalidate
      • Invalidate2 (arg0 As android.graphics.Rect)
      • Invalidate3 (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int)
      • IsInitialized As Boolean
      • RemoveView
      • RequestFocus As Boolean
      • SendToBack
      • SetBackgroundImage (arg0 As android.graphics.Bitmap) As BitmapDrawable
      • SetColorAnimated (arg0 As Int, arg1 As Int, arg2 As Int)
      • SetLayout (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int)
      • SetLayoutAnimated (arg0 As Int, arg1 As Int, arg2 As Int, arg3 As Int, arg4 As Int)
      • SetVisibleAnimated (arg0 As Int, arg1 As Boolean)
    • Properties:
      • Background As android.graphics.drawable.Drawable
      • Color As Int [write only]
      • Enabled As Boolean
      • Height As Int
      • Id As Int [read only]
      • Left As Int
      • Padding As Int()
      • Parent As Object [read only]
      • Tag As Object
      • Top As Int
      • Visible As Boolean
      • Width As Int
  • FirebaseDatabase
    • Functions:
      • getReference2 (path As String) As DatabaseReference
      • getReferencefromUrl (url As String) As DatabaseReference
      • goOffline
      • goOnline
      • Initialize (EventName As String)
      • orderByValue As FBQuery
      • purgeOutstandingWrites
      • Value2Map (value As Object) As Object
    • Properties:
      • LogLevel As com.google.firebase.database.Logger.Level [write only]
      • PersistenceEnabled As Boolean [write only]
      • Reference As DatabaseReference [read only]
  • GeoFire
    • Events:
      • onComplete (key As String, error As Databaseerror)
      • onDataChanged (datasnapshot As DataSnapshot, location As GeoLocation)
      • onDataEntered (datasnapshot As DataSnapshot, location As GeoLocation)
      • onDataExited (datasnapshot As DataSnapshot)
      • onDataMoved (datasnapshot As DataSnapshot, location As GeoLocation)
      • onGeoQueryError (error As Databaseerror)
      • onGeoQueryReady()
      • onKexExited (key As String)
      • onKeyEntered (key As String, location As GeoLocation)
      • onKeyMoved (key As String, location As GeoLocation)
    • Functions:
      • addGeoQueryDataEventListener
      • addGeoQueryEventListener
      • Initialize (EventName As String, lat As Double, lon As Double, radius As Double)
      • setLocation (key As String, location As com.firebase.geofire.GeoLocation)
      • setQueryCenter (center As com.firebase.geofire.GeoLocation, radius As Double)
    • Properties:
      • Center As com.firebase.geofire.GeoLocation
      • Radius As Double
  • GeoLocation
    • Functions:
      • Initialize (lat As Double, lon As Double)
      • IsInitialized As Boolean
    • Properties:
      • latitude As Double [read only]
      • longitude As Double [read only]

B4X:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim realtime As FirebaseDatabase
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
    realtime.Initialize("Realtime")
    realtime.PersistenceEnabled = True
    realtime.goOnline

    Dim myref As DatabaseReference
    myref.Initialize("Reference",realtime.getReference2(""),"root")
End Sub
The code will get a reference to the root database... You can for sure get a ref to any "subfolder" inside the db.

B4X:
mymessages.Initialize("Chat",realtime.getReference2("users/"&Starter.phone.GetSettings("android_id")&"/Messages"),"users/"&Starter.phone.GetSettings("android_id")&"/Messages")
Please click here to donate for my work to write the wrapper (You can donate any amount you want :) but the minimum donation should be $10+ for this Library)


Setup:
Download the 3rdparty jars from --->DOWNLOAD HERE<---. Due to their size i needed to place it on my Dropbox. Copy the content to your additional libs folder.

Download the most up to date libraryfiles (FirebaseRealtimeDatabaseVx.xx.zip) and put the content to your additional libs folder.
 

Attachments

Last edited:

fredo

Well-Known Member
Licensed User
-....- -....- -....- / - .... .. ... / .. ... / ..-. --- .-. / - .... . / --- .-.. -.. / .-.. .. -... .-. .- .-. -.-- / ...- .---- .-.-.- -..- / -....- -....- -....-


Great, I don't know what to say.
The last days I tried to figure out a way to get a grip on this really important library and now this :cool:

I will test it and give feedback here the next days.

For your tests it might be helpful to have a fully working app with the Firebase Realtime Database to compare your development.

For that I found the "Quickstart" pack in github here: https://github.com/firebase/quickstart-android

Without any knowledge of JAVA functionality and the development process I was able to compile the Quickstart via Google's "Android Studio" and had it up in short time.

Whoever is interested might have a look here:

  • After download and install Version 2.2
  • you choose "Import an Android code sample"
04-08-_2016_07-33-27.jpg
  • select "Getting started", "Firebase Quickstarts for Android"
04-08-_2016_07-34-06.jpg
  • hit "Next" and set your Project location (choose a very short path or compilation will fail later)
06-08-_2016_20-37-11.jpg
  • hit "finish" and wait...
  • You might see this errormessage:
06-08-_2016_20-42-29.jpg
This is due to the missing google-services.json file in the right places.

After trial and error I was successful with copying it in every \app and \app\src\debug folder
06-08-_2016_20-47-38.jpg
  • The you need to connect your project with Firebase witch is easy over the "Tools-Firebase" Menu
06-08-_2016_20-55-35.jpg
  • on the right appears the Firebase Assistant which helps you to have a smooth way to get the app and the Firebase together
06-08-_2016_20-56-57.jpg
06-08-_2016_21-01-24.jpg
  • Now you should be able to compile and run it
  • In the Firebase console "Auth"/ "Sign-In Method" you enable "EMail/Password provider" and then in "Auth"/ "Users" you add an user with an arbitrary Email and Password.
  • In the Firebase console "Database"/ "Rules" you enter:
B4X:
// These rules require authentication
{
  "rules": {
    ".read": "auth != null",
    ".write": "auth != null"
  }
}

  • Now you start the app, log in and make your first post and comment and check what happends milliseconds later in the Firebase console "Database"/ "Data"
1.jpg 04-08-_2016_08-46-57.jpg
2.jpg

If you have a second device connected in parallel you will notice, that the data wil be automatically synchronised. Even if one device is disconnected it will be synched later without user intervention. You can write a post offline and it will be synched if you be online later.

The nodes beginning with "-KOJ..." are automatically created Ids to help rebuild the relations of the data on the clientside. Don't worry about complexity - the lib is doing the "dirty" work.​

If you an experienced SQL developer you might shiver on the sight of the duplicated and denormalized data. But this is the way highly scaleable NoSQL works. It is very effective if you have millions of users using your app simultaneousely.

Tags: #FIBAS #Firebase
 
Last edited:

DonManfred

Expert
Licensed User
New in V1.1 (See post #1):
- Query object
- DatabaseError object
- One Event has changed signature.

B4X:
Sub Reference_onCancelled(errnum As Int,error As String, errObj As Object)
    Log($"ref_onCancelled(${errnum},${error})"$)
    Dim err As DatabaseError = errObj
  
End Sub
- NEW Event onComplete

B4X:
Sub Reference_onComplete(errorCode As Int, errorMessage As String, errObj As Object)
    Log($"ref_onCancelled(${errorCode},${errorMessage})"$)
    Dim err As DatabaseError = errObj
  
End Sub
It is - for example - called when you use removeValue() or updateChildren(Map map) after it finishes...

- btw: updateChildren is new too...
All untested :D
 

fredo

Well-Known Member
Licensed User
Thanks for the Update! I'm really greatful that you ar proceeding to work on this important library.



However, while building an testapp I got this runtime error:
Nevermind, found it. The settings in the Firebase console didn't match with my app setting.

B4X:
** Service (starter) Create **
#-Service_Create
starter_service_create (java line: 159)
java.lang.IllegalStateException: FirebaseApp with name [DEFAULT] doesn't exist.
    at com.google.firebase.FirebaseApp.getInstance(Unknown Source)
    at com.google.firebase.FirebaseApp.getInstance(Unknown Source)
    at com.google.firebase.database.FirebaseDatabase.getInstance(Unknown Source)
    at de.donmanfred.FirebaseDatabaseWrapper.Initialize(FirebaseDatabaseWrapper.java:68)
    at b4a.example.fbdbrt.starter._service_create(starter.java:159)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:153)
    at b4a.example.fbdbrt.starter.onCreate(starter.java:54)
    at android.app.ActivityThread.handleCreateService(ActivityThread.java:2877)
    at android.app.ActivityThread.-wrap4(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1427)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5422)
    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)
** Service (starter) Create **
#-Service_Create
starter_service_create (java line: 159)
java.lang.IllegalStateException: FirebaseApp with name [DEFAULT] doesn't exist.
    at com.google.firebase.FirebaseApp.getInstance(Unknown Source)
    at com.google.firebase.FirebaseApp.getInstance(Unknown Source)
    at com.google.firebase.database.FirebaseDatabase.getInstance(Unknown Source)
    at de.donmanfred.FirebaseDatabaseWrapper.Initialize(FirebaseDatabaseWrapper.java:68)
    at b4a.example.fbdbrt.starter._service_create(starter.java:159)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:153)
    at b4a.example.fbdbrt.starter.onCreate(starter.java:54)
    at android.app.ActivityThread.handleCreateService(ActivityThread.java:2877)
    at android.app.ActivityThread.-wrap4(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1427)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5422)
    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)
java.lang.RuntimeException: Unable to create service b4a.example.fbdbrt.starter: java.lang.RuntimeException: java.lang.IllegalStateException: FirebaseApp with name [DEFAULT] doesn't exist.
    at android.app.ActivityThread.handleCreateService(ActivityThread.java:2887)
    at android.app.ActivityThread.-wrap4(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1427)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5422)
    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)
Caused by: java.lang.RuntimeException: java.lang.IllegalStateException: FirebaseApp with name [DEFAULT] doesn't exist.
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:206)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:153)
    at b4a.example.fbdbrt.starter.onCreate(starter.java:54)
    at android.app.ActivityThread.handleCreateService(ActivityThread.java:2877)
    ... 8 more
Caused by: java.lang.IllegalStateException: FirebaseApp with name [DEFAULT] doesn't exist.
    at com.google.firebase.FirebaseApp.getInstance(Unknown Source)
    at com.google.firebase.FirebaseApp.getInstance(Unknown Source)
    at com.google.firebase.database.FirebaseDatabase.getInstance(Unknown Source)
    at de.donmanfred.FirebaseDatabaseWrapper.Initialize(FirebaseDatabaseWrapper.java:68)
    at b4a.example.fbdbrt.starter._service_create(starter.java:159)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
    ... 11 more
The setup in the Firebase console seems OK,
could it be a mistake on my side?
 

Attachments

Last edited:

fredo

Well-Known Member
Licensed User
...btw: updateChildren is new too...
Thanks for your ongoing efforts, it's really great.

EDIT: Those problems are solved since #35

However, there are two little problems one little problem I can't solve and I hope there is just a typo in the lib...

20-08-_2016_14-39-18.png

I used your DatabaseExample project and added the following code in Activity_Create (see attached project) right after the inits of your Database and DatabaseReference:

B4X:
    ' fredo test area
    '
    ' A database testfile "fir-quickstartsforandroi-93d9a-export.json"  for IMPORT into the Firebase database is located in the Files-folder of this project.
    '
    Dim strTopNode As String = "testnode1" ' If you create this node at the root via Firebase console and import the "fir-quickstartsforandroi-93d9a-export.json" UNDER this node the other existing data stay untouched.
    ' ────────────────────────────────────
    ' EXAMPLE
    ' ────────────────────────────────────
    ' (fbdbtestdatabase)
    '        * testnode1
    '                * post-comments
    '                    *  -KOJH1oVe...
    '                    *  -KO_BCC6e...
    '                *posts
    '                *user-posts
    '                *users
    '
    ' ────────────────────────────────────

    ' Original in JAVA from here --> https://github.com/firebase/quickstart-android/blob/master/database/app/src/main/java/com/google/firebase/quickstart/database/NewPostActivity.java

    Dim strUid As String = "11223344"
    Dim mapPostValues As Map
    mapPostValues.Initialize
    mapPostValues.Put("Uid", strUid)
    mapPostValues.Put("UNam", "testuser")
    mapPostValues.Put("Title", "### TheTitle ###")
    mapPostValues.Put("Body", "... TheBody ...")

'###Problem 1: Here should be a key generated like "-KOJ65eZv...." '' [SOLVED with Don's lib 1.20]
    Dim key As String = ref.child("posts").push.Key
    Log("#-  key=" & key)
    Dim childUpdates As Map
    childUpdates.Initialize
    childUpdates.Put("/posts/" & key, mapPostValues)
    childUpdates.Put("/user-posts/" & strUid & "/" & key, mapPostValues)

'###Problem 2: runtime error "Map cannot be cast to java.util.map". Why??
    ref.updateChildren(childUpdates)

The code snippet is transformed from an official Firebase JAVA source from here: https://github.com/firebase/quickst...base/quickstart/database/NewPostActivity.java
B4X:
    // [START write_fan_out]
    private void writeNewPost(String userId, String username, String title, String body) {
        // Create new post at /user-posts/$userid/$postid and at
        // /posts/$postid simultaneously
        String key = mDatabase.child("posts").push().getKey();
        Post post = new Post(userId, username, title, body);
        Map<String, Object> postValues = post.toMap();

        Map<String, Object> childUpdates = new HashMap<>();
        childUpdates.put("/posts/" + key, postValues);
        childUpdates.put("/user-posts/" + userId + "/" + key, postValues);

        mDatabase.updateChildren(childUpdates);
    }
// [END write_fan_out]
(Another testproject to work with the Firebase Realtime Database would be here)

I know that this kind of database is not your top field of expertise but I hope together we can find out the next steps to ensure that the library is working in all aspects.


Tags: #FIBAS #Firebasedatabase
 

Attachments

Last edited:

fredo

Well-Known Member
Licensed User
@DonManfred --> Did you had a chance to try Erels solution to the problem with the cast of Java-map to B4A-map?

This lib is so extremely beneficial for the B4A world that I mean, it is worth to keep at it.

If you will make the changes on the library-side, I am willing to test the database functionality on the B4A-side and provide constant feedback to you.


If the library for the Firebase Realtime Database is at 100%, I'm happy to write a small tutorial for the Community.
 
Last edited:

Serdar K.

Member
Licensed User
Hi,

DonManfred, thanks for making this awesome library available for B4X world.
Thank you very much for your efforts in this forum.

I have a little weird problem running this library :
Maven artifact not found com.google.firebase/

First one is solved but with the function signature issue is going on.
I'm just trying the demo supplied with the library.Only the db connection is changed.

Did anyone experience the same ? Is there another version of the demo application compatible with library's 1.1 ?

Regards,
Serdar
 

Serdar K.

Member
Licensed User
Somehow i didn't see the message over my message, that was the problem.
Thanks :)


New in V1.1 (See post #1):
- Query object
- DatabaseError object
- One Event has changed signature.

B4X:
Sub Reference_onCancelled(errnum As Int,error As String, errObj As Object)
    Log($"ref_onCancelled(${errnum},${error})"$)
    Dim err As DatabaseError = errObj
 
End Sub
- NEW Event onComplete

B4X:
Sub Reference_onComplete(errorCode As Int, errorMessage As String, errObj As Object)
    Log($"ref_onCancelled(${errorCode},${errorMessage})"$)
    Dim err As DatabaseError = errObj
 
End Sub
It is - for example - called when you use removeValue() or updateChildren(Map map) after it finishes...

- btw: updateChildren is new too...
All untested :D
 

luke2012

Well-Known Member
Licensed User
@DonManfred first of all, my compliments for this wonderful firebase library :)
I'm investigating if it is possible to store and retrieve a password using the realtime database.

So the user should be able to write and update this password.
Is it possible?

Thanks in advance.
 

DonManfred

Expert
Licensed User
Did you had a chance to try Erels solution to the problem with the cast of Java-map to B4A-map?
I guess i sorted it out... Setting a Map as a Value for a databasereference works fine here in my lastest tests. I´m figuring/investigating out more
 

DonManfred

Expert
Licensed User
Create a global Map for the Database
B4X:
    Dim db As Map
After you initialized the database and get the databasereference the event onDatachanged will be raised with the content.

B4X:
Sub Reference_onDataChange(snapshot As Object)
    Log($"ref_onDatachange()"$)
    Dim snap As DataSnapshot = snapshot
    Dim m As Map = snap.Value
    db = m
end sub
You now can use the Map "db" to make changes....

B4X:
Sub Button1_Click
    If db.IsInitialized Then
        If db.ContainsKey("users") Then
            Dim userlist As List = db.Get("users")
            For i = 0 To userlist.Size-1
                Dim user As Map = realtime.Value2Map(userlist.Get(i))
                Log(user)
                If user.Get("name") = "DonManfred" Then
                    Log("DonManfred found (me).. "&user.Get("kdnr"))
                    Log("KDNR="&user.Get("kdnr"))
                    Log("increment calls... is now "&user.Get("calls"))
                    Dim calls As Int = user.Get("calls")
                    calls = calls +1
                    user.Put("calls",calls) ' update value in map
                    userlist.Set(i,user) ' overwrite the user in the list
                End If
            Next
            db.Put("users",userlist) ' write the userlist back to the database-map
        End If
        ref.Value = db ' write the new database
    Else
        Log("Global Map not initialized!?")
    End If
End Sub
Please note that for this examplecode you need V1.2 of the FirebaseRealtimedatabase (See Post #1)
 

fredo

Well-Known Member
Licensed User
Thank you @DonManfred for your ongoing efforts!

I know this is a big project and needs a lot of work to bring it up to 100% functionality.

But I'm sure this will help thousands of B4A developers to create modern social based applications "the rapid way".

I will try the functionality the next days and give you feedback then.
 

fredo

Well-Known Member
Licensed User
OK, the push function generates the special key. This is great!

However, there still is the issue with the updateChildren function,

B4X:
Sub writeNewPost(strUid As String, strUNam As String, strTitle As String, strBody As String) As Boolean
   Log("#-writeNewPost, strUid=" & strUid & ", strUNam=" & strUNam & ", strTitle=" & strTitle & ", strBody=" & strBody)   
   Dim mapPostValues As Map
   mapPostValues.Initialize
   mapPostValues.Put("Uid", strUid)
   mapPostValues.Put("UNam", strUNam)
   mapPostValues.Put("Title", strTitle)
   mapPostValues.Put("Body", strBody)
   Dim strPostValues As String = raMapToJson(mapPostValues)

   Dim key As String = mDatabase.push   
   Log("#-  raw key=" & key)   
   ' Creates this -->    ' #-  raw key=https://fbdbzzzz-xyxyxyx.firebaseio.com/testnode1/-KT4Xi6oGKr0wye-zOoO ' The last part this is what we need = OK
   If key.Length < 2 Then    
     Return False
   End If
   '
   ' Strip the autogenerated optimized key
   key = key.SubString(key.LastIndexOf("/") +1)
   Log("#-  key=" & key)   
   
   Dim strUk1 As String = "/posts/" & key
   Dim strUk2 As String = "/user-posts/" & strUid & "/" & key
   Log("#-  strUk1=" & strUk1)   
   Log("#-  strUk2=" & strUk2)   
   
   Dim childUpdates As Map
   childUpdates.Initialize
   childUpdates.Put(strUk1, strPostValues)
   childUpdates.Put(strUk2, strPostValues )
   mDatabase.updateChildren(childUpdates)    ' <<<<<<----here it breaks
   
   Return True
   
End Sub
02-10-_2016_15-41-43.jpg

but luckily Erel has a solution for this:

02-10-_2016_15-47-44.jpg

@DonManfred you need to take it from here, since I'm still in the basecamp of "Wrap Everest"...
 
Last edited:

fredo

Well-Known Member
Licensed User
B4X:
java.lang.ClassCastException: anywheresoftware.b4a.objects.collections.Map cannot be cast to java.util.Map
    at de.donmanfred.DatabaseReferenceWrapper.updateChildren(DatabaseReferenceWrapper.java:213)
    at b4a.example.fibadb2.testfibart._writenewpost(testfibart.java:840)
    at b4a.example.fibadb2.testfibart._submitpost(testfibart.java:778)
    at b4a.example.fibadb2.testfibart._btnsend_click(testfibart.java:445)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:157)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:153)
    at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:78)
    at android.view.View.performClick(View.java:5609)
    at android.view.View$PerformClick.run(View.java:22259)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6077)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
B4X:
if (_key.length()<2) {
//BA.debugLineNum = 317;BA.debugLine="Return False";
if (true) return anywheresoftware.b4a.keywords.Common.False;
};
//BA.debugLineNum = 321;BA.debugLine="key = key.SubString(key.LastIndexOf(\"/\") +1)";
_key = _key.substring((int) (_key.lastIndexOf("/")+1));
//BA.debugLineNum = 322;BA.debugLine="Log(\"#-  key=\" & key)";
anywheresoftware.b4a.keywords.Common.Log("#-  key="+_key);
//BA.debugLineNum = 324;BA.debugLine="Dim strUk1 As String = \"/posts/\" & key";
_struk1 = "/posts/"+_key;
//BA.debugLineNum = 325;BA.debugLine="Dim strUk2 As String = \"/user-posts/\" & strUid &";
_struk2 = "/user-posts/"+_struid+"/"+_key;
//BA.debugLineNum = 326;BA.debugLine="Log(\"#-  strUk1=\" & strUk1)";
anywheresoftware.b4a.keywords.Common.Log("#-  strUk1="+_struk1);
//BA.debugLineNum = 327;BA.debugLine="Log(\"#-  strUk2=\" & strUk2)";
anywheresoftware.b4a.keywords.Common.Log("#-  strUk2="+_struk2);
//BA.debugLineNum = 329;BA.debugLine="Dim childUpdates As Map";
_childupdates = new anywheresoftware.b4a.objects.collections.Map();
//BA.debugLineNum = 330;BA.debugLine="childUpdates.Initialize";
_childupdates.Initialize();
//BA.debugLineNum = 331;BA.debugLine="childUpdates.Put(strUk1, strPostValues)";
_childupdates.Put((Object)(_struk1),(Object)(_strpostvalues));
//BA.debugLineNum = 332;BA.debugLine="childUpdates.Put(strUk2, strPostValues )";
_childupdates.Put((Object)(_struk2),(Object)(_strpostvalues));
//BA.debugLineNum = 333;BA.debugLine="Log(\"#-  childUpdates=\" & childUpdates)";
anywheresoftware.b4a.keywords.Common.Log("#-  childUpdates="+BA.ObjectToString(_childupdates));
//BA.debugLineNum = 334;BA.debugLine="mDatabase.updateChildren(childUpdates)";
mostCurrent._mdatabase.updateChildren(_childupdates);  <<<<<<<<<<<<<<<---------Line 840
//BA.debugLineNum = 337;BA.debugLine="Return True";
if (true) return anywheresoftware.b4a.keywords.Common.True;
//BA.debugLineNum = 340;BA.debugLine="End Sub";
return false;
 
Last edited:

DonManfred

Expert
Licensed User
I´m not sure but i guess you or me doing it wrong :)

Using
B4X:
    ref.Initialize("Reference",realtime.getReferencefromUrl("https://myfbname.firebaseio.com/"))
i get a reference to the HOLE database...
I can get a map holding the content including all subfolders.

And i can change the map and add new items to it (or add new lists (folders) to it), set the database back as value for the reference i am using.
It will overwrite the hole content in the db. voila, works.

If i use
B4X:
ref.Initialize("Reference",realtime.getReferencefromUrl("https://myfbname.firebaseio.com/users/"&User.Uid&"/"))
from inside a logged-in-event using firebaseauth
B4X:
Sub Auth_SignedIn (User As FirebaseUser)
    Log("SignedIn: " & User.DisplayName)
    lblName.Text = "Hello: " & User.DisplayName
    lblUID.Text = User.Uid
    lblUID.Tag = User
    logged = User
    ref.Initialize("Reference",realtime.getReferencefromUrl("https://myfbname.firebaseio.com/users/"&User.Uid&"/"))
i´ll get a "partially" databasecontent.
In this case the content inside /users/{userfolder}/ but with all subfolders (if there are any)

I can get a map holding the complete content of /users/{userfolder}/

I can add values to it and just reSet the value of the reference to the new map content... Voila, works.

Works pretty fine for me.

Note that i´m not using any updatechildren or such method...
I guess it have to be used in another way.

I´m just changing the map-content and write the map back to the reference.Value

Maybe i´m doing it wrong. Honestly i dont know :D

But that said i just have to say that i did not do much reading on the firebase-examples or tutorials on how to use firebase db

Maybe i did miss some important info ;-)
 

fredo

Well-Known Member
Licensed User
Thanks for your ongoing work.

Note that i´m not using any updatechildren or such method...
"updateChildren" is an essential function in the NoSQL world.

NoSQL is not intented to download the database from the root. It is event-driven! You just set a path to the existing item or create new items and inform Firebase RTDB that there is an update. Then all the magic around transactions etc. is handled by the RTDB.

Have a short look at this and this to get an idea what would be best to set a reference.

The fantastic difference to other RDBMS is that you structure and store your data in a special way so that you can use it later to direct load it in your views. The concept is optimized for huge ammounts of operations as needed for social oriented apps.

Good read with JAVA examples: https://firebase.googleblog.com/2015/09/introducing-multi-location-updates-and_86.html

E.g. like this:
B4X:
Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
// Generate a new push ID for the new post
Firebase newPostRef = ref.child("posts").push();
String newPostKey = newPostRef.getKey();
// Create the data we want to update
Map newPost = new HashMap();
newPost.put("title", "New Post");
newPost.put("content", "Here is my new post!");
Map updatedUserData = new HashMap();
updatedUserData.put("users/posts/" + newPostKey, true);
updatedUserData.put("posts/" + newPostKey, newPost);
// Do a deep-path update
ref.updateChildren(updatedUserData, new Firebase.CompletionListener() {
   @Override
   public void onComplete(FirebaseError firebaseError, Firebase firebase) {
       if (firebaseError != null) {
           System.out.println("Error updating data: " + firebaseError.getMessage());
       }
   }
});

Maybe this Testproject for Firebase Realtime Database will help to test...


 
Last edited:
Top