Сохранение переменной из адаптера в SharedPreference
Есть приложение, которое получает данные из сервера и выводит в список RecyclerView.
В каждом item находится checkbox в виде изображения сердечка. При нажатии на это сердечко оно должно менять цвет, но это не главное. Главное - оно должно сохранять свое состояние при следующем запуске приложения с помощью SharedPreference. Так как мне сохранить это значение из адаптера и проверять его в onCreate?
Активити, в котором выводится список
public class CatalogActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private Toolbar toolbar;
private CatalogAdapter catalogAdapter;
private ImageView imageFavorites;
private boolean favorite;
private SharedPreferences sharedPreferences;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_catalog);
toolbar = findViewById(R.id.toolbar_catalog);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
//sharedPreferences = getPreferences(MODE_PRIVATE);
recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
getData();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_toolbar_catalog, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home)
//Возврат на предыдущий экран
{
int backStackEntryCount = getSupportFragmentManager().getBackStackEntryCount();
if (backStackEntryCount > 0) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} else {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
}
onBackPressed();
}
//Переход в активити корзину
if (id == R.id.menu_basket) {
startActivity(new Intent(CatalogActivity.this, BasketActivity.class));
}
return super.onOptionsItemSelected(item);
}
//Получение данных с сервера
public void getData(){
NetworkRequest.getRequest()
.getTestApi()
.getTestModel()
.enqueue(new Callback<ArrayList<Item>>() {
@Override
public void onResponse(Call<ArrayList<Item>> call, Response<ArrayList<Item>> response) {
ArrayList<Item> item = response.body();
catalogAdapter = new CatalogAdapter(CatalogActivity.this, item);
recyclerView.setAdapter(catalogAdapter);
}
@Override
public void onFailure(Call<ArrayList<Item>> call, Throwable t) {
Toast.makeText(CatalogActivity.this, "Безуспешно", Toast.LENGTH_SHORT).show();
}
});
}
}
Адаптер
public class CatalogAdapter extends RecyclerView.Adapter<CatalogAdapter.CatalogViewHolder> {
Context context;
ArrayList<Item> arrayList;
SharedPreferences sharedPreferences;
int id;
public CatalogAdapter(Context context, ArrayList<Item> arrayList){
this.context = context;
this.arrayList = arrayList;
}
@NonNull
@Override
public CatalogViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
return new CatalogViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull CatalogViewHolder holder, int position) {
Item item = arrayList.get(position);
holder.title.setText(item.getTitle());
holder.text.setText(item.getBrand());
holder.price.setText(String.valueOf(item.getPrice()));
Picasso.with(context)
.load(item.getImageLink())
.into(holder.imageView);
}
@Override
public int getItemCount() {
return arrayList.size();
}
public class CatalogViewHolder extends RecyclerView.ViewHolder {
ImageView imageView, imageFavorites;
TextView title, text, price;
int id;
CheckBox checkBox;
boolean favorite;
public CatalogViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imageViewItem);
title = itemView.findViewById(R.id.titleItem);
text = itemView.findViewById(R.id.textItem);
price = itemView.findViewById(R.id.priceItem);
checkBox = itemView.findViewById(R.id.checkbox_favorite_item);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (checkBox.isChecked()){
Toast.makeText(context, "Добавлено в корзину", Toast.LENGTH_SHORT).show();
favorite = true;
}else{
Toast.makeText(context, "Удалено из корзины", Toast.LENGTH_SHORT).show();
favorite = false;
}
}
});
}
}
}
Не могу создать экземпляр класса SharedPreference в адаптере. Как организовать логику сохранение состояния?
Ответы (2 шт):
Ваш адаптер не должен знать о существовании всяких там адаптеров. Он должен уметь ТОЛЬКО РИСОВАТЬ. Ваши данные могут попадать откуда угодно, и RecyclerAdapter не должен зависеть от источника подачи данных.
Я бы сделал это примерно так:
Допустим мы получаем от сервера ответ в виде списка List<Items>. Создаем модельку вроде:
class UiItem {
private final Item item;
private final boolean isLiked;
// любые другие поля нужные для отображения в адаптере
// getters/setters
}
Собственно где-нибудт в. Presenter/ViewModel мы весь этот список List<Item> оборачиваем в список List<UiItem>.
List<UiItem> mapToUiModel(List<Item> items){
List<UiItem> uiItems = new ArrayList();
for(Item item : items){
uiItems.add(new UiItem(item, sharedPreference.getLiked(item.id)));
}
return uiItems;
}
И на вход адаптера мы уже передаем список в котором есть лайканые или не лайканые элементы.
Когда вы обрабатываете клик на лайк, вы сохраняете поле isLiked в SharedPreference по id и полностью в вашем Presenter/ViewModel прогоняете мапинг и снова обновляете ваш адаптер.
Чтоб не обновлять всякий раз весь адаптер, а менять только измененные элементы используйте DiffUtils.
В методе onBindViewHolder вызвал методы которые отвечают за сохранение - save и за загрузку - load
@Override
public void onBindViewHolder(@NonNull CatalogViewHolder holder, int position) {
Item item = arrayList.get(position);
holder.title.setText(item.getTitle());
holder.text.setText(item.getBrand());
holder.price.setText(String.valueOf(item.getPrice()));
Picasso.with(context)
.load(item.getImageLink())
.into(holder.imageView);
holder.favorites.setChecked(load(String.valueOf(position)));
holder.favorites.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
save(String.valueOf(position), true);
}
});
}
Сами методы (в том же классе - CatalogAdapter)
public void save(String key, boolean value){
SharedPreferences sharedPreferences = context.getSharedPreferences("Values", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(key, value);
editor.commit();
}
public boolean load(String key){
SharedPreferences sharedPreferences = context.getSharedPreferences("Values", Context.MODE_PRIVATE);
return sharedPreferences.getBoolean(key, false);
}