1

I am wanting to save the state of my recyclerview (which has cardviews dynamically in it when the user presses fab button) when

a)the user closes the app then reopens it and b) when the user goes from the activity to the main screen, then back to the activity

I want it so the cardviews and the values the user entered into the spinners are saved on these instances.

How can I achieve this? Intents? Sharedpreferences?

create.java this is the activity with cardviews n stuff. my mainactivity code is where the main screen is with 3 buttons, one which goes to this create.java screen

public class create extends AppCompatActivity {



    //a list to store all the products
    List<Product> productList;

    //the recyclerview
    RecyclerView recyclerView;


    Product mProduct;
    private Map<String, String> numberItemValues = new HashMap<>();
    private Map<Integer, Integer> mSpinnerSelectedItem = new HashMap<Integer, Integer>();


   // RelativeLayout relativeLayout;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.create);
        findViewById(R.id.relativeLayout).requestFocus();



        findViewById(R.id.relativeLayout).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                InputMethodManager imm = (InputMethodManager) view.getContext()
                        .getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
            }
        });


        //opens csv
        InputStream inputStream = getResources().openRawResource(R.raw.shopitems);
         CSVFile csvFile = new CSVFile(inputStream);

       final List<String>  mSpinnerItems = csvFile.read();


        //getting the recyclerview from xml
        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        //initializing the productlist
        productList = new ArrayList<>();
        productList.add(new Product(mSpinnerItems, "Test Edit Text",false, "Text String 2"));




        final ProductAdapter  adapter = new ProductAdapter(this, productList, numberItemValues);


        //TODO FAB BUTTON
        FloatingActionButton floatingActionButton =
             findViewById(R.id.fab);


        floatingActionButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                productList.add(mProduct);
                if(adapter != null)
                    adapter.notifyDataSetChanged();


                //Handle the empty adapter here

            }
        });









        //setting adapter to recyclerview
        recyclerView.setAdapter(adapter);









    }



    private class CSVFile {
        InputStream inputStream;

        public CSVFile(InputStream inputStream) {
            this.inputStream = inputStream;
        }

        public List<String> read() {
            List<String> resultList = new ArrayList<String>();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            try {
                String line;
                while ((line = reader.readLine()) != null) {
                    String[] row = line.split(",");
                    //TODO I edited this part so that you'd add the values in our new hash map variable

                    numberItemValues.put(row[1], row[0]);

                    resultList.add(row[1]);
                }
            } catch (IOException e) {
                Log.e("Main", e.getMessage());
            } finally {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    Log.e("Main", e.getMessage());
                }
            }
            return resultList;
        }
    }



}

ProductAdapter

public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ProductViewHolder> {

    private Map<Integer, Integer> mSpinnerSelectedItem = new HashMap<Integer, Integer>();

    private Map<String, String> numberItemValues = new HashMap<>();





   // private SearchableSpinner spinner;

    //we are storing all the products in a list
    private List<Product> productList;

    private Activity create;


    //TODO CODE FOR CSV FILE


    /*InputStream inputStream = getResources().openRawResource(R.raw.shopitems);
    CSVFile csvFile = new CSVFile(inputStream);
    final List<String>  mSpinnerItems = csvFile.read();*/


    InputStream inputStream = null;
    List<String>  mSpinnerItems = null;
    CSVFile csvFile = null;


    //TODO END OF CODE FOR CSV FILE

    public ProductAdapter(Activity activity) {
        create = activity;

    }


    //getting the context and product list with constructor
    /*public ProductAdapter(Activity activity, List<Product> productList) {
        // this.mCtx = mCtx;

       *//* inputStream = create.getResources().openRawResource(R.raw.shopitems);
        csvFile = new CSVFile(inputStream);
        mSpinnerItems = csvFile.read();*//*

        create = activity;
        this.productList = productList;
    }*/


    public ProductAdapter(Activity activity, List<Product> productList, Map<String, String> numberList) {
        numberItemValues = numberList;
        create = activity;
        this.productList = productList;
    }

    @Override
    public ProductViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //inflating and returning our view holder
        LayoutInflater inflater = LayoutInflater.from(create);
        View view = inflater.inflate(R.layout.layout_products, null);
        return new ProductViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final ProductViewHolder holder, final int position) {


        // //getting the product of the specified position




        ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(create, R.layout.item_spinner_layout,
                Product.getSpinnerItemsList());
        spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        holder.spinner.setAdapter(spinnerArrayAdapter);

        holder.spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int mPosition, long id) {
                mSpinnerSelectedItem.put(position, mPosition);


                TextView mTextView = view.findViewById(R.id.mSpinnerText);


                //TODO CODE FOR GETTING AISLE NUMBER AND PUTTING IT IN THE TEXTVIEW
                /*String currentItem = mSpinnerItems.get(position);
                String aisleNumber = numberItemValues.get(currentItem);
                holder.textView5.setText(aisleNumber);

*/




                //String currentItem = holder.spinner.getSelectedItem().toString();
                String currentItem = holder.spinner.getItemAtPosition(mPosition).toString();

                Set<String> set = numberItemValues.keySet(); for(String key : set) {String value = numberItemValues.get(key); Log.e("DATA ", "key = " + key + " value = " + value); }





                //String currentItem = holder.spinner.getItemAtPosition(mPosition).toString();
                String aisleNumber = numberItemValues.get(currentItem);
                holder.textView5.setText(aisleNumber);

                Log.e("SELECTION TEST", " Selected map item = " + aisleNumber );


            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });


        //binding the data with the viewholder views
        if (mSpinnerSelectedItem.containsKey(position)) {
            holder.spinner.setSelection(mSpinnerSelectedItem.get(position));
        }


        holder.getView().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {


                AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(create);


                // set title
                alertDialogBuilder.setTitle("Delete Item");

                // set dialog message
                alertDialogBuilder
                        .setMessage("Are you sure you want to delete this item?")
                        .setCancelable(false)
                        .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                // if this button is clicked, close
                                // current activity


                                holder.checkBox.setChecked(false);
                                holder.spinner.setSelection(0);



                                productList.remove(holder.getAdapterPosition());
                                notifyItemRemoved(holder.getAdapterPosition());

                                Toast.makeText(create, "Item removed.", Toast.LENGTH_LONG).show();


                            }
                        })
                        .setNegativeButton("No", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                // if this button is clicked, just close
                                // the dialog box and do nothing
                                dialog.cancel();
                            }
                        });

                // create alert dialog
                AlertDialog alertDialog = alertDialogBuilder.create();

                // show it
                alertDialog.show();

            }
        });





    }


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


    class ProductViewHolder extends RecyclerView.ViewHolder {

        SearchableSpinner spinner;
        EditText editText;
        TextView textView5;
        CheckBox checkBox;
        LinearLayout linearLayout;
        View rootView;


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

            spinner = itemView.findViewById(R.id.spinner);
            editText = itemView.findViewById(R.id.editText);
            textView5 = itemView.findViewById(R.id.textView5);
            checkBox = itemView.findViewById(R.id.checkBox);
            rootView = itemView.findViewById(R.id.linearLayout);


            checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    // makes the set disappear when checkbox is ticked.
                    if(isChecked){

                        checkBox.setChecked(false);
                        spinner.setSelection(0);

                        productList.remove(getAdapterPosition());
                        notifyItemRemoved(getAdapterPosition());



                        Toast.makeText(create, "Done!", Toast.LENGTH_LONG).show();
                    }

                }
            });



        }

        public View getView() {
            return rootView;
        }

    }

    //TODO CODE FOR CSV FILE
    private class CSVFile {
        InputStream inputStream;

        public CSVFile(InputStream inputStream) {
            this.inputStream = inputStream;
        }

        public List<String> read() {
            List<String> resultList = new ArrayList<String>();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            try {
                String line;
                while ((line = reader.readLine()) != null) {
                    String[] row = line.split(",");

                    numberItemValues.put(row[1], row[0]);

                    resultList.add(row[1]);
                }
            } catch (IOException e) {
                Log.e("Main", e.getMessage());
            } finally {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    Log.e("Main", e.getMessage());
                }
            }
            return resultList;
        }
    }


}

Product.Java

public class Product {

    private static String editText;
    private static Boolean checkBox;
    private static String textView5;

    public static List<String> spinnerItemsList = new ArrayList<String>();

    public Product(List spinner, String editText, Boolean checkBox, String textView5) {

        this.editText = editText;
        this.spinnerItemsList = spinner;
        this.checkBox = checkBox;
        this.textView5 = textView5;
    }
    public static String getEdittext () {
        return editText;
    }

    public static boolean getCheckbox () {
        return checkBox;
    }

    public static String getTextview () {
        return textView5;
    }
    public static List<String> getSpinnerItemsList () {
        return spinnerItemsList;
    }
}

MyListAdapter code for Spinner

public class MyListAdapter extends ArrayAdapter<String> {
    int groupid;
    List<String> items;
    Context context;
    String path;





    public MyListAdapter(Context context, int vg, int id, List<String> items) {
        super(context, vg, id, items);
        this.context = context;
        groupid = vg;
        this.items = items;

    }

    static class ViewHolder {
        public TextView textid;
        public TextView textname;

    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        {

            View rowView = convertView;
            if (rowView == null) {
                LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                rowView = inflater.inflate(groupid, parent, false);
                ViewHolder viewHolder = new ViewHolder();
                viewHolder.textid = (TextView) rowView.findViewById(R.id.txtid);
                viewHolder.textname = (TextView) rowView.findViewById(R.id.txtname);
                rowView.setTag(viewHolder);
            }
            // Fill data in the drop down.
            ViewHolder holder = (ViewHolder) rowView.getTag();
            String row = items.get(position);
            //holder.textid.setText(row[0]); //prints aisle number, dont need

            holder.textname.setText(row);



            return rowView;
        }

    }

}
Grand Skunk
  • 29
  • 18
  • Okay so you want to store the data entered by user to be stored? and then whenever user launch the app they should get what they entered earlier? – Ussaid Iqbal Sep 30 '18 at 09:52
  • yes as well as the cardviews they added . and you know the spinners are inside the cardview and those spinner values are to be stored too – Grand Skunk Sep 30 '18 at 09:58

2 Answers2

2

you should save the data in sharedPreferences or database, and every time you open your activity read the data from the stored list.

to store in data base you'll need a database helper class like this

public class DataBase_CITY extends SQLiteOpenHelper {
// The Android's default system path of your application database.
private static String DB_PATH = "";
public static String TABLE;
private static String DB_NAME;
private static String[] FIELD_NAMES;
private static String[] FIELD_TYPES;

private SQLiteDatabase myDataBase;

private final Context myContext;

/**
 * Constructor Takes and keeps a reference of the passed context in order to
 * access to the application assets and resources.
 *
 * @param context
 */
public DataBase_CITY(Context context, String dataBaseName, String tableName, 
   String[] fieldNames, String[] fieldTypes) {

    super(context, dataBaseName, null, 1);
    DB_NAME = dataBaseName;
    TABLE = tableName;
    FIELD_NAMES = fieldNames;
    FIELD_TYPES = fieldTypes;

    this.myContext = context;

    System.err.println(context.getApplicationInfo().dataDir);

    DB_PATH = context.getApplicationInfo().dataDir + File.separator
            + "databases" + File.separator;

    System.out.println(DB_PATH);
}

/**
 * Creates a empty database on the system and rewrites it with your own
 * database.
 */
public void createDataBase() throws IOException {

    boolean dbExist = checkDataBase();

    if (dbExist) {
        // do nothing - database already exist
        // Toast.makeText(myContext, "already exist",
        // Toast.LENGTH_LONG).show();
    } else {

        // By calling this method and empty database will be created into
        // the default system path
        // of your application so we are gonna be able to overwrite that
        // database with our database.
        this.getReadableDatabase();

        try {

            copyDataBase();

        } catch (IOException e) {

            // throw new Error("Error copying database");

        }
    }

}

/**
 * Check if the database already exist to avoid re-copying the file each
 * time you open the application.
 *
 * @return true if it exists, false if it doesn't
 */
private boolean checkDataBase() {

    SQLiteDatabase checkDB = null;

    try {
        String myPath = DB_PATH + DB_NAME;
        checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
        // Toast.makeText(myContext, "already exist",
        // Toast.LENGTH_LONG).show();
    } catch (SQLiteException e) {

        // database does't exist yet.
        // Toast.makeText(myContext, "not already exist",
        // Toast.LENGTH_LONG).show();
    }

    if (checkDB != null) {

        checkDB.close();

    }

    return checkDB != null ? true : false;
}

/**
 * Copies your database from your local assets-folder to the just created
 * empty database in the system folder, from where it can be accessed and
 * handled. This is done by transfering bytestream.
 */
private void copyDataBase() throws IOException {

    // Open your local db as the input stream
    InputStream myInput = myContext.getAssets().open(DB_NAME);

    // Path to the just created empty db
    String outFileName = DB_PATH + DB_NAME;

    // Open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(outFileName);

    // transfer bytes from the Input file to the output file
    byte[] buffer = new byte[1024];
    int length;
    while ((length = myInput.read(buffer)) > 0) {
        myOutput.write(buffer, 0, length);
    }

    // Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();

}

public void openDataBase() throws SQLException {

    // Open the database
    String myPath = DB_PATH + DB_NAME;
    myDataBase = SQLiteDatabase.openDatabase(myPath, null,
            SQLiteDatabase.OPEN_READONLY);

}

@Override
public synchronized void close() {

    if (myDataBase != null)
        myDataBase.close();

    super.close();

}

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL("Create table " + TABLE + " (UserID INTEGER PRIMARY KEY AUTOINCREMENT, "
            + FIELD_NAMES[0] + " " + FIELD_TYPES[0] + ", "
            + FIELD_NAMES[1] + " " + FIELD_TYPES[1] + ", "
            + FIELD_NAMES[2] + " " + FIELD_TYPES[2] + ")");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS " + TABLE);
    onCreate(db);
}

public void updateDB(String[] arguments) {
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put(FIELD_NAMES[0], Integer.parseInt(arguments[0]));
    values.put(FIELD_NAMES[1], arguments[1]);
    values.put(FIELD_NAMES[2], Integer.parseInt(arguments[2]));

    db.insert(TABLE, null, values);
    db.close();
    }

}

to store data in it you need the below method

private static void updateCityTable(String TableName, int id, String name, int 
province_id) {
    DataBase_CITY helper = new DataBase_CITY(G.CONTEXT,
            "CITY_DATABASE", TableName, G.CityTableFields, G.CityTableFieldTypes);
    try {
        helper.updateDB(new String[]{
                String.valueOf(id),
                name,
                String.valueOf(province_id)});

    } catch (Exception e) {
        e.printStackTrace();
    }

}

and you can read from the database like this

private String cityDataBaseChecker(String TableName, String column, String columnName, String amount) {
    DataBase_PROVINCE helper = new DataBase_PROVINCE(G.CONTEXT,
            "CITY_DATABASE", TableName, G.CityTableFields, G.CityTableFieldTypes);
    try {
        helper.createDataBase();
    } catch (IOException ioe) {
        throw new Error("Unable to create database");
    }

    SQLiteDatabase sqld = helper.getWritableDatabase();

    Cursor cursor = sqld.rawQuery("select * from " + TableName + " where " + columnName + "=\"" + amount + "\" order by " + column, null);
    String title = null;
    if (cursor.moveToFirst()) {
        do {
            title = cursor.getString(cursor.getColumnIndex(column));
            System.out.println("city =" + title);
        } while (cursor.moveToNext());
    }
    sqld.close();
    return title;
}

and you can define field names and types like this

public static String[] CityTableFields = new String[]{"id", "name", "province_id"};
public static String[] CityTableFieldTypes = new String[]{"INT", "TEXT", "INT"};
Mohamad Rostami
  • 420
  • 3
  • 17
0

I will not go in depth, but basically you need to persist the state. https://developer.android.com/guide/topics/data/data-storage

You have a lot of options, of course not all of them are great. Choose what you need based on your context and your needs. Read!

After you choose how you want to store your current state of the recycler's content (what i mean by that is, to store the data you have currently populated) you can proceed with finding the right places of the activities lifecycle to store that data.

For me looks like the best places would be onStart (restore data if saved) <-> onStop (save data, if it is needed to be saved). https://developer.android.com/guide/components/activities/activity-lifecycle

What is more, you will probably need the current index position and many other details which possible will appear in your application and unique situation, so you need to research this and find the best way on your own. Write code and experiment, that is how you learn.

To sum it up:

1st. Find a way to store your data efficiently based on your needs, research how can you persist effectively data in android.

2nd. Find the right places to save your data as the user clicks on his phone and does random things. What i mean by that, learn the activities lifecycle perfectly and than you will know what to do and where to do it.

3rd. Finally when you have taken the data out of the storage, populate it, and scroll to the index where the user has last been. How to programmatically scroll to the bottom of a Recycler View? (Of course, that means you will have to have stored it before that, find a way to get the current index and so on, research and code, be a developer)

Here is some info about that, but as i said you need to do the research and find what suits you.

Now do the work.

T.Dimitrov
  • 157
  • 2
  • 7