簡體   English   中英

如何使用按鈕單擊保存多個復選框的 state

[英]How to save the state of Multiple checkbox using a Button click

在我的應用程序中,我有一個ArrayListrecyclerView ,其中我在 textView 旁邊設置了一個checkBox 我想通過單擊一個按鈕來保存checkBox的 state,並且我想將其加載到另一個活動中,而這些都應該使用SharedPrefrennces來完成。

實際上,我沒有得到這樣的概念,即如何通過單擊按鈕將checkBox的 state 保存在SharedPrefrennces中。

注意:請記住我是初學者

這是顯示我所做的代碼..

public class StudentListActivity extends AppCompatActivity {
private static final String DATETIME = "dateTime";
private RecyclerView recyclerView;
private RecyclerView.Adapter rAdapter;
private RecyclerView.LayoutManager layoutManager;
ArrayList<ListOfNames> listOfNames;


SharedPreferences sharedPreferences;
SharedPreferences.Editor editor;

String t1 = "10";
String t2 = "100%";
Bundle bundle;
String subName;
Toolbar toolbar;
boolean[] items;

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

    toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    bundle = getIntent().getExtras();
    subName = bundle.getString("Subject Name");
    if (bundle != null) {
        getSupportActionBar().setTitle(subName);
    }
    loadData();


    Calendar calendar = Calendar.getInstance();
    String currentDate = DateFormat.getDateTimeInstance().format(calendar.getTime());


    toolbar.setSubtitle(currentDate);
    fabButton();
    buildRecyclerView();


}

@Override
public void onBackPressed() {
    super.onBackPressed();
    Intent intent = new Intent(this, ScrollingActivity.class);
    intent.putExtra("count", listOfNames.size());
    startActivity(intent);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main_menu, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
    switch (item.getItemId()) {
        case R.id.changeDateTime:
            handleDate();

            return true;
        case R.id.pastAttendances:
            Intent intent = new Intent(this, PastAttendences.class);

            intent.putExtra("Title", subName);
            sharedPreferences = getSharedPreferences("MY_PREF", MODE_PRIVATE);
            editor = sharedPreferences.edit();

            String result = sharedPreferences.getString(DATETIME, null);



            intent.putExtra("key", result);

            editor.remove(DATETIME);
            editor.apply();
            startActivity(intent);

            return true;

        case R.id.saveButton:

            final String toolbarDateTime = toolbar.getSubtitle().toString();

            sharedPreferences = getSharedPreferences("MY_PREF", MODE_PRIVATE);
            editor = sharedPreferences.edit();
            editor.putString(DATETIME, toolbarDateTime);
            editor.apply();


            return true;
    }

    return super.onOptionsItemSelected(item);
}

public void handelTime(final CharSequence charSequence) {

    final Calendar calendar = Calendar.getInstance();

    int Hour = calendar.get(Calendar.HOUR);
    int Minute = calendar.get(Calendar.MINUTE);

    boolean is24Hour = android.text.format.DateFormat.is24HourFormat(this);

    TimePickerDialog timePickerDialog = new TimePickerDialog(this, new TimePickerDialog.OnTimeSetListener() {
        @Override
        public void onTimeSet(TimePicker view, int Hour, int Minute) {


            Calendar calendar1 = Calendar.getInstance();

            calendar1.set(Calendar.HOUR, Hour);
            calendar1.set(Calendar.MINUTE, Minute);

            CharSequence charSequence1 = android.text.format.DateFormat.format("HH:mm:ss a", calendar1);
            toolbar.setSubtitle(charSequence + " " + charSequence1);
        }
    }, Hour, Minute, is24Hour);
    timePickerDialog.show();
}

public void handleDate() {

    final Calendar calendar = Calendar.getInstance();

    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int date = calendar.get(Calendar.DATE);

    DatePickerDialog datePickerDialog = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {
        @Override
        public void onDateSet(DatePicker view, int year, int month, int date) {


            Calendar calendar1 = Calendar.getInstance();

            calendar1.set(Calendar.YEAR, year);
            calendar1.set(Calendar.MONTH, month);
            calendar1.set(Calendar.DATE, date);

            CharSequence charSequence = android.text.format.DateFormat.format("dd-MMM-yyyy", calendar1);

            handelTime(charSequence);
        }
    }, year, month, date);

    datePickerDialog.show();
}


