I have a few recyclerview in different activities and all of their items specified by sharedpreferences but after removing an item from sharedpreferences the recyclerview doesn't update until I close the activity and open it back I tried notifyDataSetChanged() after removing the Item but seems it dose not work and here is the codes:
this is my utils class where I made the sharedpreferences:
public class Utils {
private static final String ALL_BOOK_KEY = "all_book_key";
private static final String ALREADY_READ_BOOKS = "already_read_books";
private static final String FAVORITE_BOOKS = "favorite_books";
private static final String CURRENTLY_READING_BOOKS = "currently_reading_books";
private static final String WANT_TO_READ_BOOKS = "want_to_read_books";
private static Utils instance;
private final SharedPreferences sharedPreferences;
Gson gson = new Gson();
Type type = new TypeToken<ArrayList<Book>>(){}.getType();
private Utils(Context context) {
sharedPreferences = context.getSharedPreferences("alternate_db", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
if (null == getAllBook()){
initData();
}
if (null == getAlreadyReadBooks()){
editor.putString(ALREADY_READ_BOOKS, gson.toJson(new ArrayList<Book>()));
editor.commit();
}
if (null == getWantToReadBooks()){
editor.putString(WANT_TO_READ_BOOKS, gson.toJson(new ArrayList<Book>()));
editor.commit();
}
if (null == getCurrentlyReadingBooks()){
editor.putString(CURRENTLY_READING_BOOKS, gson.toJson(new ArrayList<Book>()));
editor.commit();
}
if (null == getFavoriteBooks()){
editor.putString(FAVORITE_BOOKS, gson.toJson(new ArrayList<Book>()));
editor.commit();
}
}
private void initData() {
ArrayList<Book> books = new ArrayList<>();
books.add(new Book(1, "1Q84", "Haruki Murakami",
1350,"https://upload.wikimedia.org/wikipedia/pt/thumb/a/a6/1Q84.jpg/230px-1Q84.jpg",
"A work of maddening brilliance", "The year is 1984 and the city is Tokyo. A young woman named Aomame follows a taxi driver’s enigmatic suggestion and begins to notice puzzling discrepancies in the world around her. She has entered, she realizes, a parallel existence, which she calls 1Q84 “Q is for ‘question mark.’ A world that bears a question.” Meanwhile, an aspiring writer named Tengo takes on a suspect ghostwriting project. He becomes so wrapped up with the work and its unusual author that, soon, his previously placid life begins to come unraveled. As Aomame’s and Tengo’s narratives converge over the course of this single year, we learn of the profound and tangled connections that bind them ever closer: a beautiful, dyslexic teenage girl with a unique vision; a mysterious religious cult that instigated a shoot-out with the metropolitan police; a reclusive, wealthy dowager who runs a shelter for abused women; a hideously ugly private investigator; a mild-mannered yet ruthlessly efficient bodyguard; and a peculiarly insistent television-fee collector. A love story, a mystery, a fantasy, a novel of self-discovery, a dystopia to rival George Orwell’s 1Q84 is Haruki Murakami’s most ambitious undertaking yet: an instant best seller in his native Japan, and a tremendous feat of imagination from one of our most revered contemporary writers."));
books.add(new Book(2, "1984", "George Orwell", 328, "https://www.jiomart.com/images/product/600x600/rvkysatqkb/1984-hindi-george-orwell-paperback-296-pages-product-images-orvkysatqkb-p590846049-0-202111091023.jpg","follows the life of Winston Smith, a low ranking member of 'the Party', who is frustrated by the omnipresent eyes of the party, and its ominous ruler Big Brother", "1984 by George Orwell – review ‘Orwell’s novella is a warning for the human race’ Conheeneyl Sun 29 May 2016 12.00 BST War is Peace. Freedom is Slavery. Ignorance is Strength. 1984 is a dystopian novella by George Orwell published in 1949, which follows the life of Winston Smith, a low ranking member of ‘the Party’, who is frustrated by the omnipresent eyes of the party, and its ominous ruler Big Brother. ‘Big Brother’ controls every aspect of people’s lives. It has invented the language ‘Newspeak’ in an attempt to completely eliminate political rebellion; created ‘Throughtcrimes’ to stop people even thinking of things considered rebellious. The party controls what people read, speak, say and do with the threat that if they disobey, they will be sent to the dreaded Room 101 as a looming punishment. Orwell effectively explores the themes of mass media control, government surveillance, totalitarianism and how a dictator can manipulate and control history, thoughts, and lives in such a way that no one can escape it. 1984 The protagonist, Winston Smith, begins a subtle rebellion against the party by keeping a diary of his secret thoughts, which is a deadly thoughtcrime. With his lover Julia, he begins a foreordained fight for freedom and justice, in a world where no one else appears to see, or dislike, the oppression the protagonist opposes. Perhaps the most powerful, effective and frightening notion of 1984 is that the complete control of an entire nation under a totalitarian state is perfectly possible. If the world fell under the control of one or even multiple dictators, the future could easily become a twisted, cruel world where every movement, word and breath is scrutinised by an omnipotent, omnipresent power that no one can stop, or even oppose without the fear of death. How do I get involved in the Guardian children\'s books site? Read more Orwell’s novella is a warning for the human race. It highlights the importance of resisting mass control and oppression."));
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(ALL_BOOK_KEY, gson.toJson(books));
editor.commit();
}
public static Utils getInstance(Context context) {
if (null == instance) {
instance = new Utils(context);
}
return instance;
}
public ArrayList<Book> getAllBook() {
return gson.fromJson(sharedPreferences.getString(ALL_BOOK_KEY, null), type);
}
public ArrayList<Book> getAlreadyReadBooks() {
return gson.fromJson(sharedPreferences.getString(ALREADY_READ_BOOKS, null),type);
}
public ArrayList<Book> getWantToReadBooks() {
return gson.fromJson(sharedPreferences.getString(WANT_TO_READ_BOOKS, null), type);
}
public ArrayList<Book> getCurrentlyReadingBooks() {
return gson.fromJson(sharedPreferences.getString(CURRENTLY_READING_BOOKS,null), type);
}
public ArrayList<Book> getFavoriteBooks() {
return gson.fromJson(sharedPreferences.getString(FAVORITE_BOOKS, null), type);
}
public Book getBookById(int id) {
ArrayList<Book> books = getAllBook();
if(null != books){
for (Book b : books) {
if (b.getId() == id) {
return b;
}
}
}
return null;
}
public boolean addToAlreadyReadBook(Book book){
book.setExpanded(false);
ArrayList<Book> books = getAlreadyReadBooks();
if(null != books){
if (books.add(book)){
return addToSharedPreferences(books, ALREADY_READ_BOOKS);
}
}
return false;
}
public boolean addToWantToReadBook(Book book){
book.setExpanded(false);
ArrayList<Book> books = getWantToReadBooks();
if(null != books){
if(books.add(book)){
return addToSharedPreferences(books, WANT_TO_READ_BOOKS);
}
}
return false;
}
public boolean addToCurrentlyReading(Book book){
book.setExpanded(false);
ArrayList<Book> books = getCurrentlyReadingBooks();
if(null != books){
if(books.add(book)){
return addToSharedPreferences(books, CURRENTLY_READING_BOOKS);
}
}
return false;
}
public boolean addToFavorite(Book book){
book.setExpanded(false);
ArrayList<Book> books = getFavoriteBooks();
if(null != books){
if(books.add(book)){
return addToSharedPreferences(books, FAVORITE_BOOKS);
}
}
return false;
}
public boolean removeFromWantToRead(Book book){
book.setExpanded(false);
ArrayList<Book> books = getWantToReadBooks();
if(null != books){
for (Book b: books){
if(b.getId() == book.getId()){
if (books.remove(b)){
return addToSharedPreferences(books, WANT_TO_READ_BOOKS);
}
}
}
}
return false;
}
public boolean removeFromAlreadyReadBook(Book book){
book.setExpanded(false);
ArrayList<Book> books = getAlreadyReadBooks();
if(null != books){
for (Book b: books){
if(b.getId() == book.getId()){
if (books.remove(b)){
return addToSharedPreferences(books, ALREADY_READ_BOOKS);
}
}
}
}
return false;
}
public boolean removeFromFavoriteBook(Book book){
book.setExpanded(false);
ArrayList<Book> books = getFavoriteBooks();
if(null != books){
for (Book b: books){
if(b.getId() == book.getId()){
if (books.remove(b)){
return addToSharedPreferences(books, FAVORITE_BOOKS);
}
}
}
}
return false;
}
public boolean removeFromCurrentlyReadingBook(Book book){
book.setExpanded(false);
ArrayList<Book> books = getCurrentlyReadingBooks();
if(null != books){
for (Book b: books){
if(b.getId() == book.getId()){
if (books.remove(b)){
return addToSharedPreferences(books, CURRENTLY_READING_BOOKS);
}
}
}
}
return false;
}
public boolean addToSharedPreferences(ArrayList<Book> books, String name){
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.remove(name);
editor.putString(name, gson.toJson(books));
editor.commit();
return true;
}
}
this is my adopter class for recyclerview I am calling the method that is responsible for removing items from sharedpreferences inside the utils class from here whenever the user click on the yes button in the alertdialog:
public class BookRecAdopter extends RecyclerView.Adapter<BookRecAdopter.ViewHolder>{
private static final String TAG = "BookRecAdopter";
private ArrayList<Book> books = new ArrayList<>();
private final Context mContext;
private final String parentActivity;
public BookRecAdopter(Context mContext, String parentActivity) {
this.mContext = mContext;
this.parentActivity = parentActivity;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_book, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, @SuppressLint("RecyclerView") int position) {
Log.d(TAG, "onBindViewHolder: Called");
holder.txtName.setText(books.get(position).getName());
Glide.with(mContext).asBitmap().load(books.get(position).getImageUrl()).into(holder.imgBook);
holder.parent.setOnClickListener(view -> {
Intent intent = new Intent(mContext, BookActivity.class);
intent.putExtra(BOOK_ID_KEY, books.get(position).getId());
mContext.startActivity(intent);
});
holder.txtAuthor.setText(books.get(position).getAuthor());
holder.txtDescription.setText(books.get(position).getShortDesc());
holder.bookNameFull.setText(books.get(position).getName());
if (books.get(position).isExpanded()){
TransitionManager.beginDelayedTransition(holder.parent);
holder.expandedRelLayout.setVisibility(View.VISIBLE);
holder.downArrow.setVisibility(View.GONE);
holder.txtName.setVisibility(View.GONE);
switch (parentActivity) {
case "allBook":
holder.btnDelete.setVisibility(View.GONE);
break;
case "wantToReadBook":
holder.btnDelete.setVisibility(View.VISIBLE);
holder.btnDelete.setOnClickListener(view -> {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage("Are you sure you want to delete " books.get(position).getName() "?");
builder.setPositiveButton("Yes", (dialogInterface, i) -> {
if (Utils.getInstance(mContext).removeFromWantToRead(books.get(position))) {
Toast.makeText(mContext, "Book Removed", Toast.LENGTH_SHORT).show();
notifyDataSetChanged();
}
});
builder.setNegativeButton("No", (dialogInterface, i) -> {
});
builder.create().show();
});
break;
case "alreadyReadBook":
holder.btnDelete.setVisibility(View.VISIBLE);
holder.btnDelete.setOnClickListener(view -> {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage("Are you sure you want to delete " books.get(position).getName() "?");
builder.setPositiveButton("Yes", (dialogInterface, i) -> {
if(Utils.getInstance(mContext).removeFromAlreadyReadBook(books.get(position))){
Toast.makeText(mContext, "Book Removed", Toast.LENGTH_SHORT).show();
notifyDataSetChanged();
}
});
builder.setNegativeButton("No", (dialogInterface, i) -> {
});
builder.create().show();
});
break;
case "favoriteBook":
holder.btnDelete.setVisibility(View.VISIBLE);
holder.btnDelete.setOnClickListener(view -> {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage("are you sure you want to delete " books.get(position).getName() "?");
builder.setPositiveButton("Yes", (dialogInterface, i) -> {
if(Utils.getInstance(mContext).removeFromFavoriteBook(books.get(position))){
Toast.makeText(mContext, "Book Removed", Toast.LENGTH_SHORT).show();
notifyDataSetChanged();
}
});
builder.setNegativeButton("No", (dialogInterface, i) -> {
});
builder.create().show();
});
break;
case "currentlyReadBook":
holder.btnDelete.setVisibility(View.VISIBLE);
holder.btnDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage("Are you sure you want to delete " books.get(position).getName() "?");
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
if(Utils.getInstance(mContext).removeFromCurrentlyReadingBook(books.get(position))){
Toast.makeText(mContext, "Book Removed", Toast.LENGTH_SHORT).show();
notifyDataSetChanged();
}
}
});
builder.setNegativeButton("No", (dialogInterface, i) -> {
});
builder.create().show();
}
});
break;
}
}
else{
TransitionManager.beginDelayedTransition(holder.parent);
holder.expandedRelLayout.setVisibility(View.GONE);
holder.downArrow.setVisibility(View.VISIBLE);
holder.txtName.setVisibility(View.VISIBLE);
}
}
@Override
public int getItemCount() {
return books.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private final CardView parent;
private final ImageView imgBook;
private final ImageView downArrow;
private final TextView txtName, txtAuthor, txtDescription, bookNameFull, btnDelete;
private final RelativeLayout expandedRelLayout;
public ViewHolder(@NonNull View itemView) {
super(itemView);
parent = itemView.findViewById(R.id.parent);
imgBook = itemView.findViewById(R.id.imgBook);
txtName = itemView.findViewById(R.id.txtBookName);
downArrow = itemView.findViewById(R.id.btnDownArrow);
ImageView upArrow = itemView.findViewById(R.id.btnUpArrow);
expandedRelLayout = itemView.findViewById(R.id.expandedRelLayout);
txtAuthor = itemView.findViewById(R.id.txtAuthor);
txtDescription = itemView.findViewById(R.id.txtShortDec);
bookNameFull = itemView.findViewById(R.id.bookNameFull);
btnDelete = itemView.findViewById(R.id.btnDelete);
downArrow.setOnClickListener(view -> {
Book book = books.get(getAdapterPosition());
book.setExpanded(!book.isExpanded());
notifyItemChanged(getAdapterPosition());
});
upArrow.setOnClickListener(view -> {
Book book = books.get(getAdapterPosition());
book.setExpanded((!book.isExpanded()));
notifyItemChanged(getAdapterPosition());
});
}
}
public void setBooks(ArrayList<Book> books) {
this.books = books;
notifyDataSetChanged();
}
}
and this is one of the activities where a recyclerview is there and it get the items from sharedprefereces:
public class Favorite extends AppCompatActivity {
RecyclerView favoriteRec;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_favorite);
favoriteRec = findViewById(R.id.favoriteRec);
BookRecAdopter books = new BookRecAdopter(this, "favoriteBook");
books.setBooks(Utils.getInstance(this).getFavoriteBooks());
favoriteRec.setAdapter(books);
favoriteRec.setLayoutManager(new LinearLayoutManager(this));
}
@Override
public void onBackPressed(){
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
overridePendingTransition(R.anim.close_in, R.anim.close_out);
}
}
I think I have to override some callback method to update the recyclerview after any change in the sharedpreferences but I don't know which one and where
I appreciate any help.
CodePudding user response:
First, when configuring your RecyclerView
setup its layout manager before its adapter:
BookRecAdopter books = new BookRecAdopter(this, "favoriteBook");
favoriteRec.setLayoutManager(new LinearLayoutManager(this));
favoriteRec.setAdapter(books);
Then, given your project structure, I think that you should populate your adapter's data directly from the Utils
class.
Try to define a inner method inside the adapter that update the list of books (updateBooks
), and call it after every deletion and on initialization.
public class BookRecAdopter extends RecyclerView.Adapter<BookRecAdopter.ViewHolder>{
private static final String TAG = "BookRecAdopter";
private ArrayList<Book> books = new ArrayList<>();
private final Context mContext;
private final String parentActivity;
public BookRecAdopter(Context mContext, String parentActivity) {
this.mContext = mContext;
this.parentActivity = parentActivity;
updateBooks();
}
private void updateBooks() {
switch (parentActivity) {
case "allBook":
this.books = Utils.getInstance(mContext).getAllBooks();
break;
case "wantToReadBook":
this.books = Utils.getInstance(mContext).getWantToReadBooks();
break;
case "alreadyReadBook":
this.books = Utils.getInstance(mContext).getAlreadyReadBooks();
break;
case "favoriteBook":
this.books = Utils.getInstance(mContext).getFavoriteBooks();
break;
case "currentlyReadBook":
this.books = Utils.getInstance(mContext).getCurrentlyReadingBooks();
break;
default:
break;
}
this.notifyDataSetChanged();
}
...
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, @SuppressLint("RecyclerView") int position) {
...
if (books.get(position).isExpanded()){
...
switch (parentActivity) {
case "wantToReadBook":
holder.btnDelete.setVisibility(View.VISIBLE);
holder.btnDelete.setOnClickListener(view -> {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage("Are you sure you want to delete " books.get(position).getName() "?");
builder.setPositiveButton("Yes", (dialogInterface, i) -> {
if (Utils.getInstance(mContext).removeFromWantToRead(books.get(position))) {
Toast.makeText(mContext, "Book Removed", Toast.LENGTH_SHORT).show();
updateBooks();
}
});
builder.setNegativeButton("No", (dialogInterface, i) -> {
});
builder.create().show();
});
break;
case "alreadyReadBook":
holder.btnDelete.setVisibility(View.VISIBLE);
holder.btnDelete.setOnClickListener(view -> {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage("Are you sure you want to delete " books.get(position).getName() "?");
builder.setPositiveButton("Yes", (dialogInterface, i) -> {
if(Utils.getInstance(mContext).removeFromAlreadyReadBook(books.get(position))){
Toast.makeText(mContext, "Book Removed", Toast.LENGTH_SHORT).show();
updateBooks();
}
});
builder.setNegativeButton("No", (dialogInterface, i) -> {
});
builder.create().show();
});
break;
case "favoriteBook":
holder.btnDelete.setVisibility(View.VISIBLE);
holder.btnDelete.setOnClickListener(view -> {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage("are you sure you want to delete " books.get(position).getName() "?");
builder.setPositiveButton("Yes", (dialogInterface, i) -> {
if(Utils.getInstance(mContext).removeFromFavoriteBook(books.get(position))){
Toast.makeText(mContext, "Book Removed", Toast.LENGTH_SHORT).show();
updateBooks();
}
});
builder.setNegativeButton("No", (dialogInterface, i) -> {
});
builder.create().show();
});
break;
case "currentlyReadBook":
holder.btnDelete.setVisibility(View.VISIBLE);
holder.btnDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage("Are you sure you want to delete " books.get(position).getName() "?");
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
if(Utils.getInstance(mContext).removeFromCurrentlyReadingBook(books.get(position))){
Toast.makeText(mContext, "Book Removed", Toast.LENGTH_SHORT).show();
updateBooks();
}
}
});
builder.setNegativeButton("No", (dialogInterface, i) -> {
});
builder.create().show();
}
});
break;
}
}
...
}