如何用SharedPreferences保存RecyclerView中CardView的图片状态?
Got it, let's work through this step by step. You want each CardView's image state to stick around even after closing the app or navigating back—SharedPreferences is exactly the right tool for this. Here's how to modify your adapter and handle the logic properly:
1. Fix the ViewHolder Global Variable Bug
First up, remove the global holder variable in your adapter. It’s unnecessary and will cause weird issues with RecyclerView’s view recycling. Your onCreateViewHolder should just create and return a ViewHolder locally:
// Delete this line from your adapter class // private ViewHolder holder; @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listitem_lesson_rec_view, parent, false); return new ViewHolder(view); // Create and return directly, no global holder needed }
2. Integrate SharedPreferences for State Storage
We’ll use each lesson’s lessonId as a unique key to store its image state. This way, every lesson’s state stays independent.
a. Load Saved State in onBindViewHolder
Instead of always loading the plain image, check SharedPreferences first to see if a saved state exists, then load the matching image:
@Override public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) { Log.d(TAG, "onBindViewHolder: called"); Lesson currentLesson = lessons.get(position); holder.txtLessons.setText(currentLesson.getLessonNumber()); final int imgSad = R.mipmap.sad; final int imgSmile = R.mipmap.smile; final int imgPlain = R.mipmap.plain; // Get our SharedPreferences instance (named "LessonStates" to keep things organized) SharedPreferences prefs = context.getSharedPreferences("LessonStates", MODE_PRIVATE); // Read the saved state for this lesson—default to 0 (plain image) if no state exists int imageState = prefs.getInt("lesson_" + currentLesson.getLessonId(), 0); // Pick the right image based on the saved state int imageToLoad = imgPlain; switch (imageState) { case 1: imageToLoad = imgSmile; break; case 2: imageToLoad = imgSad; break; default: imageToLoad = imgPlain; } Glide.with(context) .asBitmap() .load(imageToLoad) .into(holder.imageView); // ... rest of your click listener code }
b. Update State When Returning from the Lesson Activity
When the user finishes with Lesson1Activity and navigates back, we need to save the new state (e.g., mark it as completed with the smile image). Add this code to Lesson1Activity:
// Inside Lesson1Activity.java @Override protected void onDestroy() { super.onDestroy(); // Save the state for lesson 1 (we'll use 1 to represent the smile image) SharedPreferences prefs = getSharedPreferences("LessonStates", MODE_PRIVATE); prefs.edit().putInt("lesson_1", 1).apply(); }
If you only want to update the state after a specific action (like clicking a "Complete" button in Lesson1Activity), move the prefs.edit() code to that button’s onClick listener instead.
c. Refresh the RecyclerView When Returning
To make the image update right away when the user comes back to the RecyclerView screen, override onResume in the parent Activity (the one holding the RecyclerView):
// Inside your Activity with the RecyclerView @Override protected void onResume() { super.onResume(); // Tell the adapter to reload data and update all views yourLessonAdapter.notifyDataSetChanged(); }
Replace yourLessonAdapter with the actual instance of LessonRecViewAdapter in your Activity.
3. Optional: Update Image Immediately on Click (If Needed)
If you want the image to change as soon as the user taps the CardView (before navigating), add the state save code directly to the onClick listener:
holder.cardView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int lessonId = currentLesson.getLessonId(); switch (lessonId) { case 1: // Save the state first SharedPreferences prefs = context.getSharedPreferences("LessonStates", MODE_PRIVATE); prefs.edit().putInt("lesson_" + lessonId, 1).apply(); // Update the current CardView's image right away Glide.with(context) .asBitmap() .load(imgSmile) .into(holder.imageView); // Navigate to Lesson1Activity Intent intent = new Intent(context, Lesson1Activity.class); context.startActivity(intent); break; case 2: Toast.makeText(context, "Comming Soon", Toast.LENGTH_SHORT).show(); break; default: break; } } });
Quick Notes
- We use
LessonStatesas the SharedPreferences file name to keep all lesson states grouped together. - Each lesson’s state uses a unique key like
lesson_1orlesson_2to avoid conflicts. - Using
apply()instead ofcommit()for edits is better—it’s asynchronous and won’t block the main thread.
内容的提问来源于stack exchange,提问作者Mak