private void buildRecyclerView() {

    recyclerView = findViewById(R.id.recyclerView2);
    recyclerView.hasFixedSize();
    layoutManager = new LinearLayoutManager(StudentListActivity.this);
    rAdapter = new AdapterForStudentList(this, listOfNames);

    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(rAdapter);

    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleCallback);
    itemTouchHelper.attachToRecyclerView(recyclerView);

}

public void insertData(String text, String t1, String t2) {
    ListOfNames lt = new ListOfNames(text, t1, t2);
    if (listOfNames.contains(lt)) {
        Toast.makeText(this, "Student Name Already exists!!", Toast.LENGTH_SHORT).show();
    } else {
        listOfNames.add(lt);
        rAdapter.notifyDataSetChanged();
    }

}

public void saveData() {
    sharedPreferences = getSharedPreferences("SHARED PREF", MODE_PRIVATE);
    editor = sharedPreferences.edit();

    Gson gson = new Gson();
    String json = gson.toJson(listOfNames);
    editor.putString(subName, json);
    editor.apply();
}

public void loadData() {


    sharedPreferences = getSharedPreferences("SHARED PREF", MODE_PRIVATE);

    Gson gson = new Gson();
    String json = sharedPreferences.getString(subName, null);
    Type type = new TypeToken<ArrayList<ListOfNames>>() {
    }.getType();

    listOfNames = gson.fromJson(json, type);

    if (listOfNames == null) {
        listOfNames = new ArrayList<>();
    }
}


ListOfNames deletedItem = null;
ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
        return false;
    }

    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
        final int position = viewHolder.getAdapterPosition();
        String name = listOfNames.get(position).getStudentName();

        deletedItem = listOfNames.get(position);
        listOfNames.remove(deletedItem);

        sharedPreferences = getSharedPreferences("SHARED PREF", MODE_PRIVATE);
        editor = sharedPreferences.edit();
        editor.remove("text");


        saveData();
        editor.apply();
        rAdapter.notifyItemRemoved(position);

        Snackbar.make(recyclerView, name + "Deleted", Snackbar.LENGTH_LONG)
                .setAction("Undo", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        listOfNames.add(position, deletedItem);
                        rAdapter.notifyItemInserted(position);

                        saveData();
                    }
                }).show();
    }

    @Override
    public void onChildDrawOver(@NonNull Canvas c, @NonNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        new RecyclerViewSwipeDecorator.Builder(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)

                .addSwipeLeftBackgroundColor(ContextCompat.getColor(StudentListActivity.this, R.color.my_background))
                .addSwipeLeftActionIcon(R.drawable.ic_delete_black_24dp)
                .create()
                .decorate();
        super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);

    }
};

public void fabButton() {
    FloatingActionButton floatingActionButton = findViewById(R.id.fab2);
    floatingActionButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            AlertDialog.Builder b = new AlertDialog.Builder(StudentListActivity.this);
            View view = getLayoutInflater().inflate(R.layout.dialogbox_frontpage, null);

            final EditText editText = view.findViewById(R.id.editText);
            b.setView(view);
            b.setTitle("Student name");
            b.setPositiveButton("ok", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    String text = editText.getText().toString().trim();

                    if (text.isEmpty()) {
                        Toast.makeText(StudentListActivity.this, "Please add subject name", Toast.LENGTH_SHORT).show();
                    } else {
                        insertData(text, t1, t2);
                        saveData();
                    }
                }
            });
            b.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            });
            b.setCancelable(false);
            b.show();
        }
    });
}

}

I made changes in the Adapter class for saving the state of the checkbox its working but when i am saving the state of the checkbox then,what i checked earlier is disappering and when i removed the saving code which is saving my state of checkbox then its工作正常復選框 state 沒有消失

實際上我不想這樣,我想在單擊按鈕時保存復選框的狀態,並想加載另一個沒有發生的活動。 你可以解釋嗎。 我想我很好地描述了我的問題......

這是上面代碼的 AdapterClass。

public class AdapterForStudentList extends RecyclerView.Adapter<AdapterForStudentList.StudentViewHolder> {

Context context;
private ArrayList<ListOfNames> mListOfNames;


public static class StudentViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    public TextView studentName, attendence, percentage;
    CheckBox mCheckedBox;
    private ItemClickListener itemClickListener;

    public StudentViewHolder(@NonNull View itemView) {
        super(itemView);
        studentName = itemView.findViewById(R.id.studentName);
        attendence = itemView.findViewById(R.id.attendence);
        percentage = itemView.findViewById(R.id.percentage);
        mCheckedBox = itemView.findViewById(R.id.mCheckBox);
        mCheckedBox.setOnClickListener(this);
    }

