Issue
I am trying to establish whether the user liked post or not by reading the response from server, assign value to boolean accordingly inside Retrofit.call.enqueue() and change UI's TextView value to +1 if true. How can I hold value of variable inside multiple callbacks and update UI based on it after call finishes?
In the UI I have two buttons(like\dislike) in RecyclerView adapter that updates data to MySQL Database after click and I am trying to update number of likes or dislikes after users interaction (+1 if user did not voted already, which I check via Retrofit call).
I have tried to assign value to global variable in Adapter class but the code runs before call is finished (I assume it's because Retrofit runs in separate thread by default). I have also tried to update UI in AsyncTask in onPostExecute() method like this:
private class LoadDataAsyncTask extends AsyncTask<String, Void, Boolean> {
//variable to be updated based on response
boolean voted = true;
public LoadDataAsyncTask() {
//todo
}
@Override
protected Boolean doInBackground(String... params) {
Log.v("Voted state start", String.valueOf(voted));
GetUserVotes mApiGetUserVotes;
mApiGetUserVotes = ApiUtils.getAPIServiceUserVotes();
mApiGetUserVotes.getVotes().enqueue(new Callback<ResultVotes>() {
@Override
public void onResponse(Call<ResultVotes> call, Response<ResultVotes> response) {
if(response.body().getSuccess()==1)
voted = true;
else
voted = false;
if(!voted){
//todo
} else {
Log.v("Voted", String.valueOf(voted));
//todo
}
}
@Override
public void onFailure(Call<ResultVotes> call, Throwable t) {
}
});
Log.v("Voted state end", String.valueOf(voted));
return voted;
}
@Override
protected void onPostExecute(Boolean result) {
Log.v("Voted state", String.valueOf(result));
if(result) {
//todo
} else {
//update UI TextView to +1 vote
Log.v("onPostExecution", "Triggered");
}
}
}
And results are:
1. V/Voted state start: false
2. V/Voted state end: false
3. V/Voted state: false
4. V/onPostExecution: Triggered
5. V/Voted: true
and should look like (if voted):
1. false
2. true
3. true
4. Triggered
5. true
I have also tried to make Interface like this:
public interface ResponseListener {
void onSuccess();
void onFail();
}
And to implement it in Adapter class (onFail() if not voted):
@Override
public void onBindViewHolder(final NewsViewHolder holder, int position) {
final int iLikes = list.get(position).getPositiveVotes();
final int iDislikes = list.get(position).getNegativeVotes();
final ResponseListener retrofitResponseListener = new ResponseListener() {
@Override
public void onSuccess() {
}
@Override
public void onFail() {
int x = iNegativeVotes + 1;
holder.textViewDislike.setText(String.valueOf(x));
}
};
}
Here is code snippet:
@Override
public void onBindViewHolder(final NewsViewHolder holder, int position) {
final int iLikes = list.get(position).getPositiveVotes();
final int iDislikes = list.get(position).getNegativeVotes();
holder.btnPositive.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final boolean[] voted = {false};
GetUserVotes mApiGetUserVotes;
mApiGetUserVotes = ApiUtils.getAPIServiceUserVotes();
mApiGetUserVotes.getVotes(email, url).enqueue(new Callback<ResultVotes>() {
@Override
public void onResponse(Call<ResultVotes> call, Response<ResultVotes> response) {
if(response.body().getSuccess()==1){
voted[0] = true;
}else{ voted[0] = false; }
if(!voted[0]){
//this is not working
holder.textViewDislike.setText(String.valueOf(x));
} else {
//do not update TextView
}
}
@Override
public void onFailure(Call<ResultVotes> call, Throwable t) {
}
});
}
});
}
How can I update TextView values after button click based on Retrofit response?
I have heard that there is something called 'Callback hell', what is it and how to effectively avoid it?
Solution
You do not need any global variable neither callbacks.
Just declared a public methods in your adapter that simply update your adapter list. You just need the position of updated item.
Update Likes:
public void updateLikes(int pos){
int iLikes = list.get(position).getPositiveVotes();
iLikes++;
list.get(position).setPositiveVotes(iLikes);
notifyDataSetChanged(); // very important
}
Update Dislikes:
public void updateDislikes(int pos){
int iDislikes = list.get(position).getNegativeVotes();
iDislikes ++;
list.get(position).setNegativeVotes(iDislikes);
notifyDataSetChanged(); // very important
}
And on your retrofit or Aysn success call simply call these methods:
adapter.updateLikes(position) or adapter.updateDislikes(position)
Answered By - Muazzam A.
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.