Method to find object by ID with firebase in Android - android

Well, I want to create this method, but since you're not able to return from listener's methods, I just can't figure it out a way to give the user when firebase finds it:
public static User findByID(#NonNegative final int id) {
getDatabase().orderByChild("id")
.equalTo(id)
.limitToFirst(1)
.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
dataSnapshot.getValue(User.class); // this one must be returned
}
#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) {}
});
}
Creating a variable to receive value and return doesn't work as well, since firebase takes a bit long to find the user.

Data retrieval is asynchronous in Firebase, so you cannot return. I think there are two ways to overcome the problem you are facing.
First Way
If data should be returned somewhere in the same class in which findById() exists, then you can do as follows:
class A {
private TextView nameTextView;
...
public void findById(#NonNegative int id) {
userRef().orderByChild("id")
.equalTo(id)
.limitToFirst(1)
.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
User user = dataSnapshot.getValue(User.class);
onUserRetrieved(user);
}
...
});
}
private void onUserRetrived(User user) {
// Now you can do whatever you want with the "user"
// For instance, update name field in the layout...
nameTextView.setText(user.getName);
...
}
}
Second Way
If you need to notify an instance of another class, you can pass a listener to the function as parameter and then call a method in that listener as a way of notifying the caller. An example caller would look like as follows:
class Caller {
...
private void someFunction() {
...
String userId = 1; // Get user id somehow
DatabaseUtil.findUserById(userId, new DatabaseUtil.Listener() {
#Override
public void onUserRetrieved(User user) {
// Now you can do whatever you want with the "user"
}
});
...
}
}
whereas your static function may reside in a class as follows:
class DatabaseUtil {
public static void findUserById(#NonNegative int id, Listener listener) {
FirebaseDatabase.getInstance().getreference("user")
.orderByChild("id")
.equalTo(id)
.limitToFirst(1)
.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
User user = dataSnapshot.getValue(User.class);
listener.onUserRetrieved(user);
}
...
});
}
interface Listener {
void onUserRetrieved(User user);
}
}

Related

How to cut down repeated Firebase Listener

There are ten activity java code, seven activity need to firebase data. so i added firebaseListener(addChildEventListener). Because data is updated in each activity, each activity need to each Listener.
In my mind, it can work just one code...(because many people will say this is redundancy)
service, thred..? what i have to use.
mDatabase.child("Room-List").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
String key = dataSnapshot.getKey();
if(key.equals(roomName)) {
room = dataSnapshot.getValue(Room.class);
gap = room.gap;
nextTime = room.nextTime;
gameMode = room.gameMode;
break;
}
}
}
#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) { }
});
//Member-List - nickName, online, state, position
mDatabase.child("Room-List").child(roomName).child("Member-List").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
AllnickName = "";
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
Person person = dataSnapshot.getValue(Person.class);
if(person.online) {
online++;
AllnickName += person.nickName;
break;
}
}
TextView_person.setText(AllnickName);
TextView_roomName.setText(roomName + online);
}
#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) { }
});
}
There is no need for a Service or Tread to do this. When your app start you can spin up a Singletons in Android. In the Singleton you can host the ChildEventListener code and it can be accessed by any Activity who need the ChildEventListener Data.
If your Activity closes and restarted the Singleton will not be affected by that.
What is the purpose of Singleton?
The purpose of the Singleton class
is to control object creation, limiting the number of objects to only
one. The singleton allows only one entry point to create the new
instance of the class.
Since there is only one Singleton instance, any instance fields of a
Singleton will occur only once per class, just like static fields.
Singletons are often useful where you have to control the resources,
such as database connections or sockets.
If user or Android system closes your app the ChildEventListener and Singleton is also killed until user start your app again. If you need the ChildEventListener to be auto restarted in this case and so to speak "always be alive" you have to use a [Android Service][2]

Why onChildAdded is fired multiple times?

