Как обновить TextView на основе ответа от сервера внутри адаптера RecyclerView после взаимодействия с пользователем? - PullRequest
0 голосов
/ 22 сентября 2019

Я пытаюсь установить, понравился ли пользователю сообщение или нет, прочитав ответ с сервера, соответственно присвоить значение boolean внутри Retrofit.call.enqueue () и изменить значение TextView пользовательского интерфейса на +1, если оно истинно.Как я могу держать значение переменной в нескольких обратных вызовах и обновлять пользовательский интерфейс на его основе после завершения вызова?

В пользовательском интерфейсе у меня есть две кнопки (например, \ dislike) в адаптере RecyclerView, который обновляет данные в базу данных MySQL после нажатия иЯ пытаюсь обновить количество лайков или дислайков после взаимодействия с пользователем (+1, если пользователь еще не проголосовал, что я проверяю с помощью вызова Retrofit).

Я пытался присвоить значение глобальной переменной в классе Adapter, нокод выполняется до завершения вызова (я полагаю, это потому, что Retrofit по умолчанию работает в отдельном потоке).Я также пытался обновить пользовательский интерфейс в AsyncTask в методе onPostExecute () следующим образом:

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");
            }
        }

    }

И результаты:

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

и должны выглядеть (если проголосовали):

1. false
2. true
3. true
4. Triggered
5. true

Я также попытался сделать интерфейс следующим образом:

public interface ResponseListener {

    void onSuccess();

    void onFail();
}

И реализовать его в классе адаптера (onFail (), если не проголосовал):

 @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));
            }
        };

    }

Вот фрагмент кода:

 @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) {

                    }
                });
            }
        });
    }

Как я могу обновить значения TextView после нажатия кнопки на основе ответа Retrofit?

Я слышал, что есть что-то, называемое «Ад обратного вызова», что такоеэто и как эффективно этого избежать?

1 Ответ

2 голосов
/ 22 сентября 2019

Вам не нужны ни глобальные переменные, ни обратные вызовы.

Только что объявлены открытые методы в вашем адаптере, которые просто обновляют список ваших адаптеров.Вам просто нужна позиция обновленного элемента.

Обновление лайков:

public void updateLikes(int pos){
   int iLikes = list.get(position).getPositiveVotes();
   iLikes++;
   list.get(position).setPositiveVotes(iLikes);
   notifyDataSetChanged();  // very important 

}

Обновление не нравится:

public void updateDislikes(int pos){
   int iDislikes = list.get(position).getNegativeVotes();
   iDislikes ++;
   list.get(position).setNegativeVotes(iDislikes);
   notifyDataSetChanged();  // very important 

}

А при вашей модернизации или вызове Aysn просто вызовите эти методы:

adapter.updateLikes(position) or adapter.updateDislikes(position)
...