[英]How to save the state of Multiple checkbox using a Button click
在我的應用程序中,我有一個ArrayList
的recyclerView
,其中我在 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
修改先前的值。 (注意:我記得術語recycle與recreate不同)
解決此問題的一種方法是改用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
相關的任何內容。 而且因為您沒有添加新項目,也沒有刪除您選中的復選框,所以在用戶按下菜單中的保存按鈕之前,它不會保存。 在其中,您可以只使用StudentListActivity
的saveData
方法作為保存按鈕。
此外,刪除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;
}
}
在onBindViewHolder
中CheckBox
的偵聽器內部:
// 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.