简体   繁体   中英

RecyclerView does not update or refresh when calling notifyDataSetChanged()

IronMax app屏幕截图

I have an app that uses RecyclerView. When user selects "Add New Row" from the options menu, I output a test message to the screen, and some values get appended to two different ArrayLists. That part is working great, as I have confirmed these values are successfully added by looking at the ArrayList values using the debugger.

Anyhow I am not able to get the RecyclerView to redraw the screen and show the new information. My attempt to redraw / update the screen is by using this code (line 78 of MainActivity.java):

//call notify data set changed method for the adapter
  adapter.notifyDataSetChanged();

Maybe I am not calling notifyDataSetChanged on the same adapter that actually is used for RecycleView??

Here is the complete code for MainActivity.java (see options menu code at end):

package com.joshbgold.ironmax;

import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private static final int ADD_ROW = 1;  //used for case statement statement to select menu item
    private RecyclerView recyclerView;
    public Exercises exercises = new Exercises();
    public ExerciseRow adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        assert getSupportActionBar() != null;
        ActionBar actionBar = getSupportActionBar();

        actionBar.setDisplayShowHomeEnabled(true);
        actionBar.setIcon(R.mipmap.barbell);
        actionBar.setTitle("  " + "Iron Max");

        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        //ExerciseRow adapter = new ExerciseRow(this);
        adapter = new ExerciseRow(this);
        recyclerView.setAdapter(adapter);

        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);

        recyclerView.setHasFixedSize(true);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

       /* MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.add_row, menu);
        return super.onCreateOptionsMenu(menu);*/

        menu.add(0, ADD_ROW, 0, "Add New Row");
        menu.getItem(0).setIcon(R.drawable.plus);

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        menu.getItem(0).setIcon(R.drawable.plus);

        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int length;

        switch (item.getItemId()) {
            case 1:
                Toast msg = Toast.makeText(MainActivity.this, "Test code for adding an exercise", Toast.LENGTH_LONG);
                msg.show();

                exercises.addExercise("Some exercise");
                exercises.addPersonalBest(500);
                length = exercises.getExercisesArrayLength();

               //call notify data set changed method for the adapter
                adapter.notifyItemInserted(length - 1);
                adapter.notifyDataSetChanged();

                return super.onOptionsItemSelected(item);


            default:
                return super.onOptionsItemSelected(item);
        }
    }
}

Here is Exercises.java:

import android.support.v7.app.AppCompatActivity;

import java.util.ArrayList;

public class Exercises extends AppCompatActivity {

    public ArrayList<String> exercisesArrayList = new ArrayList<>();  //stores all the lifts

    private ArrayList<Integer> personalBestsArrayList = new ArrayList<>();  //stores personal bests in pounds

    public ArrayList<String> getExercisesArray() {   //returns the whole exercises arraylist
        return exercisesArrayList;
    }

    public ArrayList<Integer> getPersonalBests() {  //returns the whole personal bests arraylist
        return personalBestsArrayList;
    }

    public String getExercise(int position) {  //returns individual exercise from array
        return exercisesArrayList.get(position);
    }

    public void addExercise(String exercise) {
        exercisesArrayList.add(exercise);
    }

    public void removeExercise(int position) {
        exercisesArrayList.remove(position);
    }

    public void editExercise(int position, String exercise) {
        exercisesArrayList.set(position, exercise);
    }

    public int getExercisesArrayLength() {
        return exercisesArrayList.size();
    }


    public Integer getPersonalBest(int position) {  //returns individual personal best from array
        return personalBestsArrayList.get(position);
    }

    public void addPersonalBest(int personalBest) {
        personalBestsArrayList.add(personalBest);
    }

    public void removePersonalBest(int position) {
        personalBestsArrayList.remove(position);
    }

    public void editPersonalBest(int position, int personalBest) {
        personalBestsArrayList.set(position, personalBest);
    }

    public Exercises() {} //constructor
}

Here is ExerciseRow.java:

import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;

public class ExerciseRow extends RecyclerView.Adapter<ExerciseRow.ExerciseViewHolder> {

    String exerciseName = "burpee";
    String exercisePR = "100";  // user's personal record for this exercise in pounds

    private Context context;
    Exercises exercises = new Exercises();


    public ExerciseRow(Context context) {
        this.context = context;
    }