I have a problem with my code, I don't know if I get it because of onChildAdded or RecyclerView
Simply I want to display messages Inbox on RecyclerView that contains all messages I received from other users, each message contains the last message sent and information about senders such as his name and photo.
Like this
This is my structure
Messages
Receiver_UID
Sender_UID
push
message : "text"
I used 2 nested query to achieve that
so firstly I get sender UID, and then I get the last message from another query
dataQuery = FirebaseDatabase.getInstance().getReference("Messages").child(my_Id);
dataQuery.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot getalldata, String s) {
final String sender_UID = getalldata.getKey();
Query lastmess = FirebaseDatabase.getInstance().getReference("Messages").child(my_Id).child(sendUID);
lastmess.orderByKey().limitToLast(1).addChildEventListener(new ChildEventListener() { // last message
#Override
public void onChildAdded(DataSnapshot snap, String s) {
MessModel messages = snap.getValue(MessModel.class);
String Last_message = messages.getMessage();
getUserData(Last_message ,sender_UID);
}
#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) {
}
});
}
#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) {
}
});
And finally I get information of sender by this method
private void getUserData(final String last_message , String sendUID) {
FirebaseDatabase.getInstance().getReference("Users").orderByKey().equalTo(sendUID).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(final DataSnapshot data, final String s) {
listImessagesitem model = data.getValue(listImessagesitem.class);
name =model.getName();
uid = model.getUid();
//another information
result.add( new listImessagesitem( name ,last_message ,uid, ... another info));
useradapter = new listMessagesAdapter(getActivity(),result);
myList.setAdapter(useradapter);
useradapter.notifyDataSetChanged();
}
#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) {
}
});
}
It works well the first time and when I make refresh as well
The problem is when someone, in the list of messages Inbox, sends me a new message. In this case, if I didn't make refresh, I see two senders with the same information and different last messages ... If he sent again, I see 3 senders with same previous case and so on.
How can I fix it?
I mean How can I add the new message to the user if he already exists in my inbox list
Any help would be appreciated, Thanks
What I understand from looking at your code is that u have nested ChildEventListener's. So every-time the top listener is invoked a new inner child listener is created causing duplicate data as it calls the getUserData method to update the adapter.
What you can do?
1: Check if the result list contains the object if not then add otherwise ignore.
2: From what I understand, I believe you are trying to create a Mail Client application where two users are sending emails to each other. So instead of the structure that you have in your db why not create a single node for both the users something like this user_1_ID+user_2_ID .
This reduces the complexity as both the users will read from the same node and the message object should have a timestamp field to determine the latest message.

Retrieve Random Object from Firebase Android

I want to be able to return random objects from the following image:
And not just the first object (-Kci1vM1dVBYBcPW7QA) which returns as is already. I have inserted the code from my app where it is currently reading from. The variables one, two and three are currently reading the first object but I want them to be able to retrieve random objects.
public void displayDeals(){
databaseReference.child("FruitDeals").child("bR4sR4flMkYFrw1SzuWA8hpOnY52").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
deals_information = dataSnapshot.getValue(Deals_Information.class);
one = deals_information.getDeal();
two = deals_information.getPrice();
three = deals_information.getAisleNum();
}
#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) {
throw databaseError.toException();
}
});
}

Altering Firebase reference depending on whether a node has child or not before loading data

I am trying to set my Firebase reference before my child listener kicks in and loads my data. I know onCreate is ahead of onResume but my code below seems to contradict it as my reference is still what I have set in my onResume(). It seems like what I set up in onCreate doesn't go before what I have in onCreate().
Why is that?
I am trying to read from a template in my database if another node doesn't have the user registered as a child yet.
Any hint would be appreciated.
p.s. I have logged out the references and the Log in OnResume() goes first as well.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.services_activity);
app = FirebaseApp.getInstance();
database = FirebaseDatabase.getInstance(app);
auth = FirebaseAuth.getInstance(app);
storage = FirebaseStorage.getInstance(app);
username = auth.getCurrentUser().getUid();
databaseRef = database.getReference("serv_hst");
servTempltRef = database.getReference("serv_tmplt");
databaseRef.child(username).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
//I am trying to set my reference that I will use in OnResume() ..!!
if (dataSnapshot.hasChildren()) {
servTempltRef = database.getReference("serv_hst");
}
}
#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) {
}
});
}
#Override
protected void onResume() {
super.onResume();
servTempltRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
}
#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) {
}
});
The code inside the onChildAdded() will be executed asynchronously only when the data will be downloaded from Firebase Database.
So, after that the execution flow will execute the line in which there is the .addChildEventListener() method, it will go ahead and will continue to execute the next lines...
In your case, the onCreate() has no other lines to be executed. So, due to the Activity lifecicle, the onResume() method will be executed without the data you need.

Android: Firebase ChildEventListener() not working

I am working in my app with Firebase and I tried to use onChildAdded() callback but I think I am doing something wrong because I get no response.
/**
* Constructor
*/
private FirebaseManager(Context context) {
Firebase.setAndroidContext(context);
Firebase.getDefaultConfig().setPersistenceEnabled(true);
mFirebaseRef = new Firebase(FIREBASE_URL);
}
public void checkUsers() {
Firebase checkRef = mFirebaseRef.child("/data/users/");
// Also tried
// Firebase checkRef = mFirebaseRef.child("data").child("users");
checkRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Log.d(TAG,"New child added");
}
#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(FirebaseError firebaseError) {
}
});
}
In onCreate() of my MainActivity I authenticate the user and the call checkUsers(). After that I manually add a new user in database. But I get nothing in log.
This is the json structure:
What am I doing wrong?
I got it. There was a concurrency problem. I called checkUsers() in onCreate() of the MainActivity but it needs to be called in onAuthenticated(), because the user was authenticated after the method checkUsers() tried to set listeners.
I got a LOG about the failure of accessing database:
W/SyncTree: Listen at / failed: FirebaseError: Permission denied
but didn't seen it because I was following a specific TAG with logcat Search.

Categories

Resources