I have a code for change messageText from database entry:
#Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.edit:
AdapterView.AdapterContextMenuInfo tm = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
int position = tm.position;
final DatabaseReference ref = adapter.getRef(position);
ref.child("messageUserId").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (FirebaseAuth.getInstance().getCurrentUser().getUid().equals(dataSnapshot.getValue().toString())) {
ref.child("messageText").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
input.setText(dataSnapshot.getValue().toString());
sendMessage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ref.child("messageText").setValue(input.getText().toString());
input.getText().clear();
Toast.makeText(Chat.this, "Изменено", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
break;
}
return false;
}
Code ref.child("messageText").setValue(input.getText().toString()) works excellent, but after it code starts up again from
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
input.setText(dataSnapshot.getValue().toString());
And everything goes in a circle - the data from messageText is inserted into the EditText input and I can again change the text.
How to stop executing code after first changing messageText?
ValueEventListener's onDataChange() method:
This method will be called with a snapshot of the data at this location. It will also be called each time that data changes.
With other words, even if it is a write, an update or even a delete operation, this method is triggered. This is also happening in your case, you're using the same reference ref.child("messageText") to add data and also to listen for changes and that's why you have this behaviour. This is happening over and over again. To solve this, you need to change the logic of your code, by creating two different events. onClick to write the data to the database and attach the listener so it cannot be related to that event.
Right code:
#Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.edit:
AdapterView.AdapterContextMenuInfo tm = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
int position = tm.position;
editText = adapter.getRef(position);
editText.child("messageUserId").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (FirebaseAuth.getInstance().getCurrentUser().getUid().equals(dataSnapshot.getValue())) {
editText.child("messageText").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
input.setText(dataSnapshot.getValue().toString());
editMessage();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
} else {
Toast.makeText(Chat.this, "Запрещено", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
return true;
}
private void editMessage() {
sendMessage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
editText.child("messageText").setValue(input.getText().toString());
Toast.makeText(Chat.this, "Изменено", Toast.LENGTH_SHORT).show();
input.getText().clear();
sendMessage();
}
});
}
private void sendMessage() {
sendMessage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (input.getText().toString().trim().equals("")) {
Toast.makeText(Chat.this, getString(R.string.edittext_null), Toast.LENGTH_SHORT).show();
} else {
FirebaseDatabase.getInstance()
.getReference()
.push()
.setValue(new ChatMessage(input.getText().toString(),
Objects.requireNonNull(FirebaseAuth.getInstance().getCurrentUser()).getDisplayName(),
FirebaseAuth.getInstance().getCurrentUser().getUid(),
payload,
avatar,
uploadedAttach
));
input.setText("");
}
}
});
}
It was necessary to simply return to the button its original action and use addListenerForSingleValueEvent instead addValueEventListener.
Related
I have two tables - cartOrders and placedOrders. cartOrders is used to add products to cart, and placedOrders is activated when the user presses "Place Order" button.
I need to copy data from cartOrders to placedOrders when the user clicks the "Place Order" button, but I'm not able to do so.
cartDatabase = FirebaseDatabase.getInstance().getReference("cartOrders");
cartQuery = cartDatabase.child(orderID).orderByChild("productQuantity").startAt(1);
placedOrdersDatabase = FirebaseDatabase.getInstance().getReference("placedOrders");
placedOrderQuery = placedOrdersDatabase.child("orderID");
placeOrderButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
cartDatabase.child(orderID).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
//Logic to add data to data to placedOrders.
String name = dataSnapshot.child("productName").getValue(String.class);
System.out.println("ProductName: " + name);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Intent intent = new Intent(getApplicationContext(), OrderPlacedActivity.class);
intent.putExtra("ORDER_ID", orderID);
startActivity(intent);
}
});
In the code, I was checking if the code is picking up the data from the database, but it wasn't. The output is null. Both the tables have the same structure.
Any help will be appreciated.
Thanks!
My cartOrders table structure:
cartOrders:
----------OrderID:
-----------------ProductID:
---------------------------ProductID:
---------------------------ProductName:
---------------------------ProductPrice:
---------------------------ProductQty:
#Alex Mamo answered this question on a different question.
private void copyRecord(Query fromPath, final DatabaseReference toPath) {
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
toPath.setValue(dataSnapshot.getValue()).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isComplete()) {
System.out.println("Complete");
} else {
System.out.println("Failed");
}
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
fromPath.addListenerForSingleValueEvent(valueEventListener);
}
The code works fine.
Link:Moving or copying data from one node to another in firebase database
I am trying to update my mcustDelivery status, from "Accept" to "Enroute" in Firebase after user press enroute button.
but whenever, I press enroute button, the firebase change to "Enroute" and immediately changes back to "Accept".
This is my setOnClickListener for enroute button.
OrderStatus.Java
enroute.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mDatabase.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
dataSnapshot.getRef().child("mcustDeliveryStatus").setValue("Enroute");
enroute.setImageResource(R.drawable.greenenroute);
deliver.setImageResource(R.drawable.bluedeliver);
enroute.setMaxWidth(266);
enroute.setMaxHeight(150);
deliver.setMaxWidth(266);
deliver.setMaxHeight(150);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
this below code is where i get the the Accepted status on ViewNewOrder.java
accept.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mDatabase.child(getKey()).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
dataSnapshot.getRef().child("mcustDeliveryStatus").setValue("Accepted");
Intent orderStatus = new Intent(ViewOrderRequest.this, orderStatus.class);
startActivity(orderStatus);
Toast.makeText(getApplicationContext(),"notification sent to customers",Toast.LENGTH_LONG).show();
//start new activity show root map
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(getApplicationContext(),"not updates",Toast.LENGTH_LONG).show();
}
});
}
});
It's simple you have used addValueEventListener for accepting the request you are changing the value in the same reference. So the addValueEventListener triggered up and again change the value to accept. For writing, data refer firebase docs for read and write
private DatabaseReference mDatabase;
mDatabase = FirebaseDatabase.getInstance().getReference();
mDatabase.child(getKey()).child("mcustDeliveryStatus").setValue("Accepted")
or simple fix change that addValueEventListener to addListenerForSingleValueEvent
I want to generate a report pdf counting on total Orders and orders with status wanted
I have this code to create pdf and fill table out
private TemplatePDF templatePDF;
FirebaseDatabase database;
DatabaseReference reference;
Button btnRatio1;
ArrayList<String[]> rowqa=new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reportes);
database=FirebaseDatabase.getInstance();
reference=database.getReference("Requests");
btnRatio1=findViewById(R.id.Quality);
btnRatio1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
reference.orderByChild("date").startAt("1530002755582").endAt("1530504865654").
addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
showData(dataSnapshot);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
createTemplate(rowqa);
}
});
}
private void showData(DataSnapshot dataSnapshot){
int total=(int)dataSnapshot.getChildrenCount();
int count=0;
String[]row;
for (DataSnapshot myDataSnapshot : dataSnapshot.getChildren())
{
Request rq = myDataSnapshot.getValue(Request.class);
if (rq.getStatuscali().equals("0"))
{
count++;
}
}
row= new String[]{Common.getDate(Long.parseLong("1529945980802")),String.valueOf(count),String.valueOf(total),""+ count/total};
addRow(row);
}
private void createTemplate(ArrayList<String[]> rowqa) {
TemplatePDF templatePDF1 = new TemplatePDF(getApplicationContext());
templatePDF1.openDocument("Quality");
templatePDF1.addTitles("Frutifelles E.I.R.L.","Calidad de pedidos generados","25/06/2018");
templatePDF1.createTable(header,rowqa);
templatePDF1.closeDocument();
templatePDF1.viewPDF();
}
private void addRow(String[]row){
rowqa.add(row);
}
The first time show me my pdf this way
But the second time show me correctly
It seems like first time it doesn't work
just as #Jen Person said, you should put the createTemplate(rowqa) inside the onDataChange callback, else when you click the button at the first time, the rowqa is empty, so createTemplate(rowqa) will get an empty PDF.
an example:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reportes);
btnRatio1=findViewById(R.id.Quality);
btnRatio1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// dateStart, dateEnd should be instance fields
queryData(dateStart, dateEnd);
}
});
}
private void queryData(String dateStart, String dateEnd) {
database=FirebaseDatabase.getInstance();
reference=database.getReference("Requests");
reference.orderByChild("date")
.startAt(dateStart)
.endAt(dateEnd)
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
showData(dataSnapshot);
createTemplate(rowqa);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
i made my app with like button, now i would add the like counter...but i'm confused. you can help me? how can i add the like counter?
i have 2 functions:
first
viewHolder.mLikeBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mProcessLike = true;
if(mProcessLike){
mDatabaseLike.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (mProcessLike) {
if (dataSnapshot.child(post_key).hasChild(mAuth.getCurrentUser().getUid())) {
mDatabaseLike.child(post_key).child(mAuth.getCurrentUser().getUid()).removeValue();
mProcessLike=false;
} else {
mDatabaseLike.child(post_key).child(mAuth.getCurrentUser().getUid()).setValue("RandomValue");
mProcessLike=false;
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
}
second (it's for change the colour of the button)
public void setLikeBtn(final String post_key){
mDatabaseLike.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.child(post_key).hasChild(mAuth.getCurrentUser().getUid())){
mLikeBtn.setImageResource(R.mipmap.likepieno);
}else{
mLikeBtn.setImageResource(R.mipmap.likevuoto);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
a2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//below
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
ref.addListenerForSingleValueEvent(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(com.google.firebase.database.DataSnapshot dataSnapshot) {
ra2 = dataSnapshot.child("a2").getValue(String.class);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//fetching face value
ref.addListenerForSingleValueEvent(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(com.google.firebase.database.DataSnapshot dataSnapshot) {
rface = dataSnapshot.child("face").getValue(String.class);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//fetching nothingdb which is equals to "zero" in Firebase by default.
ref.addListenerForSingleValueEvent(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(com.google.firebase.database.DataSnapshot dataSnapshot) {
nothing = dataSnapshot.child("nothingdb").getValue(String.class);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//fetching addeddb which is equals to "one" in Firebase by default.
ref.addListenerForSingleValueEvent(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(com.google.firebase.database.DataSnapshot dataSnapshot) {
added = dataSnapshot.child("addeddb").getValue(String.class);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//starting if condition
if (ra2==nothing){
if (rface==nothing){
a2.setBackgroundResource(R.drawable.rounded);{
Firebase refChild = ref2.child("a2");
refChild.setValue("rounda2");
refChild = ref2.child("face");
refChild.setValue("one");
}
else if (rface==added) {
a2.setBackgroundResource(R.drawable.crossed);
{
Firebase refChild = ref2.child("a2");
refChild.setValue("crossa2");
refChild = ref2.child("face");
refChild.setValue("zero");
}
}
}
});
}
});
I am trying to use the above written code so that once I click on the button the background image of the button is changed based on the data present in the Firebase but the If Condition is not working for reason.
It just ignores if (ra2==nothing){ and also the next if conditions.
The listener onDataChange() callbacks are asynchronous. ra2, nothing, added, and rface will not contain valid results when you compare them for equality because the onDataChange() methods will not yet have executed. This answer to a related question explains the execution order in more detail.
In addition, to compare Strings for equality you cannot use the == operator. You must use the equals() method or TextUtils.equals().
#qbix's answer is true, your if condition actually work but it does not receive the value of ra2, rface, nothing, and added yet.
Also, why should you create 4 different ValueEventListener while you listening to the same reference? You can use just 1 listener then put your if condition inside onDataChange, like this:
a2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
ra2 = dataSnapshot.child("a2").getValue(String.class);
rface = dataSnapshot.child("face").getValue(String.class);
nothing = dataSnapshot.child("nothingdb").getValue(String.class);
added = dataSnapshot.child("addeddb").getValue(String.class);
//starting if condition
if (ra2.equals(nothing)) {
if (rface.equals(nothing)) {
a2.setBackgroundResource(R.drawable.rounded);
Firebase refChild = ref2.child("a2");
refChild.setValue("rounda2");
refChild = ref2.child("face");
refChild.setValue("one");
} else if (rface.equals(added)) {
a2.setBackgroundResource(R.drawable.crossed);
Firebase refChild = ref2.child("a2");
refChild.setValue("crossa2");
refChild = ref2.child("face");
refChild.setValue("zero");
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, "onCancelled", databaseError.toException());
}
});
}
});