Firebase Android addChildEventListener explanation - android

I need some clear explanation with addChildEventListener and Query event binding.
I use firebase in my android app. In the onCreate() method of my activity, I create something like this...
fiDbQuery = fiDbRef.child("users").orderByChild("name");
fiDbQuery.addChildEventListener(// listener //);
... where fiDbQuery is a Query instance in the activity (global var) and fiDbRef is a DatabaseReference instance in the activity too, where I already set the initial value.
all is well, when activity first loaded, all the users data are loaded and shown. But then, I have some button to sort this data according to users field, either by email, age, name, etc.
and in those buttons onClickevent listener, I do something like this... (this one is the sort by age button)
fiDbQuery = fiDbRef.child("users").orderByChild("age");
... and I didn't provide the addChildEventListener function because it is already "added" on onCreate() method, right? The data aren't loaded, but if I add the addChildEventListener function it works again.
My question is, is it save to use multiple addChildEventListener into one Query, or is there any performance issues with that? All I want to accomplice is reusing the fiDbQuery instance without the need to add addChildEventListener every single time I modify the fiDbQuery.
Thank You for your help.
EDIT:
all those query I make use the exact same listener. Only one listener for all those query which populate a listView.

You don't need to add the addChildEventListener again. What you need to do, is to change the logic of your actions a little bit.
First define all your queries like this:
nameQuery = fiDbRef.child("users").orderByChild("name");
ageQuery = fiDbRef.child("users").orderByChild("age");
//and so on
To solve your problem, you only need to use an if else-if statement which sounds like this:
Query query;
if(nameButton.isClicked()) {
query = nameQuery;
} else if(ageButton.isClicked()) {
query = ageQuery;
}
query.addChildEventListener( // listener. //);
This means that according on which button the click was made, you are using the desired query. With this code, you just use the addChildEventListener once.
Hope it helps.

Related

NullPointerException when writing to Firebase database

I am trying to add an item to a user in my Firebase database but I keep getting a NullPointerException every time I try and access the location I want to write the data. This location does not yet exist (because I need to first write data to it); however, this was not a problem when adding a "userID" section and adding information underneath it, like so:
database = FirebaseDatabase.getInstance();
userReference = database.getReference("accounts");
DatabaseReference currentUserDB = userReference.child(user.getUid());
currentUserDB.child("name").setValue(name);
The above section of the code adds a key with the user ID and then adds the users name inside it. This is similar to what I want to do next.
What I would like to do is add a section called "item" and inside that add "first" with the value name. Like this .
Where the keys "item" and "first" don't exist until the user first clicks the button to run this code. This code should also work item "second" and so on.
database = FirebaseDatabase.getInstance();
DatabaseReference dbR = database.getReference("accounts").child(uid);
reference = dbR.child("item");
DatabaseReference databaseReference = reference.child("test");
databaseReference.child("name").setValue(name);
I get a NullPointerException at this line:
DatabaseReference databaseReference = reference.child("test");
and I'm not sure why.
I am sure this has been answered in some form because it seems so simple, but I haven't seen anywhere that discusses writing two keys to the database at once.
Any help appreciated. My apologies if this is a duplicate.
Cheers
Edit: I know what a NullPointerException is, i just don't know why I'm getting one in this instance. The two sets of code are very similar and I'm not sure why the second code set gives me an error.
You should write your code like this:
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
reference.child("accounts")
.child("test")
.child("item")
.child("first")
.child("name")
.setValue(name);
If possible put your code here, it would help.
I think if "item" and "first" doesnt exist you can't use it as reference cause the node isnt there.
You need to use reference = dbR.setValue("item") first, and then you can use use as ref.

Get event when replacing node with the same value?

is it possible to get an event in a Listener when I replace value of a node with the same value? seams like if firebase notice that the value is the same no event accures..:s
The Firebase Database synchronizes state between clients. If a write operation doesn't change the state, there is nothing to synchronize to the other listening clients.
In simple code:
ref.setValue(1);
ref.setValue(1); // won't trigger listeners
ref.setValue(2); // will trigger active listeners
ref.setValue(2); // won't trigger listeners
It sounds like you want to instead pass messages between clients. This is totally feasible, but means that you should model your data differently. Instead of storing the value in your database, store the fact that the client wrote a value.
In simple code:
ref.push(1);
ref.push(1);
ref.push(2);
ref.push(2);
In this last sample each write will trigger listeners on ref, since each write is new.
This is a common pattern: instead of storing the final state, you're storing the state changes. It essentially similar the mechanism behind oplogs in databases and many other systems.
Because nothing happens there is no event that is triggered. What can you do in stead, is to check the value before you are setting it.
if(myValue.equals(firebaseValue)) {
//do something
} else {
//do something else
}
Hope it helps.

Couchbase lite on Android, retrieve views

This question is about Couchbase lite (no Sync Gateway).
I'm new to Couchbase, I managed to use the demo app, but I don't understand it completely.
It contains this code which (as far as I understand, since I'm not native English speaker) retrieve views to populate a listview with the indexes:
// This code can be found in ListsActivity.java
// in the setupViewAndQuery() method
com.couchbase.lite.View listsView = mDatabase.getView("list/listsByName");
if (listsView.getMap() == null) {
listsView.setMap(new Mapper() {
#Override
public void map(Map<String, Object> document, Emitter emitter) {
String type = (String) document.get("type");
if ("task-list".equals(type)) {
emitter.emit(document.get("name"), null);
}
}
}, "1.0");
}
listsLiveQuery = listsView.createQuery().toLiveQuery();
Could anyone give me a hand with what each part is doing?
In which step is the listview populated
Can I change "list/listsByName" in the code (line 3)? What would happen?
Can I emit more than one element?
The code is a little bit convoluted. Let's answer the easy parts first.
Can I change "list/listsByName" in the code (line 3)?
Yes. That's just the name of the Couchbase View. You choose the View name. Unfortunately the terms used in Couchbase and Android overlap some. A Couchbase View is a kind of static index of your database.
Can I emit more than one element?
Yes. You can emit most anything you want. Take a look at the documentation here
Now, tracing how the Android ListView gets updated:
In ListsActivity.java notice in the onCreate method a ListAdapter instance gets added to the ListView. This ListAdapter is a private inner class that extends LiveQueryAdapter.
LiveQueryAdapter is in the utils subpackage. If you look at its constructor, you'll see it adds a change listener to the query passed in. When triggered, this change listener sets an enumerator equal to the rows passed back by the live query, then calls notifyDataSetChanged to tell the list to refresh itself. That, in turn, causes getView in ListAdapter to get called. That's where the data is pulled from the database and used to populate a list entry.

Going to parent of an entry in firebase database

I am attaching a picture of my firebase database. I am at OPL and I want to go to its parent. Is there somekind of "GetParent()" kind of fuction, like "GetChildren" that can take me there?
To read the data from database, you need to set listeners at appropriate locations. These listeners provide values for one time as well as for updates with the methods onChildAdded() and onChildChanged().
For your case, you should attach a childListener on the ActionList by using the line
mDatabase.child('ActionList').addChildEventListener(listenerName);
Set up the onChildAdded() method of this listener which provides a snapshot. Traversing through the children from that snapshot using dataSnapshot.getChildren() and to get their values use this function child.getKey() method.

Editing realm object relationship without committing transaction

I have a class called Person one of the variables is a realm list called clothes:
public class Person extends RealmObject{
private RealmList<Clothing> clothes;
}
Clothes is used to display in a RecyclerView wherein the contents can be edited such as quantity, color of clothing, or cloth type.
When I edit the clothing values:
public void setCloth(int i, Cloth cloth) {
realmInstance.beginTransaction();
clothes.set(i, cloth);
realmInstance.commitTransaction();
}
Of course, the record is saved. My problem is what if the user, cancels the editing of the WHOLE Person object. Then the clothes list change will persist.
Please help.
I'm sure you would be a great fan of nested transactions (https://github.com/realm/realm-java/issues/1509).
In the next release of Realm, a new method copyFromRealm() will be introduced. You should copy the clothes list and use copyToRealmOrUpdate() when you commit the Person object.
I have now solved the issue:
The solution is if you're using a fragment or an activity, and displaying the realm object and it's relationship through widgets, begin transaction immediately.
Realm realmInstance = Realm.getInstance(this);
realmInstance.beginTransaction();
This way, changes done directly on the realm object whether a relationship or a plain variable will be allowed.
To cancel the changes done simply use:
realmInstance.cancelTransaction();
This code can be invoked by overriding onBackPressed or any means of canceling the editing.
After canceling the transaction, any changes done including the RealmList objects will be forfeited.
More Info:
I was displaying the clothes list array in a recyleview through an adapter with editing controls (etc. setting the qty, changing cloth type). This solution can also be used in that scenario.
Hope this helps.

Categories

Resources