I have an activity in which I'm getting the data from Firebase database and showing multiple markers on the map. In onMarkerClick, I want the user to go to another activity that have details about the marker that was tapped. On first tap on the marker, it shows the title only and on second tap it goes to the other activity after doing Firebase database query to get the id for that marker so that the correct details will be provided about the tapped marker.
The problem is when I tap on any marker the first time, and then If I click on any other marker, the opened activity opens up the details of the marker that was tapped first.
If I tap on the same marker twice, it works fine. But when I come back to the map activity, tapping on any marker first time, will open up the details for the marker that was previously tapped.
What can be done to do the correct query inside onMarkerClick.
Here's the code.
#Override
public boolean onMarkerClick(Marker marker) {
eventTitle = marker.getTitle();
q = database.getReference("events")
.orderByChild("event_title")
.equalTo(marker.getTitle());
q.addValueEventListener(vel);
Intent intent = new Intent(NearbyEventsActivity.this, EventDetailActivity.class);
Bundle bundle = new Bundle();
bundle.putString("eventid", eventid);
intent.putExtras(bundle);
if (eventid != null) {
startActivity(intent);
}
return false;
}
ValueEventListener vel = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Event e = snapshot.getValue(Event.class);
eventid = e.getEvent_id();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
The problem is when I tap on any marker the first time, and then If I click on any other marker, the opened activity opens up the details of the marker that was tapped first.
Firebase query executes asyncronously. Your ValueEventListener will not be called immediately.
Use your secound Activity start code inside onDataChange method.
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Event e = snapshot.getValue(Event.class);
eventid = e.getEvent_id();
}
Intent intent = new Intent(NearbyEventsActivity.this, EventDetailActivity.class);
Bundle bundle = new Bundle();
bundle.putString("eventid", eventid);
intent.putExtras(bundle);
if (eventid != null) {
startActivity(intent);
}
}
Related
Context:
In my MainActivity I am trying to check if a value exists in the Firebase database, if it exists, it shows HomeActivity, but if it doesn't exist it will do something else. I mean, in the onStart () method, before the MainActivity is displayed and displayed to the user, the condition is checked. And if the condition is true, MainActivity should never be shown to user and HomeActivity is shown.
Problem:
I dont know why this is happening, but, if the value EXIST on firebase Database, my MainActivity is shown a few seconds and then HomeActivity is displayed. And what should happen as clarified above is that HomeActivity is shown to the user directly. I think that the method, addListenerForSingleValueEvent is the problem here, but I wouldn't know why.
Code:
#Override
protected void onStart() {
super.onStart();
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Users").child("Person").child(mAuth.getCurrentUser().getUid());
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot data: dataSnapshot.getChildren()){
if(data.exists()){
Intent intent = new Intent (MainActivity.this, HomeActivity.class);
startActivity(intent);
MainActivity.this.finish();
}else{
FirebaseUser user = mAuth.getCurrentUser();
if(user!=null){
Intent intent = new Intent(MainActivity.this, RegistrarseActivity.class);
startActivity(intent);
}
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
I have a method in my FollowersActivity class getFriendsAttendingEvent(); which returns the number of users that adhere to two specific criteria. Now, those users populate a list when I click on a TextView which I have in my Adapter class PostAdapter.
I need to get that number (quantity) of users that are in the list and I want to put it in the TextView in my PostAdapter class. I want to do something like holder.textView.setText(*list.size()), but how can I get that number from my FollowersActivity over to my PostAdapter class?
I know from the Adapter class I transfer data between the two classes by using Intent, but to go the other way around, would I have to create an interface or something? SharedPreferences perhaps? I don't know...
How would I send this line, String number = String.valueOf(mIdList.size()); over to my PostAdapter? This is the number that I need.
FollowersActivity
private void getFriendsAttendingEvent() {
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Attending Event").child(mPostId);
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
mIdList.clear();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
mIdList.add(snapshot.getKey());
}
DatabaseReference reference1 = FirebaseDatabase.getInstance().getReference("Following").child(mFirebaseUser.getUid());
reference1.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
mIdList1.clear();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
for (String id : mIdList) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (Objects.equals(snapshot.getKey(), id)) {
mIdList1.add(snapshot.getKey());
}
}
}
}
if (mIdList1.size() > 0) {
String number = String.valueOf(mIdList.size());
Log.d("NUMBEROFUSERS", number);
showUsers();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
PostAdapter
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, int position) {
mFirebaseUser = FirebaseAuth.getInstance().getCurrentUser();
final Post post = mPost.get(position);
holder.friendsAttendingEvent.setOnClickListener(v -> {
Intent intent = new Intent(mContext, FollowersActivity.class);
intent.putExtra("id", post.getPostid());
intent.putExtra("postid", post.getPostid());
intent.putExtra("publisherid", post.getPublisher());
intent.putExtra("title", "Friends Attending");
mContext.startActivity(intent);
});
So what I have understood so far is that,
You have a PostAdapter (that displays data related to a post just like in most of the social media applications) and this Adapter has a TextView that represents the number of followers.
So, the navigation structure might be like this:
PostAdpater --- (Click on the TextView) ---> FollowersActivity
By Clicking the TextView representing the number of followers we shift to the FollowersActivity, and there you might be displaying the details of Followers. But the problem is, that you are fetching the data on the FollowersActivity where as you required it before the navigation on the PostAdapter.
The Only Simple Solution that I am able to figure out is that you move your query function getFriendsAttendingEvent() from FollowersActivity to PostAdapter, fetch the count of followers in the adapter and then pass that count to the FollowersActivity through Intent in case you do not want to re fetch data.
PostAdapter -------> FollowersActivity
(count required here) (fetching here)
PostAdapter -------> FollowersActivity
(fetch count here) (pass data here through Intent of refetch it)
Please tell me if didn't understood the problem correctly i might come up with a better solution
firstly, i want to build navigator drawer. i have already call text from firebase but my problem is how to display in nav_header. i dont know how to explain in specific. I want key in first name and last name but i dont know where to call class .i try show my code.
This how i call string from firebase but now i try to display in navigator bar
userDatabase = new UserDatabase();
reff = FirebaseDatabase.getInstance().getReference("Member").child(userid);
reff.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot snap: dataSnapshot.getChildren()){
UserDatabase user = snap.getValue(UserDatabase.class);
txvName.setText(""+user.getFirstName()+" "+user.getLastName());
txvAdd.setText(""+user.getAddress1()+" "+user.getAddress2()+" "+user.getAddress3());
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
that so many xml and that only one of class is sidemenu.class . I dont know where to put the code in sidemenu.class
You can call inside activity which contains Navigation drawer
and add menu item like this
final Menu menu = navigationView.getMenu();
menu.add(user.getFirstName()+" "+user.getLastName());
Is there any way to pull data from firebase where the code is? I currently have valueEventListeners, but they all run after the code below them, thus invalidating the following code. I want to be able to pull a value exactly where the code is, not later.
As of yet, I have not found anything online about this.
A good example of my problems in the code:
public void onItemClick(AdapterView<?> l, View v, final int position, long id) {
FirebaseAuth mAuth = FirebaseAuth.getInstance();
FirebaseUser user = mAuth.getCurrentUser();
final String uid = user.getUid();
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
cCESnapshot = dataSnapshot.child(uid).child("currChallenges").child(challengeList.get(position));
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Intent intent = new Intent();
intent.setClass(this, ChallengeView.class);
intent.putExtra("snapshot", cCESnapshot.toString());
intent.putExtra("name", challengeList.get(position));
startActivity(intent);
}
cCESnapshot is null because the intent runs before the valueEventListener.
The onDataChange() is asynchronous, so the only way to use the retrieved data is inside onDataChange(), example:
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
cCESnapshot = dataSnapshot.child(uid).child("currChallenges").child(challengeList.get(position));
Intent intent = new Intent();
intent.setClass(this, ChallengeView.class);
intent.putExtra("snapshot", cCESnapshot.toString());
intent.putExtra("name", challengeList.get(position));
startActivity(intent);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
This is an asynchronous operation, when the data will arrive, the onDataChange callback will be triggered. Your startActivty code will be executed sequentially and this is why you get no value in cCESnapshot.
Move the startActivity code inside the listener.
But be careful, because each time the onItemClick click listener will be called, you'll add a value event listener. That way, you'll have multiple calls to onDataChange in each click and so multiple startActivities.
Instead, i recommend using addListenerForSingleValueEvent which will be triggered only after a single change in data.
so I'm trying to get users key by their email and the problem is that I dont know inside my code if the query actually found something or not .. so I'm assuming if I'm inside onchildadded that the query is successful and a child has been found so I will pass the key to another activity and stop current activity but when I run the app the whole code get executed .. I feel my way is kinda wrong but I didn't find any way to know if the query is sucsessful or a child is found .... if you have any idea pleas help ...
public void searchemail(String email){
Firebase ref = new Firebase("https://<myfirebase>.firebaseio.com/users");
Query queryRef = ref.orderByChild("Email").equalTo(email);
ChildEventListener listener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
userkey = dataSnapshot.getKey();
homeintent.putExtra("key", userkey);
startActivity(homeintent);
finish();
return;
// I want code to stop here
}}
queryRef.addChildEventListener(listener);
Toast toast = Toast.makeText(this, "email not found", Toast.LENGTH_SHORT); // Im assuming if Im here then no child is found but this always get executed before startactivity
}
OUTPUT :
if email found -> toast will show then home activity will start...
if email not found -> only toast will show..
The methods of a ChildEventListener get called when the relevant event happened. So onChildAdded() will be called when a child has been added. For this reason you cannot easily use a ChildEventListener to detect if a child exists.
The easiest way to detect if a child exists, is to use a ValueEventListener:
public void searchemail(String email){
Firebase ref = new Firebase("https://<myfirebase>.firebaseio.com/users");
Query queryRef = ref.orderByChild("Email").equalTo(email);
ValueEventListener listener = new ValueEventListener() {
#Override
public void onDataChanged(DataSnapshot snapshot) {
if (snapshot.exists()) {
for (DataSnapshot child: snapshot.getChildren()) {
homeintent.putExtra("key", child.getKey());
startActivity(homeintent);
break; // exit for loop, we only want one match
}
}
else {
Toast toast = Toast.makeText(this, "email not found", Toast.LENGTH_SHORT);
}
}
};
queryRef.addValueEventListener(listener);
}