I try to create a Shopping/ToDoList application where the items are contained in SharedPreferences. When I start the application, and I choose what I want to execute, Shopping list part or ToDoList part, then the java code fetches the existing data from the SharedPreferences and give to the RecycleView to create and show a list. It seems works totally correct, but if I push the “add” button, then a new Activity is executed where I can specify the items, and when I click the save button, then the java code safe to the SharedPreferences and close the Activity and goes back to the “list” activity where the list should appears again with the new item. But when one data is inserted not in order in SharedPreferences but between two older data then the list create method get crazy and repeat always only the last data from SharedPreferences. But when I close the application, and restart, or goes back to the Main activity where I can choose again which list part I want then the list is totally OK again.
That is the list creating java code:
package com.example.recycleviewapp; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import java.util.LinkedList; import java.util.List; import java.util.Map; public class ShoppingList extends AppCompatActivity implements MyRecyclerViewAdapter.ItemClickListener, View.OnClickListener { public MyRecyclerViewAdapter adapter; public Button btn; public SharedPreferences sharedPreferences; public SharedPreferences.Editor myEdit; private List<String> items; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_shoppinglist); sharedPreferences = getSharedPreferences("ShoppingList", Context.MODE_PRIVATE); myEdit = sharedPreferences.edit(); btn = findViewById(R.id.button); items = new LinkedList<>(); StartDisplay(); RecyclerView recyclerView = findViewById(R.id.list); recyclerView.setLayoutManager(new LinearLayoutManager(this)); adapter = new MyRecyclerViewAdapter(this,items); adapter.setClickListener(this); recyclerView.setAdapter(adapter); btn.setOnClickListener(this); } @Override public void onItemClick(View view, int position) { //sharedPreferences = getSharedPreferences("ShoppingList", Context.MODE_PRIVATE); String item_click =adapter.getItem(position); String[] itemarray = item_click.split(" ",0); //Toast.makeText(this, adapter.RemoveItem(position), Toast.LENGTH_SHORT).show(); //adapter.RemoveItem(position); //myEdit = sharedPreferences.edit(); myEdit.remove(itemarray[0]); myEdit.commit(); adapter.notifyItemRemoved(position); items.remove(item_click); } @Override public void onClick(View v) { Intent NewSLItem = new Intent(ShoppingList.this, NewSLItem.class); startActivity(NewSLItem); } @Override public void onResume() { super.onResume(); StartDisplay(); } public void StartDisplay() { //sharedPreferences = getSharedPreferences("ShoppingList", Context.MODE_PRIVATE); Map<String, ?> allEntries = sharedPreferences.getAll(); items.clear(); for (Map.Entry<String, ?> entry : allEntries.entrySet()) { //Toast.makeText(this, entry.getKey(), Toast.LENGTH_SHORT).show(); String [] item_total = entry.getValue().toString().split(";"); items.add(entry.getKey() + " " + item_total[0] + " " + item_total[1]); } allEntries.clear(); } }
Here is the code where I can specify the item:
package com.example.recycleviewapp; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.Spinner; import android.widget.TextView; import java.util.ArrayList; import java.util.List; public class NewSLItem extends MainActivity { private ArrayList<String> items; private ArrayAdapter<String> itemsAdapter; private ListView lvItems; private Button btn; public SharedPreferences sharedPreferences; public SharedPreferences.Editor myEdit; public List<String> list = new ArrayList<>(); public EditText etNewItem; public String[] unit = {"liter", "kg", "pcs"}; public Spinner spinner; public EditText amount; public String itemName; public TextView title; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_shoppinglist_popup); sharedPreferences = getSharedPreferences("ShoppingList", Context.MODE_PRIVATE); myEdit = sharedPreferences.edit(); btn = (Button)findViewById(R.id.addbtn); title = findViewById(R.id.title); etNewItem = (EditText) findViewById(R.id.etNewItem); amount = (EditText) findViewById(R.id.amount); spinner = (Spinner) findViewById(R.id.spinner); ArrayAdapter aa = new ArrayAdapter(this,android.R.layout.simple_spinner_item,unit); aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(aa); title.setText("Create a new item for ShoppingList"); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onAddItem(); finish(); } }); } public void onAddItem() { //myEdit = sharedPreferences.edit(); itemName = etNewItem.getText().toString(); String itemValue = amount.getText().toString() + ";" + spinner.getSelectedItem().toString(); myEdit.putString(itemName,itemValue); myEdit.commit(); etNewItem.setText(""); } }
and here is the RecyclerView code:
package com.example.recycleviewapp; import android.content.Context; import android.graphics.Color; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; import androidx.recyclerview.widget.RecyclerView; import java.util.List; public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> { private List<String> mData; private LayoutInflater mInflater; private ItemClickListener mClickListener; MyRecyclerViewAdapter(Context context, List<String> data) { this.mInflater = LayoutInflater.from(context); this.mData = data; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = mInflater.inflate(R.layout.recyclerview_row, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) { String meta_data = mData.get(position); if (meta_data.contains("High")) holder.myTextView.setBackgroundColor(Color.parseColor("#FF003B")); holder.myTextView.setText(meta_data); } @Override public int getItemCount() { return mData.size(); } public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { TextView myTextView; ViewHolder(View itemView) { super(itemView); myTextView = itemView.findViewById(R.id.tvAnimalName); itemView.setOnClickListener(this); } @Override public void onClick(View view) { if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition()); } } String getItem(int id) {return mData.get(id); } void setClickListener(ItemClickListener itemClickListener) { this.mClickListener = itemClickListener; } public interface ItemClickListener { void onItemClick(View view, int position); } }
So the problem is in casef of only where the data is not in order in SharedPreferences and I go back from a new activity.
Please help me if you can, where should I fix my application? Thanks in advance!!!
Advertisement
Answer
When you return to the list after adding an item, you reread all the items from the SharedPreferences
in StartDisplay()
(which is called from onResume()
. This changes the data that the adapter is working with. However, you didn’t tell the adapter that the data has changed. The adapter caches the View
s and you must tell it when you modify the data, otherwise it doesn’t know the data has changed. Add the following to StartDisplay()
which will invalidate the adapter’s cache and ensure that it rebuilds all the views:
adapter.notifyDataSetChanged()