Как я могу сохранить состояние кнопки (например, видимость кнопки) внутри элемента RecyclerView даже после того, как приложение полностью закрыто?

#java #android #android-recyclerview #android-button #android-database

#java #Android #android-recyclerview #android-кнопка #android-база данных

Вопрос:

Я пытаюсь сохранить состояние кнопки в определенном элементе RecyclerView всякий раз, когда пользователь нажимает эту кнопку. В момент нажатия на него его видимость исчезнет, и будет видна другая кнопка. Как я могу сохранить состояние кнопки, чтобы всякий раз, когда приложение полностью закрывается, когда я снова его открываю, состояние кнопки все еще сохранялось?

Я попытался создать базу данных для состояния видимости кнопки, но я не мог понять, куда поместить правильный код для добавления данных и их сохранения.

onBindViewHolder() внутри класса RecyclerView, вот куда я помещаю свой прослушиватель нажатия кнопки.

 @Override
    public void onBindViewHolder(final MyViewHolder holder, int position){
        MakerAdapter h = makerList.get(position);
        final String macString = h.getHMac();

        holder.rIcon.setImageResource(h.getHIcon());
        holder.rDevice.setText(h.getHDevice());
        holder.rBrand.setText(h.getHBrand());
        holder.rIp.setText(h.getHIp());
        holder.rMac.setText(h.getHMac());
        holder.rDate.setText(h.getHDate());
        holder.rWifi.setText(h.getHWifi());

        holder.rMark.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mSafeDB = new SafeDB(getApplicationContext(), null,null,1);
                holder.rMark.setVisibility(GONE);
                holder.rUnsafe.setVisibility(VISIBLE);
                mSafeDB.addSafeMaker(macString, holder.rMark.getVisibility());
            }
        });

        holder.rUnsafe.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mSafeDB = new SafeDB(getApplicationContext(), null,null,1);
                holder.rUnsafe.setVisibility(GONE);
                holder.rMark.setVisibility(VISIBLE);
                mSafeDB.addSafeMaker(macString, holder.rUnsafe.getVisibility());
            }
        });
    }
  

Это мой импорт, специфичный для этого метода (onBindViewHolder):

 import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static com.facebook.FacebookSdk.getApplicationContext;
  

Это моя база данных

 import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class SafeDB extends SQLiteOpenHelper {

    private static final int DB_VERSION = 1;
    private static final String DB_NAME = "safedb.db";
    private static final String TABLE_NAME = "marked_safe";
    private static final String COL_ID = "id";
    private static final String COL_MAC = "mac";
    private static final String COL_MARK = "mark";

    //////////Housekeeping START
    public SafeDB(Context context, String name, SQLiteDatabase.CursorFactory factory, int version){
        super(context, DB_NAME, factory, DB_VERSION);
    }
    public SafeDB(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
        // this.context = context;
    }


    @Override
    public void onCreate(SQLiteDatabase db){
        String query = "CREATE TABLE "   TABLE_NAME   "("  
                COL_ID   " INTEGER PRIMARY KEY AUTOINCREMENT, "  
                COL_MAC   " TEXT, "  
                COL_MARK   " INTEGER "  
                ");";
        db.execSQL(query);
    }

    public void open() throws SQLException {
        close();
        this.getWritableDatabase();
    }

    public void closeDB() {
        SQLiteDatabase db = this.getReadableDatabase();
        if (db != null amp;amp; db.isOpen())
            db.close();
    }



    @Override
    public void onUpgrade(SQLiteDatabase db, int i, int i1){
        db.execSQL("DROP TABLE IF EXISTS "   TABLE_NAME);
        onCreate(db);
    }
//////////Housekeeping END

    public void deleteTable(){
        SQLiteDatabase db = getWritableDatabase();
        db.execSQL("DROP TABLE IF EXISTS "   TABLE_NAME);
    }

    //IF FIRST TIME. THIS WILL BE TRIGGERED
    public void addSafeMaker(String mac, int mark){
        ContentValues values = new ContentValues();
        values.put(COL_MAC, mac);
        values.put(COL_MARK, mark);
        SQLiteDatabase db = getWritableDatabase();
        db.insert(TABLE_NAME, null, values);
    }


    //UPDATE THE Arp
    public void updateMaker(String mac, int mark){
        ContentValues values = new ContentValues();
        values.put(COL_MAC, mac);
        values.put(COL_MARK, mark);
        SQLiteDatabase db = getWritableDatabase();
        db.update(TABLE_NAME, values, "id = 1", null);
    }


    //GET THE MAC
    public String getMac(String x) {
        SQLiteDatabase db = getWritableDatabase();
        String query = "SELECT * FROM "  TABLE_NAME " WHERE "  COL_ID " = '"   x "'"   " LIMIT 1;" ;
        Cursor c = db.rawQuery(query, null);
        c.moveToFirst();

        String mac = c.getString(c.getColumnIndex("mac"));
        return mac;
    }

    //GET THE BUTTON VISIBILITY VALUE
    public String getSafeValue(String x) {
        SQLiteDatabase db = getWritableDatabase();
        String query = "SELECT * FROM "  TABLE_NAME " WHERE "  COL_ID " = '"   x "'"   " LIMIT 1;" ;
        Cursor c = db.rawQuery(query, null);
        c.moveToFirst();

        String mark = c.getString(c.getColumnIndex("mark"));
        return mark;
    }

    //CHECK IF EMPTY
    public boolean isEmpty() {
        boolean e = true;
        SQLiteDatabase db = getWritableDatabase();
        String count = "SELECT count(*) FROM "   TABLE_NAME;
        Cursor c = db.rawQuery(count, null);
        c.moveToFirst();
        int icount = c.getInt(0);
        e = icount <= 0;
        return e;
    }

    public int getCount(){
        int count = 0;
        SQLiteDatabase db = getWritableDatabase();
        String c = "SELECT count(*) FROM "   TABLE_NAME;
        Cursor x = db.rawQuery(c, null);
        x.moveToFirst();
        count = x.getInt(0);
        return count;
    }
}

  

Комментарии:

1. Используйте SharedPreference вместо базы данных. Все, что вам нужно, это добавить некоторую переменную like btnVisibility = true и использовать ее в onCreate методе вашей деятельности, чтобы определить, видна кнопка или нет

Ответ №1:

Ниже приведен рабочий пример, основанный на вашем коде, хотя адаптер, вероятно, сильно отличается. Были сделаны некоторые предположения / догадки. Таким образом, код очень похож на код в принципе, и его необходимо будет адаптировать.

Вышесказанное добавляет mac (при условии, что mac является уникальным) при создании экземпляра адаптера конкретный mac будет добавлен только один раз.

В методе onBindView статус / метка извлекается из базы данных, чтобы определить, какая кнопка отображается.

При нажатии кнопки отображаемая кнопка переключается, и соответствующий mac (тег кнопки используется для сохранения mac) используется для обновления соответствующей строки в соответствии с mac.

SafeDB.java

 public class SafeDB extends SQLiteOpenHelper {

    private static final int DB_VERSION = 1;
    private static final String DB_NAME = "safedb.db";
    private static final String TABLE_NAME = "marked_safe";
    private static final String COL_ID = "id";
    private static final String COL_MAC = "mac";
    private static final String COL_MARK = "mark";

    //////////Housekeeping START
    public SafeDB(Context context, String name, SQLiteDatabase.CursorFactory factory, int version){
        super(context, DB_NAME, factory, DB_VERSION);
    }
    public SafeDB(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }


    @Override
    public void onCreate(SQLiteDatabase db){
        String query = "CREATE TABLE "   TABLE_NAME   "("  
                COL_ID   " INTEGER PRIMARY KEY, "   // AUTOINCREMENT REMOVED NOT NECESSARY
                COL_MAC   " TEXT UNIQUE, "   // Probably should be unique
                COL_MARK   " INTEGER "  
                ");";
        db.execSQL(query);
    }

    public void open() throws SQLException {
        close();
        this.getWritableDatabase();
    }

    public void closeDB() {
        SQLiteDatabase db = this.getReadableDatabase();
        if (db != null amp;amp; db.isOpen())
            db.close();
    }



    @Override
    public void onUpgrade(SQLiteDatabase db, int i, int i1){
        deleteTable(); // might as well use the deleteTable method as it exists
        onCreate(db);
    }
//////////Housekeeping END

    public void deleteTable(){
        SQLiteDatabase db = getWritableDatabase();
        db.execSQL("DROP TABLE IF EXISTS "   TABLE_NAME);
    }

    //IF FIRST TIME. THIS WILL BE TRIGGERED
    // wont hurt to return the id of the inserted row (-1 if no row inserted)
    public long addSafeMaker(String mac, int mark){
        ContentValues values = new ContentValues();
        values.put(COL_MAC, mac);
        values.put(COL_MARK, mark);
        SQLiteDatabase db = getWritableDatabase();
        return db.insert(TABLE_NAME, null, values);
    }


    //UPDATE THE Arp
    public int updateMaker(String mac, int mark){
        ContentValues values = new ContentValues();
        values.put(COL_MARK, mark);
        //values.put(COL_MARK, mark); // guess this wont change rather that it will be used to determine the row to be updated
        SQLiteDatabase db = getWritableDatabase();
        //db.update(TABLE_NAME, values, "id = 1", null); // Will only ever update 1 specific row
        String whereclause = COL_MAC   "=?";
        String[] whereargs = new String[]{mac};
        return db.update(TABLE_NAME,values,whereclause,whereargs);
    }


    //GET THE MAC
    public String getMac(String x) {
        SQLiteDatabase db = getWritableDatabase();
        String query = "SELECT * FROM "  TABLE_NAME " WHERE "  COL_ID " = '"   x "'"   " LIMIT 1;" ;
        Cursor c = db.rawQuery(query, null);
        c.moveToFirst();

        String mac = c.getString(c.getColumnIndex("mac"));
        return mac;
    }

    public boolean getSafeValue(String mac) {
        int mark = 0; // assume marked safe if row not found
        SQLiteDatabase db = this.getWritableDatabase();
        String whereclause = COL_MAC   "=?";
        String[] whereargs = new String[]{mac};
        Cursor c = db.query(TABLE_NAME,null,whereclause,whereargs,null,null,null);
        if (c.moveToFirst()) {
            mark = c.getInt(c.getColumnIndex(COL_MARK));
        }
        return mark < 1;
    }

    //GET THE BUTTON VISIBILITY VALUE
    /*
    public String getSafeValue(String x) {
        SQLiteDatabase db = getWritableDatabase();
        String query = "SELECT * FROM "  TABLE_NAME " WHERE "  COL_ID " = '"   x "'"   " LIMIT 1;" ;
        Cursor c = db.rawQuery(query, null);
        c.moveToFirst();

        String mark = c.getString(c.getColumnIndex("mark"));
        return mark;
    }
    */

    //CHECK IF EMPTY
    /*
    public boolean isEmpty() {
        boolean e = true;
        SQLiteDatabase db = getWritableDatabase();
        String count = "SELECT count(*) FROM "   TABLE_NAME;
        Cursor c = db.rawQuery(count, null);
        c.moveToFirst(); // WARINING if no rows then next line will crash INDEX OUT OF BOUNDS
        int icount = c.getInt(0);
        e = icount <= 0;
        return e;
    }
    */

    public long getCount(){
        int count = 0;
        SQLiteDatabase db = getWritableDatabase();
        return DatabaseUtils.queryNumEntries(this.getWritableDatabase(),TABLE_NAME);
        /*
        quick form used as above
        String c = "SELECT count(*) FROM "   TABLE_NAME;
        Cursor x = db.rawQuery(c, null);
        x.moveToFirst();
        count = x.getInt(0);
        return count;
        */
    }
}
  
  • Обратите внимание на комментарии, были некоторые проблемы с вашим кодом.

MyAdapter.java

 public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

    ArrayList<String> mMacList;
    SafeDB mDB;
    Context mContext;


    public static class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView mMac;
        public Button mSafe;
        public Button mUnsafe;

        public MyViewHolder(View view) {
            super(view);
            mMac = view.findViewById(R.id.name);
            mSafe = view.findViewById(R.id.marksafe);
            mUnsafe = view.findViewById(R.id.markunsafe);
        }
    }

    public MyAdapter(Context context,ArrayList<String> maclist) {
        mMacList = maclist;
        mContext = context;
        mDB = new SafeDB(context);

        // Could add the mac's to the DB here (note DB changed so mac is unqiue so same mac won't be added)
        for (String mac: maclist) {
            mDB.addSafeMaker(mac,0);
        }
    }

    @NonNull
    @Override
    public MyAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {

        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.mylist_item,viewGroup, false);
        MyViewHolder vh = new MyViewHolder(v);
        mContext = viewGroup.getContext();
        return vh;
    }

    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder viewHolder, int i) {
        viewHolder.mMac.setText(mMacList.get(i));
        if (mDB == null) {
           mDB = new SafeDB(viewHolder.mMac.getContext());
        }
        //Set the Tag for the buttons with the mac so it can be retrieved
        viewHolder.mSafe.setTag(mMacList.get(i));
        viewHolder.mUnsafe.setTag(mMacList.get(i));

        // Display the buttons according to the database
        if (mDB.getSafeValue(mMacList.get(i))) {
            viewHolder.mSafe.setVisibility(View.GONE);
            viewHolder.mUnsafe.setVisibility(View.VISIBLE);
        } else {
            viewHolder.mSafe.setVisibility(View.VISIBLE);
            viewHolder.mUnsafe.setVisibility(View.GONE);
        }
        // Add the onCLickListeners
        viewHolder.mSafe.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                viewHolder.mSafe.setVisibility(View.GONE);
                viewHolder.mUnsafe.setVisibility(View.VISIBLE);
                String mac = (String) ((Button) viewHolder.mSafe).getTag();
                changeSafeMark((String)viewHolder.mSafe.getTag(),0);
            }
        });
        viewHolder.mUnsafe.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                viewHolder.mSafe.setVisibility(View.VISIBLE);
                viewHolder.mUnsafe.setVisibility(View.GONE);
                changeSafeMark((String)viewHolder.mUnsafe.getTag(),1);
            }
        });
    }

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

    public int changeSafeMark(String mac, int mark) {
        int result = mDB.updateMaker(mac,mark);
        return resu<
    }
}
  
  • Вероятно, это совсем другое дело, и был использован только самый простой из макетов.

mylistitem.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@ id/name"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content" />
    <Button
        android:id="@ id/marksafe"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:text="Make Safe"
        />
    <Button
        android:id="@ id/markunsafe"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:text="Make Unsafe"
        />
</LinearLayout>
  

MainActivity.java

Действие вызова, используемое для тестирования :-

 public class MainActivity extends AppCompatActivity {

    RecyclerView mList;
    RecyclerView.LayoutManager mLayoutManager;
    MyAdapter mMyAdapter;

    // The underlying data (just a list of strings for the macs)
    ArrayList<String> mymacliist = new ArrayList<>(Arrays.asList("M1","M2","M3"));

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

        mList = this.findViewById(R.id.mylist);
        mLayoutManager = new LinearLayoutManager(this);
        mList.setLayoutManager(mLayoutManager);
        mMyAdapter = new MyAdapter(this,mymacliist);
        mList.setAdapter(mMyAdapter);
    }
}
  

Результаты

При первом запуске :-

введите описание изображения здесь

После нажатия M2 и M3 (кнопки изменены таким образом, чтобы при нажатии они были безопасными) приложение останавливается, а затем запускается :-

введите описание изображения здесь

Комментарии:

1. Спасибо за этот прототип, концепции вашего кода здесь решили мою проблему.

Ответ №2:

база данных — ваш лучший вариант, вы должны поместить код в onclicklistiner.

если вы хотите «переключить», сохраните логическое значение в базе данных, чтобы, если оно true, пользователь нажал на элемент, и если оно false, пользователь не нажал на элемент.

чем в вашем onclicklistiner вы выполняете оператор if для логического значения.