i have developed an Android app and I used Firebase for authentication, database and storage. In my app there is navigationview and there are 5 6 fragments. For example there is a profile fragment, users can change personal information in there, but after save button profile fragment is crashing and app is going back to HomePageActivity. There is same problem on uploading images in a activity. Users upload some wound photos, from an activity ,which is reached from a fragment. However after uploading photo to the storage and sending information to database activity is crashing and app is going back to HomePageActivty. I used both addValueEventListener and addListenerForSingleValueEvent, but problem is not been solved. Could you help me?
Here is a example:
btnSave.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
save();
bringInfo();
Toast.makeText(ProfilActivity.this,"Info changes is saved.",Toast.LENGTH_LONG).show();
}
});
private void save() {
myRef.child("kullanicilar").child(firebaseUser.getUid())
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, Object> postValues = new HashMap<String,Object>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
postValues.put(snapshot.getKey(),snapshot.getValue());
}
postValues.put("ad", (etNameH.getText().toString()).substring(0,1).toUpperCase()+(etNameH.getText().toString()).substring(1));
postValues.put("soyad", (etSurnameH.getText().toString()).substring(0,1).toUpperCase()+(etSurnameH.getText().toString()).substring(1));
postValues.put("hastane", etCalistigiKurumPr.getText().toString());
myRef.child("kullanicilar").child(firebaseUser.getUid()).updateChildren(postValues);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
}
);
}
private void bringInfo() {
myRef.child("kullanicilar")
.child(firebaseUser.getUid()).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
user = dataSnapshot.getValue(Users.class);
etNameH.setText(user.getAd());
etSurnameH.setText(user.getSoyad());
etCalistigiKurumPr.setText(user.getHastane());
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
remove calling bringInfo() from btnSave. OnClickListner method and put under onDataChange method try this
public void onClick(View v) {
save();
// bringInfo() remove from here
Toast.makeText(ProfilActivity.this,"Info changes is
saved.",Toast.LENGTH_LONG).show();
}
public void onDataChange(DataSnapshot dataSnapshot) {
// *****Remaining Code*****
bringInfo() put it here
}
Related
I am creating an android app using firebase. My firebase database structure is as follow-
Users:{
uid:{
name:Bruno,
age: 22,
email: bruno#gmail.com,
address:...
}
},
Level_info:{
uid:{
score:70,
level:5
}
}
Before Rxjava, I retrieve all users like this-
userRef.addValueEventListener(new ValueEventListerner(){
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(Datasnapshot snapshot:dataSnapshot.getChildren())
{
User user = snapshot.getValue(User.class);
userList.add(user);
//to get score and levels
/*I can't add nested value event listener directly because of Asynchronous behavior */
userId.add(user.getId());
}
getLevels(userId);
}
#Override
public void onCancelled(DatabaseError error) {
//handle errors
}
});
void getLevels(final ArrayList<String> userid){
levelRef.addValueEventListener(new ValueEventListener(){
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(String id:userid)
{
Level level = dataSnapshot.child(id).getValue(Level.class);
levelList.add(level);
}
/** Attch both "userList" and "levelList" to RecyclerView */
}
#Override
public void onCancelled(DatabaseError error) {
//handle errors
}
});
}
It goes fine.But if there are many nested Listeners, It will hard to read.So I tried to change to RxJava and RxAndroid. Like this-
public Observable<ArrayList<User>> userOb(){
return Observable.create(new
ObservableOnSubscribe<ArrayList<User>>() {
#Override
public void subscribe(final
ObservableEmitter<ArrayList<User>> emitter)
throws Exception {
FirebaseDatabase.getInstance().getReference("Users")
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
ArrayList<UserModel> listUsers;
for(DataSnapshot snapshot: dataSnapshot.getChildren()){
User user = snapshot.getValue(User.class);
listUsers= new ArrayList<>();
listUsers.add(user);
emitter.onNext(listUsers);
}
emitter.onComplete();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
}
Here I don't know how to zip with LevelObservable because levelObservable need UserId from UserObservable to get data from Levels/(uid)/"level_info" .May be this is stupid question but I am new to RxJava. I want to get Corresponding userId from UserObservable to LevelObservable. So how can I do that?
Sorry for my bad English Writing skill.
Edit: Is there some ways to implement like this (because may be I miss some easy ways to implement).
In my code, when user click on a button, it calls a function.In that function data has to loaded from firebase. On successful of loading, Intent will pass to another activity with some putExtra data.
SharedPreferences pref = getApplicationContext().getSharedPreferences("My_pref", MODE_PRIVATE);
choice = pref.getInt("language", 0);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(choice==1)
{
firebase("param1","param2","English");
}
if(choice==2)
{
firebase("param1","param2","hindi");
}
}
});
public void firebase(String files,String titles,String language)
{
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference(language);
DatabaseReference myRef1=myRef.child(titles);
DatabaseReference myRef2=myRef.child(files);
myRef1.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
language_title = dataSnapshot.getValue(String.class);
t=1;
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
myRef2.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
language_file= dataSnapshot.getValue(String.class);
f=1;
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
if(t==1&&f==1) {
Intent i = new Intent(getApplicationContext(), caf.class);
i.putExtra("titles", language_title);
i.putExtra("files", language_file);
startActivity(i);
}
}
But in that case intent is only passing when I click twice.In single click Intent is not passing. where is the problem?
Any code that needs data from the database, needs to be inside the onDataChange method or be called from there.
See my answer here for a longer explanation: getContactsFromFirebase() method return an empty list.
Since you have two onDataChange methods, you'll need to make sure both have been called before starting the new activity. Using some simple flag variables to track state, you can do that with:
Declare two member fields:
boolean isTloaded, isFLoaded;
And then
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference(language);
DatabaseReference myRef1=myRef.child(titles);
DatabaseReference myRef2=myRef.child(files);
isTloaded = false;
isFloaded = false;
myRef1.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
language_title = dataSnapshot.getValue(String.class);
t=1;
isTloaded = true;
if (isTloaded && isFloaded) {
startCafActivity();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // never ignore errors
}
});
myRef2.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
language_file= dataSnapshot.getValue(String.class);
f=1;
isFloaded = true;
if (isTloaded && isFloaded) {
startCafActivity();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // never ignore errors
}
});
And then finally:
private void startCafActivity() {
if(t==1&&f==1) {
Intent i = new Intent(getApplicationContext(), caf.class);
i.putExtra("titles", language_title);
i.putExtra("files", language_file);
startActivity(i);
}
}
It might be even simpler, but I had a hard time figuring out your application logic due to the variable names. Consider using more descriptive named than t, f and caf to make it easier for others (and your future self) to understand what each part of the code does in isolation.
I fetched data from firebase database, inside OnDataChange method I want to perform another query based on the data I fetched previously. Before going to another activity I fetched all my data using a callback function MyCallback. Here listAllRequest contains expected data but userMap contains null. How can I ensure userMap contains data before going to another activity?
public void readRequestData(final Outgoing.MyCallback myCallback) {
groupDatabase = FirebaseDatabase.getInstance().getReference("Users").child(user.getUid()).child("outgoing");
userInfoRef= FirebaseDatabase.getInstance().getReference("UserInfo");
groupDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
listAllRequest.clear();
for(DataSnapshot childSnapshot: dataSnapshot.getChildren())
{
final BookRequestData bookRequestData = childSnapshot.getValue(BookRequestData.class);
listAllRequest.add(bookRequestData);
userInfoRef.child(bookRequestData.getOwnerId()).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
User user=dataSnapshot.getValue(User.class);
userMap.put(bookRequestData.getReqId(),user);
Log.e("outgoing",user.getName());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
myCallback.onCallback(listAllRequest);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {}
});
}
I want to read data offline for my users, but Persistance mode will make OnDataChange in ValueEventListener call twice. how can I prevent it. I need to use ValueEvent for my own purpose. someone help me please.
Update : I am making a friend suggestions list for users in my app, the suggested user must dont have any relationship with the current user. and this is my code ( I use Persistance for offline data as Firebase's suggestion)
valueEventListener_check_relationship=new ValueEventListener() {
#Override
public void onDataChange(#NonNull final DataSnapshot dataSnapshot_root) {
num_fiend_req=0;
num_sent_req=0;
update_badges(num_sent_req,tv_badges_sent_req);
update_badges(num_fiend_req,tv_badges_friend_req);
arrayList_suggestions.clear();
adapter_suggestions.notifyDataSetChanged();
GlobalConstants.ROOT_REF.child(GlobalConstants.CHILD_USERS)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot snapshot:dataSnapshot.getChildren()){
Object_User user_suggested=snapshot.getValue(Object_User.class);
if(!user_suggested.user_id.equals(GlobalConstants.getMyUID())){
if(!dataSnapshot_root.hasChild(user_suggested.user_id))
addToList(user_suggested);
else {
RemoveUserFromlist(user_suggested);
if (dataSnapshot_root.child(user_suggested.user_id)
.hasChild(GlobalConstants.CHILD_REQUESTING)){
String values=dataSnapshot_root.child(user_suggested.user_id)
.child(GlobalConstants.CHILD_REQUESTING)
.getValue().toString();
if (values.equalsIgnoreCase(GlobalConstants.VALUE_REQUESTING_SENDER))
num_sent_req++;
else num_fiend_req++;
}
update_badges(num_sent_req,tv_badges_sent_req);
update_badges(num_fiend_req,tv_badges_friend_req);
adapter_suggestions.notifyDataSetChanged();
}
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
GlobalConstants.ROOT_REF.child(GlobalConstants.CHILD_RELATIONSHIP)
.child(GlobalConstants.getMyUID()).keepSynced(true);
GlobalConstants.ROOT_REF.child(GlobalConstants.CHILD_RELATIONSHIP)
.child(GlobalConstants.getMyUID())
.addValueEventListener(valueEventListener_check_relationship);
I have issues on nested queries I'm trying to do using firebase, seems like the first query (activity1) doesn't wait until the second (activity2) and third query (activity3) finished running, this might return NULL value from the first query. Please look at my sample for more understanding, I've been stuck here for days trying all kind of method but it just wont work. :(
Query query_1= reference.child("Users").child("Room")
.child("Profile");
query_1.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//ACTIVITY 1
Query query_2 = reference.child("Users").child(Room)
.child("Receiver").child("id");
query_2.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//ACTIVITY 2
Query query_3 = reference.child("chatrooms").child("Room")
.child("Creator").child("id");
query_3.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//ACTIVITY 3
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});