    public void setItemClickListener(ItemClickListener ic) {
        itemClickListener = ic;
    }

    @Override
    public void onClick(View v) {
        itemClickListener.onItemClick(v, getLayoutPosition());
    }

    interface ItemClickListener {
        void onItemClick(View v, int position);
    }

}

public AdapterForStudentList(Context context, ArrayList<ListOfNames> listOfNames) {
    this.context = context;
    mListOfNames = listOfNames;
}

@NonNull
@Override
public StudentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    View view = inflater.inflate(R.layout.check_box_cardview, parent, false);

    SharedPreferences preferences = context.getSharedPreferences("checkedItems", MODE_PRIVATE);
    boolean valueBoolean = preferences.getBoolean("KEY", false);
    SharedPreferences.Editor editor = preferences.edit();
    editor.putBoolean("KEY", valueBoolean);
    editor.apply();

    return new StudentViewHolder(view);
}

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

    ListOfNames currentItems = mListOfNames.get(position);
    holder.studentName.setText(currentItems.getStudentName());
    holder.attendence.setText(currentItems.getAttendent());
    holder.percentage.setText(currentItems.getPercetage());
    holder.mCheckedBox.setChecked(currentItems.getChecked());


    holder.setItemClickListener(new StudentViewHolder.ItemClickListener() {
        @Override
        public void onItemClick(View v, int position) {
            CheckBox checkBox = (CheckBox) v;

            ListOfNames currentItems = mListOfNames.get(position);

            if (checkBox.isChecked()) {

                currentItems.setChecked(true);

            } else {
                currentItems.setChecked(false);
            }
        }
    });
    holder.mCheckedBox.setChecked(getFromSp("mCheckedBox"+position));
    holder.mCheckedBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            saveInSp("mCheckedBox"+position, isChecked);

        }
    });
}



@Override
public int getItemCount() {
    return mListOfNames.size();
}
private boolean getFromSp(String key){
    SharedPreferences preferences = context.getSharedPreferences("checkedItems", MODE_PRIVATE);
    return preferences.getBoolean(key,false);
}

private void saveInSp(String key, boolean value) {
    SharedPreferences preferences = context.getSharedPreferences("checkedItems", MODE_PRIVATE);
    SharedPreferences.Editor editor = preferences.edit();
    editor.putBoolean(key, value);
    editor.apply();
}

}

您無需使用SharedPreferences來保存復選框的狀態。 您可以在ListOfNames class 中使用setChecked方法。

此外,為什么您在添加新項目時遇到該錯誤是因為當您調用onCheckedChanged時, CheckBox偵聽器的notifyDataSetChanged方法會被不必要地調用 這個概念是當你通知適配器時, 回收,換句話說, 它會重新創建視圖,因此如果復選框被選中然后它們又回到未選中狀態,它也可以調用onCheckedChanged修改先前的值。 (注意:我記得術語recyclerecreate不同)

解決此問題的一種方法是改用OnClickListener並從那里獲取CheckBox並查看其值。

所以而不是

holder.mCheckedBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        // ...
    }
});

將其更改為:

holder.mCheckedBox.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        CheckBox checkBox = (CheckBox) view;
        boolean isChecked = checkBox.isChecked();
        // ...
    }
});

那應該可以解決這種奇怪現象的發生。

回到使用SharedPreferences ,正如我已經建議的那樣,使用ListOfNames class 的setChecked方法(參見下面的代碼) 然后刪除與適配器內的SharedPreferences相關的任何內容。 而且因為您沒有添加新項目,也沒有刪除您選中的復選框,所以在用戶按下菜單中的保存按鈕之前,它不會保存。 在其中,您可以只使用StudentListActivitysaveData方法作為保存按鈕。

此外,刪除ItemClickListener接口和 ViewHolder 中的implements View.OnClickListener ViewHolder 這是相當多余的。

您的AdapterForStudentList現在應該如下所示:

public class AdapterForStudentList extends RecyclerView.Adapter<AdapterForStudentList.StudentViewHolder> {

    private Context context;
    private ArrayList<ListOfNames> mListOfNames;

    public static class StudentViewHolder extends RecyclerView.ViewHolder {
        public TextView studentName, attendence, percentage;
        CheckBox mCheckedBox;