    @Override
    public ExerciseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.exercise_list_item, parent, false);
        return new ExerciseViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ExerciseViewHolder holder, int position) {
        ArrayList<String> exercisesArray = exercises.getExercisesArray();
        holder.bindExercises(exercisesArray.get(position));
    }

    @Override
    public int getItemCount() {
        return exercises.getExercisesArrayLength();
    }

    public class ExerciseViewHolder extends RecyclerView.ViewHolder {

        public TextView exerciseNameTextView;
        public TextView personalRecordTextView;
        public ImageView edit_Icon;
        public ImageView percentages_Icon;
        public ImageView trash_Icon;
        public ImageView plus_icon;
        public ImageView facebook_icon;
        public ImageView twitter_icon;

        public ExerciseViewHolder(View itemView) {
            super(itemView);

            exerciseNameTextView = (TextView) itemView.findViewById(R.id.list_item_exercise_textview);
            personalRecordTextView = (TextView) itemView.findViewById(R.id.list_item_amount_textview);
            edit_Icon = (ImageView) itemView.findViewById(R.id.list_item_pencil);
            percentages_Icon = (ImageView) itemView.findViewById(R.id.list_item_percent);
            trash_Icon = (ImageView) itemView.findViewById(R.id.list_item_trash);
            plus_icon = (ImageView) itemView.findViewById(R.id.list_item_plus);
            facebook_icon = (ImageView) itemView.findViewById(R.id.list_item_facebook);
            twitter_icon = (ImageView) itemView.findViewById(R.id.list_item_twitter);

            View.OnClickListener plus = new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // allow user to add a new exercise and personal best
                    exercises.addExercise("Some exercise");
                    exercises.addPersonalBest(500);
                    notifyDataSetChanged();
                }
            };

            View.OnClickListener edit = new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    int position = getLayoutPosition();  //use getAdapterPosition() if getLayoutPosition causes a problem

                    if (position == 0) {  //prevent user from deleting the first row.
                        Toast.makeText(context, "Sorry, example row cannot be edited.", Toast.LENGTH_LONG).show();
                    }
                    else{
                        editRow(position);  //edit the row at the current position
                        notifyDataSetChanged();
                    }
                }
            };

            View.OnClickListener percentages = new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //get exercise name
                    exerciseName = exerciseNameTextView.getText().toString();
                    exercisePR = personalRecordTextView.getText().toString();

                    //show percentages layout
                    startPercentagesActivity(exerciseName, exercisePR);
                }
            };

            View.OnClickListener trash = new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    int position = getLayoutPosition();  //use getAdapterPosition() if getLayoutPosition causes a problem

                    if (position == 0) {  //prevent user from deleting the first row.
                        Toast.makeText(context, "Sorry, example row cannot be deleted.", Toast.LENGTH_LONG).show();
                    } else {
                        exercises.removeExercise(position);
                        exercises.removePersonalBest(position);
                        notifyItemRemoved(position);
                        notifyItemRangeChanged(position, exercises.getExercisesArrayLength());
                    }
                }
            };

                plus_icon.setOnClickListener(plus);
                edit_Icon.setOnClickListener(edit);
                percentages_Icon.setOnClickListener(percentages);
                trash_Icon.setOnClickListener(trash);
            }

        public void bindExercises(String exercises) {
            Exercises exercisesObject = new Exercises();
            exerciseNameTextView.setText(exercisesObject.getExercise(getAdapterPosition()));
            personalRecordTextView.setText((exercisesObject.getPersonalBest(getAdapterPosition())).toString() + " pounds");
        }

    }

    private void startPercentagesActivity(String some_exercise, String personal_record) {
        Intent intent = new Intent(context, PercentagesActivity.class);
        intent.putExtra("exerciseName", some_exercise);
        intent.putExtra("personalRecord", personal_record);
        context.startActivity(intent);
    }

    protected void editRow(final int position) {
        LayoutInflater layoutInflater = LayoutInflater.from(context);

        //text_entry is an Layout XML file containing two text field to display in alert dialog
        final View textEntryView = layoutInflater.inflate(R.layout.text_entry, null);
        final EditText liftName = (EditText) textEntryView.findViewById(R.id.liftNameEditText);
        final EditText PersonalBestInPounds = (EditText) textEntryView.findViewById(R.id.personalBestEditText);
        final AlertDialog.Builder alert = new AlertDialog.Builder(context);

        alert.setIcon(R.mipmap.barbell)
                .setTitle("Please make your changes:")
                .setView(textEntryView)
                .setPositiveButton("Save",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int whichButton) {


                                //retrieve the user's input
                                String lift = liftName.getText().toString();
                                int personalBest = Integer.parseInt(PersonalBestInPounds.getText().toString());

                                //save the user's input to the appropriate arrays
                                exercises.editExercise(position, lift);
                                exercises.editPersonalBest(position, personalBest);
                            }
                        })
                .setNegativeButton("Cancel",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,
                                                int whichButton) {
                            }
                        });
        alert.show();
    }
}

If you have read this far, I give you credit! Please understand I am completely new to RecyclerView, so whatever error(s) I have made could be something quite simple even.

The issue is that you have two different instances of Exercises One in MainActivity and another in ExerciseRow You are adding the data to the wrong one.

A few other things that may help you along your way.

  1. Exercises Should not extend AppCompatActivity (or really anything as far as I can tell)

  2. You should avoid saving a reference to the context (as you are doing in Exercises) it can great memory issues. Instead try one of the following.

    A. Use the context to get the LayoutInflater in the constructor

    B. Call parent.getContext() in onCreateViewHolder

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM