4

I'm migrating from ListView to RecyclerView, but after entering some data in SQLite, my list is not updated using notifyDataSetChanged (); so I always have to call the setAdapter () method;

I have simplified my code to post here. can anyone help me fix the notifyDataSetChanged (); to work in my code please?

RecyclerViewAdapter

public class RecyclerViewAdapter extends RecyclerView.Adapter<ViewHolder> {

private List<Model> model;
private Context context;

public RecyclerViewAdapter(Context context, List<Model> model) {
    this.context = context;
    this.model = new ArrayList<>(model);
}

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

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    final Model model = model.get(position);
    holder.bind(model);
}

@Override
public int getItemCount() {
    return model.size();
} }

ViewHolder

public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

private List<Model> model = new ArrayList<>();
private Context context;

private TextView textViewGroup;
private TextView textViewName;

public ViewHolder(Context context, View itemView, List<Model> model) {
    super(itemView);

    this.model = model;
    this.context = context;

    itemView.setOnClickListener(this);

    textViewGroup = (TextView) itemView.findViewById(R.id.textViewGroup);
    textViewName = (TextView) itemView.findViewById(R.id.textViewName);

}

public void bind(Model model) {
    textViewGroup.setText(model.getGroup());
    textViewName.setText(model.getName());
    }
}

@Override
public void onClick(View view) {
    Model model = this.model.get(getAdapterPosition());
    Intent intent = new Intent(this.context, ShowGroup.class);
    intent.putExtra("DATA", model);
    intent.putExtra("POSITION", getAdapterPosition());
    ((Activity) this.context).startActivityForResult(intent, 7);

    Log.i(">>", "_IDHOLDER: " + model.getId());
    Log.i(">>", "_POSITION: " + getAdapterPosition());
    Log.i(">>", ".");
} }

Model

public class Model implements Serializable {

public static final String TABLE = "GROUP_NAME";
public static final String ID = "_ID";
public static final String GROUP = "GROUP";
public static final String NAME = "NAME";

private long id;
private String group;
private String name;

public Model() {
    setId(0);
}

public long getId() {
    return id;
}

public void setId(long id) {
    this.id = id;
}

public String getGroup() {
    return group;
}

public void setGroup(String group) {
    this.group = group;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
} }

Repository

public class Repository {

private SQLiteDatabase db;

public Repository(SQLiteDatabase db) {
    this.db = db;
}

private ContentValues fillModelValues(Model model) {
    ContentValues values = new ContentValues();
    values.put(Model.GROUP, model.getGroup());
    values.put(Model.NAME, model.getName());

    return values;
}

public void insert(Model model) {
    ContentValues values = fillModelValues(model);
    db.insertOrThrow(Model.TABLE, null, values);
}

public List<Model> consDataBase(Context context) {

    List<Model> listModel = new ArrayList<>();

    Cursor cursor = db.query(Model.TABLE, null, null, null, null, null, null);

    if (cursor.getCount() > 0) {
        cursor.moveToFirst();

        do {
            Model model = new Model();
            model.setId(cursor.getLong(cursor.getColumnIndex(Model.ID)));
            model.setGroup(cursor.getString(cursor.getColumnIndex(Model.GROUP)));
            model.setName(cursor.getString(cursor.getColumnIndex(Model.NAME)));

            listModel.add(model);

        } while (cursor.moveToNext());
    }

    cursor.close();

    return listModel;
} }

MainActivity

public class MainActivity extends AppCompatActivity {

private List<Model> listModel;
private LinearLayoutManager layoutManager;
private RecyclerView recyclerView;
private RecyclerViewAdapter recyclerViewAdapter;

private FloatingActionButton fab;

private DataBase dataBase;
private SQLiteDatabase db;
private Repository repository;

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

    layoutManager = new LinearLayoutManager(this);
    recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    recyclerView.setLayoutManager(layoutManager);

    fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            startActivityForResult(new Intent(MainActivity.this, AddGroup.class), 4);
        }
    });

    try {
        dataBase = new DataBase(this);
        db = dataBase.getWritableDatabase();
        repository = new Repository(db);

        listModel = repository.consDataBase(context);
        recyclerViewAdapter = new RecyclerViewAdapter(context, listModel);
        recyclerView.setAdapter(recyclerViewAdapter);
        recyclerView.setHasFixedSize(true);

    } catch (SQLException e) {

    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (db != null) {
        db.close();
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == 4) {

        listModel = repository.consDataBase(context);
        recyclerViewAdapter = new RecyclerViewAdapter(context, listModel);
        recyclerView.setAdapter(recyclerViewAdapter);       
    }
} }

AddGroup

public class AddGroup extends AppCompatActivity {

private EditText editTextGroup;
private EditText editTextName;

private DataBase dataBase;
private SQLiteDatabase db;
private Repository repository;
private Model model;

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

    editTextGroup = (EditText) findViewById(R.id.editTextGroup);
    editTextName = (EditText) findViewById(R.id.editTextName);

    try {
        dataBase = new DataBase(this);
        db = dataBase.getWritableDatabase();
        repository = new Repository(db);
        model = new Model();

    } catch (SQLException e) {

    }
}

private void saveModel() {
    try {
        model.setGroup(editTextGroup.getText().toString().trim());
        model.setName(editTextName.getText().toString().trim());
        if (model.getId() == 0) {
            repository.insert(model);
        }

    } catch (Exception e) {

    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (db != null) {
        db.close();
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu_add_group, menu);

    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == R.id.action_save) {
        saveModel();            

    }
    return super.onOptionsItemSelected(item);
} }
F4bioo
  • 179
  • 1
  • 5
  • 11
  • 1
    In your code I cannot see `notifyDataSetChanged`. Where are you calling it? BTW in your adapter I see you build a copy of input list with `this.model = new ArrayList<>(model)` and you don't have an `addItem` method for updating such list explicitly. Maybe you didn't report it in shared code? – andrea.petreri Feb 09 '16 at 07:09
  • 1
    the method to save is in **Repository** `insert (Model model).` I removed it and added `ecyclerView.setAdapter (recyclerViewAdapter);` in **onActivityResult** and this is my question how can I implement `notifyDataSetChanged ();` without having to rebuild with `setAdapter()`? – F4bioo Feb 09 '16 at 07:21
  • 1
    What I mean is that in your repository you store data. Then you need to update also your List and this list should be shared between Activity and Adapter. In Adapter constructor use `this.model = model`, while in `onActivityResult` do `listModel .clear();` then `listModel.addAll(repository.consDataBase(context))` then `recyclerViewAdapter.notifyDataSetChanged()`. – andrea.petreri Feb 09 '16 at 07:29
  • thank you, it is working now, **thanks so much** :) ... Please edit your answer, it will help you get scores – F4bioo Feb 09 '16 at 07:49
  • Glad I could help :) ... I've posted answer :) – andrea.petreri Feb 09 '16 at 07:50
  • You can also vote up if you think it's reasonable :) – andrea.petreri Feb 09 '16 at 07:56
  • after change in adapter constructor: `this.model = new ArrayList <> (model);` to `this.model = model;` my search doesn't working, do you have any idea? [search reference](http://stackoverflow.com/a/30429439/5392773) – F4bioo Feb 10 '16 at 21:10
  • 1
    If you mean that list is not filtered, maybe the issue is that you should keep two collections, the original one with all elements and the filtered one for keeping just the outcome of filter. Filtered list should be at the beginning a copy of the original list and should be passed to Adapter constructor. Then, filter method should update filter list by checking items in original list. Hope this could help. – andrea.petreri Feb 11 '16 at 07:25
  • maybe if it isn't a hard work to do, can you show me it? sorry, I'm a beginner yet. thanks again. – F4bioo Feb 11 '16 at 11:37
  • 1
    I need some time but I can try to share some code with you. – andrea.petreri Feb 11 '16 at 12:25
  • 1
    hey @thetonrifles thank you, it's not necessary I fixed it. see below :) [link](http://stackoverflow.com/a/34448455/5392773) – F4bioo Feb 11 '16 at 12:54

3 Answers3

3

it's working now

RecyclerViewAdapter

public class RecyclerViewAdapter extends RecyclerView.Adapter<ViewHolder> {

    private List<Model> model;
    private Context context;

    public RecyclerViewAdapter(Context context, List<Model> model) {
    this.context = context;
        this.model = new ArrayList<>(model);
    }

    ...

    public void notify(List<Model> list) {
        if (model != null) {
        model.clear();
        model.addAll(list);

        } else {
            model = list;
        }
        notifyDataSetChanged();
    }
}

Then in onActivityResult

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == 4) {
    listModel = repository.consDataBase(this);
        recyclerViewAdapter.notify(listModel);
    }
}

thank you :)

F4bioo
  • 179
  • 1
  • 5
  • 11
2

In order to have your code working you need to change Adapter constructor implementation as follows:

public RecyclerViewAdapter(Context context, List<Model> model) {
    this.context = context;
    this.model = model;
}

Then in onActivityResult do like this:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 4) {
        listModel.clear();
        listModel.addAll(repository.consDataBase(context));
        recyclerViewAdapter.notifyDataSetChanged();
    }
}
andrea.petreri
  • 4,137
  • 2
  • 22
  • 21
  • if i gont create a seperate class for get and set how to update the recycler view bro https://stackoverflow.com/questions/63661586/android-adapter-notifydatasetchanged-cant-updated-my-recyclerview – Kingg Aug 31 '20 at 13:19
-1

Simply put: RecyclerViewAdapter.notyfyDataSetChanged();

PrakashG
  • 1,642
  • 5
  • 20
  • 30