        public StudentViewHolder(@NonNull View itemView) {
            super(itemView);
            studentName = itemView.findViewById(R.id.studentName);
            attendence = itemView.findViewById(R.id.attendence);
            percentage = itemView.findViewById(R.id.percentage);
            mCheckedBox = itemView.findViewById(R.id.mCheckBox);
        }

    }

    public AdapterForStudentList(Context context, ArrayList<ListOfNames> listOfNames) {
        this.context = context;
        mListOfNames = listOfNames;
    }

    @NonNull
    @Override
    public StudentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View view = inflater.inflate(R.layout.check_box_cardview, parent, false);
        return new StudentViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull StudentViewHolder holder, final int position) {
        final ListOfNames currentItems = mListOfNames.get(position);
        holder.studentName.setText(currentItems.getStudentName());
        holder.attendence.setText(currentItems.getAttendent());
        holder.percentage.setText(currentItems.getPercetage());
        holder.mCheckedBox.setChecked(currentItems.getChecked());

        holder.mCheckedBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                CheckBox checkBox = (CheckBox) view;
                boolean isChecked = checkBox.isChecked();
                currentItems.setChecked(isChecked);
            }
        });
    }

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



注意:不要忘記實現將阻止用戶添加或刪除項目的約束。 並不是說會有什么宏大的例外,而是會讓你的存檔功能失效

此外,我的印象是您希望能夠添加/刪除項目,同時還能夠選中/取消選中復選框。 我想出的解決方案是創建另一個列表來保存選中復選框的位置,然后在用戶點擊保存按鈕時使用它。 (請參閱下面的更新帖子)這應該使您能夠添加/刪除和檢查/取消選中,同時在用戶這樣做之前還不能保存檢查。 (如果你想要這個,我可以制作代碼並放在這里)

最后一件事,如果您確實設置了約束,那么我認為使用OnCheckedChangedListener而不是我上面所做的實現沒有問題,因為除了添加/刪除項目之外,我覺得您不會在其他任何地方調用notifyDataSetChanged

希望我澄清了一些事情。



更新:實現更改列表的功能和僅在用戶操作時保存復選框狀態的功能

我之前給你的解決方案是創建一個列表來放置檢查項目的位置,這實際上不是一個好主意 如果我們從列表中刪除怎么辦? 或者更糟糕的是,如果我們對列表進行排序呢?

這是我認為最好的方法:創建一個臨時變量來保存復選框的臨時 state,並且僅在用戶點擊保存時傳遞其值。 當我們使用Gson轉換瞬態變量時,它不會序列化/包含在 json 字符串中。

因此,在您的ListOfNames class 中,我建議創建該瞬態變量。 並將其用於臨時檢查/取消檢查。 僅當用戶真正想要時才將其保存到SharedPreferences中。

您的ListOfNames應如下所示:

public class ListOfNames {
    // variables...

    // Create a transient variable to hold the temporary state of the check box
    private transient boolean tempChecked;

    // constructor and other methods...

    // Couple of methods for operations on temporary checks and actual checks
    public void setTemporaryChecked(boolean checked) {
        tempChecked = checked;
    }

    public boolean getTemporaryChecked() {
        return tempChecked;
    }

    public void checkedToTemporaryChecked() {
        tempChecked = checked;
    }

    public void temporaryCheckedToChecked() {
        checked = tempChecked;
    }
}

onBindViewHolderCheckBox的偵聽器內部:

// Get the temporary checked value instead of the actual one
// (Because you know, RecyclerView recycles views)
holder.mCheckedBox.setChecked(currentItems.getTemporaryChecked());

holder.mCheckedBox.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        CheckBox checkBox = (CheckBox) view;
        boolean isChecked = checkBox.isChecked();
        // Set the temporary checked instead
        currentItems.setTemporaryChecked(isChecked);
    }
});

在您的loadData方法中:

public void loadData() {
    // ...

    // Set our temporary checks
    // Important because transient variables don't get included in Json string
    for (ListOfNames current: listOfNames)
        current.checkedToTemporaryChecked();
}

最后在菜單中的保存邏輯代碼中( saveData方法中):

case R.id.saveButton:
    // ...

    // Convert temporary checks to actual checks
    for (ListOfNames current: listOfNames)
        current.temporaryCheckedToChecked();
    saveData();

    return true;
// ...

完成了,您應該可以添加。 刪除甚至排序列表(如果您想稍后添加此功能)而不影響復選框,並且僅在用戶這樣做時才保存這些復選框的值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM