I have put a button in my App. When I press the button +1 value saves to my database. So I want to check a method that when the button count =5 show an alert.It checks when i click the button. When my button count =5 alert shows 3-4 times. But I want to show it for 1 time :(
Here is the code :
private void ButtonChecker(){
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference ezzeearnRef = rootRef.child(User1);
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Long BRef1 = dataSnapshot.child("BRef").getValue(Long.class);
assert BRef1 != null;
int x = BRef1.intValue( );
ref = x;
if (x ==5){
showAlert("Don't CLick Button ");
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
ezzeearnRef.addValueEventListener(eventListener);
}
You're registering a new listener every time that the user presses the button. If the initial value is 3, the user has to press the button twice to get it to 5. That means your code registers two listeners and thus shows two alerts.
Two solutions:
Only register a listener once.
Register listeners that only get the current value.
Register listeners that only get the current value
This is the simplest change: we'll register a listener that:
Reads the current value
Automatically unregisters itself
The only change is how you register the listener:
ezzeearnRef.addListenerForSingleValueEvent(eventListener);
But this still registers/unregisters a listener for every click, which can be a bit wasteful. In addition: if you ever make your app multi-user, this misses the fact that other users may be incrementing the counter too.
Only register a listener once
Whenever possible, register and unregister your listeners in activity-lifecycle methods. For example, it is quite common to register the listeners in onStart and unregister them in onStop:
#Override
protected void onStart() {
super.onStart();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference ezzeearnRef = rootRef.child(User1);
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Long BRef1 = dataSnapshot.child("BRef").getValue(Long.class);
assert BRef1 != null;
int x = BRef1.intValue( );
ref = x;
if (x ==5){
showAlert("Don't CLick Button ");
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
};
ezzeearnRef.addValueEventListener(eventListener);
}
#Override
protected void onStop() {
super.onStop();
ezzeearnRef.removeEventListener(eventListener);
}
With this code your listener will be active during the lifecycle of the activity. During that time, if the counter (is or) becomes 5, the alert will show once.
Sometime firebase call for data multiple time so you will get same x value more then one time. to fix this use a boolean variable which store value about alert.
boolean isAlertShown = false;
private void ButtonChecker(){
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference ezzeearnRef = rootRef.child(User1);
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Long BRef1 = dataSnapshot.child("BRef").getValue(Long.class);
assert BRef1 != null;
int x = BRef1.intValue( );
ref = x;
if (x ==5 && !isAlertShown){
isAlertShown = true;
showAlert("Don't CLick Button ");
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
ezzeearnRef.addValueEventListener(eventListener);
}
Related
i noticed that my app uses alot of memory so i used the profiler and found that as soon as the app starts and splash screen appear the app get over 150+MB even on splash before opening main or anyother activity.
Update: i solved all memory leaks, yet my app still my app uses on my real phone nearly 300+ MB of ram just while browsing the MainActivity with recycleview.
LeakCanary and i keeps giving me error that this is a cause of memory leaks so anyone please tell me how to solve it >
if you clicked any recyclerview items:
[]
Activity Code:
public class WorkDetailsActivity extends AppCompatActivity {
ArrayList<String> imagesFromURL = new ArrayList<String>();
ActivityWorkDetailsBinding binding;
DatabaseReference databaseReference;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityWorkDetailsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
String workUid_details = getIntent().getExtras().getString("UID_Details");
String title = getIntent().getExtras().getString("name");
String description = getIntent().getExtras().getString("description");
String location = getIntent().getExtras().getString("location");
String path = getIntent().getExtras().getString("path");
databaseReference = FirebaseDatabase.getInstance().getReference().child("Work").child(path);
databaseReference.child(workUid_details).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
binding.workDetailsTitle.setText(title);
binding.workDetailsDescription.setText(description);
binding.workDetailsLocation.setText(location);
binding.getUIDDetails.setText(workUid_details);
for (DataSnapshot dataSnapshot : snapshot.child("images").getChildren()) {
String value = String.valueOf(dataSnapshot.child("image").getValue());
imagesFromURL.add(value);
//Log.i("Value", String.valueOf(imagesFromURL));
}
initRecyclerView();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
private void initRecyclerView(){
binding.workDetailsImage.setNestedScrollingEnabled(false);
binding.workDetailsImage.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
binding.workDetailsImage.setHasFixedSize(true);
PrivateRecyclerAdapter adapter = new PrivateRecyclerAdapter(this, imagesFromURL);
binding.workDetailsImage.setAdapter(adapter);
binding.progressBar.setVisibility(View.VISIBLE);
/* //Add Divider between recyclerView items
DividerItemDecoration itemDecorator = new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL);
binding.workDetailsImage.addItemDecoration(itemDecorator);
final int radius = getResources().getDimensionPixelSize(R.dimen.radius);
final int dotsHeight = getResources().getDimensionPixelSize(R.dimen.dots_height);
final int color = ContextCompat.getColor(this, R.color.green);
binding.workDetailsImage.addItemDecoration(new DotsIndicatorDecoration(radius, radius * 2, dotsHeight, color, color));
binding.workDetailsImage.setOnFlingListener(null);
new PagerSnapHelper().attachToRecyclerView(binding.workDetailsImage);*/
}
#Override
protected void onDestroy() {
super.onDestroy();
imagesFromURL = null;
binding.workDetailsImage.setAdapter(null);
binding.workDetailsTitle.setText(null);
binding.workDetailsLocation.setText(null);
binding.workDetailsDescription.setText(null);
binding.getUIDDetails.setText(null);
binding.workDetailsImage.setAdapter(null);
}
The problem with the above code is that you are registering value event listener as anonymous implementation. Which will hold the reference of the activity. And based on the LeakCanary stack trace your activity was in destroyed state but due to the listener the activity instance is not being able to be garbage collected and hence it is being leaked. What you need to do is add and remove the listener as below.
Create the instance of ValueEventListener and store it in variable
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
binding.workDetailsTitle.setText(title);
binding.workDetailsDescription.setText(description);
binding.workDetailsLocation.setText(location);
binding.getUIDDetails.setText(workUid_details);
for (DataSnapshot dataSnapshot : snapshot.child("images").getChildren()) {
String value = String.valueOf(dataSnapshot.child("image").getValue());
imagesFromURL.add(value);
//Log.i("Value", String.valueOf(imagesFromURL));
}
initRecyclerView();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
Register it in the onStart method of your activity lifecycle using
#Override
protected void onStart() {
databaseReference.child(workUid_details).addValueEventListener(valueEventListener);
}
Remove the listener in onStop method of your activity lifecycle using
#Override
protected void onStop() {
databaseReference.child(workUid_details).removeEventListener(valueEventListener);
}
Hello so I've been strugging for awhile now. I want to consult someone about my code. I want to apply
a coloring function to my app.
When the person presses the button when it's at its:
GREEN state it updates the value on the database to BEING HOUSEKEPT
YELLOW state when pressed sends READY FOR INSPECTION RoomStatus
RED state when pressed sends READY FOR HOUSEKEEPING RoomStatus
It was working earlier but when I tried to restrict the users that users who are Housekeepers can't access the RED STATE which are for House Keepers, I inserted somewhere in my code where I want to implement it.
I'm going over loops here can somebody tell me where I did wrong?
Here's my code:
Button room1;
private DatabaseReference mFirebaseDatabase, mFirebaseDatabase1, mFirebaseDatabase1room;
private FirebaseDatabase mFirebaseInstance;
private DatabaseReference referenceroom1;
private String roomStat;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_navi_to_scan2);
mFirebaseInstance = FirebaseDatabase.getInstance();
mFirebaseDatabase1 = mFirebaseInstance.getReference("Rooms");
mFirebaseDatabase = mFirebaseInstance.getReference("Users");
mFirebaseDatabase1room = mFirebaseInstance.getReference("Rooms").child("Room1");
referenceroom1 = mFirebaseDatabase1.child("Room1").child("RoomStatus");
room1 = (Button) findViewById(R.id.rm1Btn);
mFirebaseDatabase1.child("Room1").addValueEventListener(new ValueEventListener() { //attach listener
#Override
public void onDataChange(DataSnapshot dataSnapshot) { //something changed!
for (DataSnapshot locationSnapshot : dataSnapshot.getChildren()) {
String location = locationSnapshot.getValue().toString();
if (location.equals("READY FOR HOUSEKEEPING")) {
room1.setBackgroundColor(Color.GREEN);
roomStat = "Green";
} else if (location.equals("BEING HOUSEKEPT")) {
room1.setBackgroundColor(Color.YELLOW);
roomStat = "Yellow";
} else {
room1.setBackgroundColor(Color.RED);
roomStat = "Red";
}
if (roomStat.equals("Green")) {
room1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String message = "BEING HOUSEKEPT";
DatabaseReference reference = mFirebaseDatabase1.child("Room1").child("RoomStatus");
reference.setValue(message);
Intent next1 = new Intent(getApplicationContext(), ReaderActivity3.class);
startActivity(next1);
}
});
} else if (roomStat.equals("Yellow")) {
room1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String message = "READY FOR INSPECTION";
DatabaseReference reference = mFirebaseDatabase1.child("Room1").child("RoomStatus");
reference.setValue(message);
Intent next1 = new Intent(getApplicationContext(), ReaderActivity2.class);
startActivity(next1);
}
});
} else {
room1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String message = "READY FOR HOUSEKEEPING";
DatabaseReference reference = mFirebaseDatabase1.child("Room1").child("RoomStatus");
reference.setValue(message);
Intent next1 = new Intent(getApplicationContext(), ReaderActivity.class);
startActivity(next1);
//I ALSO WANT TO PUT A CONDITION HERE FETCHING userType from Structure
// mFirebaseDatabase = mFirebaseInstance.getReference("Users").child("userKey");
//but doing this would mean that I would have to put a listener inside, would that be okay? I tried when this
//was working at first but it didin't and now the whole thing is not working
}
});
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) { //update UI here if error occurred.
}
});
}
Here's my structure:
Can you help me identify what's the problem with how i implemented this?
I see nothing wrong, try debugging. Android is buggy nowadays, especially when you're connecting to a cloud database. In the left side of the run button the bug shaped one. Debug.
Or maybe you could try to show your location which is your string, to check if you pulled the right info from your database. You can use logs. A guide can be found here
https://developer.android.com/studio/debug/am-logcat.html
I have a textView in my activity - say, "Username". It is supposed to be populated from a Firebase database. I am making the Firebase query in Asynctask so as not to block the activity. However that means that the TextView loads first, before the Firebase query is completely executed.
So what is the best way to refresh this textBox after the Firebase query is executed inside the AsyncTask and the username gets known?
I do not want to showprogressBar and block the activity while the data is being fetched from the database. That would defeat the purpose of doing it in AsyncTask.
Code for the AsyncTask is below
private class CheckUserLoginAndRetrieveDataFromFirebase extends AsyncTask <Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids) {
if (thisAppUser!=null) {
setUserDataForToday();
if (createNewNode) { //This is the first time the User is logging in
createUsersNodesForFirstTime();
}
}
return null;
}
Code for my Firebase Query in the AsyncTask is below
public static void setUserDataForToday() {
setProperDatabaseReference(); //This sets reference to user specific nodes in the database
myRef.child("dashboard").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Dashboard dashboard = dataSnapshot.getValue(Dashboard.class);
if (dataSnapshot.getChildrenCount() > 0) {
createNewNode = false;
if (dashboard.checkIfTodaysDateExistsInDatabase()) {
//An entry for todays date exists in database, so no data change needed
myDashboard = dashboard;
}
I hope this example will help you
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setUserDataForToday();
Log.d("MainActivity", "Process is not blocked");
}
public void setUserDataForToday() {
Log.d("MainActivity", "Called method");
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
database.child("users").child("1").child("name").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
String userName = dataSnapshot.getValue(String.class);
Log.d("MainActivity", "Received value: " + dataSnapshot.getValue());
dataSnapshot.getKey();
TextView textView = (TextView) findViewById(R.id.textUserName);
textView.setText(userName);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d("MainActivity", "DB error: " + databaseError.getMessage());
}
});
}
public void onClick(View v) {
setUserDataForToday();
}
}
If you are working with Android studio click tools>Firebase>Realtime Database and follow instructions. This will get you started. You probably want to click tools>firebase>authentication if you want to have users and if you want only certain users to access certain things configure rules for the database. Frank is correct no need for async task.
sorry I don't speak very well English.
My problem is that in the next fragment of code,
in valueEventListener, not enter, I don't know why, so, I can't getValue of "cantidad" of my realtime database.
The databaseReference get correctly, but when get the line eventValueEventListener = new Value..., not enter in onDataChange() method.
What is the problem?
Thanks.
btnGoToEvent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(auth != null && btnGoToEvent.getText().equals("¡ME APUNTO!")) {
btnGoToEvent.setText("Al final no voy a ir");
databaseReference = FirebaseDatabase.getInstance().getReference().child("Eventos").child(String.valueOf(position));
valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
cantidad = Integer.parseInt(dataSnapshot.child("cantidad").getValue().toString());
cantidad++;
databaseReference.setValue(cantidad);
databaseReference.push().setValue(new User(auth.getEmail()));
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
}else if(auth != null && btnGoToEvent.getText().equals("Al final no voy a ir")){
btnGoToEvent.setText("¡ME APUNTO!");
}else{
Toast.makeText(getApplicationContext(), "Necesita estar registrado para apuntarse", Toast.LENGTH_LONG).show();
}
}
});
All you're doing there is creating a new ValueEventListener. That won't get any callback until you add it to a Reference to listen to.
Maybe you meant to also write this line to set that up?
databaseReference.addValueEventListener(valueEventListener);
My Firebase database structure is:
I want to retrieve the full name of some user, when I have its key.
My code:
public class ProfileActivity extends AppCompatActivity implements View.OnClickListener {
private FirebaseAuth firebaseAuth;
private TextView textView;
private Button logbutton,wantToDeliverButton,lookForButton;
private String userName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
Firebase.setAndroidContext(this);textView = (TextView)findViewById(R.id.textView2);
Firebase usersRef = new Firebase("https://myfirstfirebaseauth.firebaseio.com");
firebaseAuth = FirebaseAuth.getInstance();
if (firebaseAuth.getCurrentUser() == null){
finish();
startActivity(new Intent(this,LoginActivity.class));
}
FirebaseUser user = firebaseAuth.getCurrentUser();
Firebase ref = usersRef.child("User").child(user.getUid());
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
userName = dataSnapshot.getValue(User.class).getFullName();
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
textView.setText("welcome "+userName);
}
}
But it set the textView to null. I try to put Toast inside the onDataChange() method, but it doesn't work. It seems it doesn't even get inside the method.
The line FirebaseUser user = firebaseAuth.getCurrentUser(); is correct because if i'm writing textView.setText("welcome "+ user.getEmail()); - I really get the correct email.
How to solve this? Am I using the correct listener? I don't want to change anything in the database, just retrieve.
Edit: it goes to onCancelled().
You're mixing capabilities from the legacy 2.5.X Firebase SDK (Example: Firebase.setAndroidContext()) and the new 9.X.X SDK (Example: FirebaseAuth.getInstance()). That is almost certainly a recipe for failure. Rework your code to use only the new SDK. The Setup Guide is here.