Reputation: 87
I am running a transaction on click of a layout inside my adapter, but when I click the layout, the transaction runs successfully. But it creates another item inside my RecyclerView
. I tried notifydatasetChanged() inside transaction but it creates an error:
CalledFromWrongThreadException: Only the original thread that created a view
hierarchy can touch its views.
Then I tried putting notifyDataSetChanged() outside the transaction, but it's not working. Below is what I am doing:
holder.follow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
DatabaseReference mWorkDatabase =
FirebaseDatabase.getInstance().getReference()
.child("WorkforWorkMen").child(work_id).child("follower");
mWorkDatabase.runTransaction(new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData
mutableData) {
if(holder.followText.getText().equals("Follow")) {
holder.followText.setText("Following");
FirebaseAuth mAuth = FirebaseAuth.getInstance();
String current_user =
mAuth.getCurrentUser().getUid();
DatabaseReference mFollowingDatabase =
FirebaseDatabase.getInstance().getReference()
.child("WorkFollowing").child(current_user).child(work_id);
final Map fol = new HashMap();
fol.put("follower",work_id);
mFollowingDatabase.setValue(fol);
mutableData.setValue
(Integer.parseInt(mutableData.getValue().toString()) + 1);
}
else {
holder.followText.setText("Follow");
FirebaseAuth mAuth = FirebaseAuth.getInstance();
String current_user =
mAuth.getCurrentUser().getUid();
DatabaseReference mFollowingDatabase =
FirebaseDatabase.getInstance().getReference()
.child("WorkFollowing").child(current_user).child(work_id);
mFollowingDatabase.setValue(null);
mutableData.setValue(Integer
.parseInt(mutableData.getValue().toString()) - 1);
}
return Transaction.success(mutableData);
}
@Override
public void onComplete(DatabaseError databaseError,
boolean b, DataSnapshot dataSnapshot) {
Toast.makeText(context,"error on complete"+
String.valueOf(databaseError), Toast.LENGTH_SHORT).show();
Log.i("eror here", "onComplete:
"+String.valueOf(databaseError));
}
});
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "here",
Toast.LENGTH_SHORT).show();
notifyDataSetChanged();
}
});
}
});
i think when i add the data to my list the change in the value of followers cause it to add a new item, i am not sure though
private void loadMessages(){
if(keys.size() == 0){
messagesList.clear();
Toast.makeText(getContext(), " size zero no results found",
Toast.LENGTH_SHORT).show();
}
else {
messagesList.clear();
for (int i = 0; i < 5; i++) {
if (i>=keys.size()){
Toast.makeText(getContext(), "list is less than 5 item",
Toast.LENGTH_SHORT).show();
}
else {
listPos = i;
String id = keys.get(i);
mWorkDatabase.child(id).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
String messageKey = dataSnapshot.getKey();
NewWork message = dataSnapshot.getValue(NewWork.class);
itemPos++;
messagesList.add(message);
mAdapter.notifyDataSetChanged();
mRecyclerView2.scrollToPosition(messagesList.size() - 1);
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
}
}
Upvotes: 3
Views: 1248
Reputation: 1
The Firebase database client, runs all network operations in a background thread. This means that you cannot create
or modify
views within that background thread. You can modify the UI only in the thread where those views were created. However, the thread in which you are allowed to make those changes is the main thread. So what you need to do is to get the following line of code out of the transaction.
notifyDataSetChanged();
Note: The entire view tree is single threaded. So, you must always be on the UI thread when calling any method on any view. If you are doing work on other threads and want to update the state of a view from that thread, you should use a Handler
.
You can find much more here.
Upvotes: 1
Reputation: 907
You are calling notifyDataSetChanged()
from background thread
you need to call it from ui thread
as follows
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
notifyDataSetChanged();
}
});
Upvotes: 1