SharedPreferences实现视频完成标记功能空指针异常求助
嘿,我来帮你搞定这个烦人的空指针问题!从你的报错日志和代码来看,核心问题一眼就能看出来:你要操作的completedTick这个ImageView对象始终是null,所以调用它的setVisibility()方法才会抛出NullPointerException。咱一步步拆解原因,再给你针对性的解决方案:
先看你两次报错的核心原因
第一次报错(onCreateView里的问题)
你在onCreateView里的执行顺序搞反了:
// 先调用了判断逻辑,这时候completedTick还没初始化! if(activityCompleted == false || activityCompleted == null ) { completedTick.setVisibility(view.INVISIBLE); }else{ completedTick.setVisibility(View.VISIBLE); } // 之后才调用initialiseRecyclerView,里面才会初始化completedTick initialiseRecyclerView(view);
这就好比你想开灯,但灯还没装上去,肯定会出问题!
第二次报错(onViewCreated里的问题)
你把逻辑移到了onViewCreated,但这里有两个大概率的坑:
- ID不匹配:你代码里写的是
R.id.completedTickImage,但之前第一次用的是R.id.completedTick,得确认你的布局文件里这个ImageView的ID到底是啥,拼写差一个字符都找不到控件! - 控件在RecyclerView的Item里:如果这个对勾是每个视频条目旁边的,那它是在RecyclerView的item布局里,不是Fragment的根布局。这种情况下,你直接用
view.findViewById()是绝对找不到的——因为RecyclerView的item是动态加载的,每个item都有自己的completedTick,不能在Fragment的生命周期方法里直接获取单个实例。
针对性解决方案
情况1:对勾在Fragment根布局(不是每个视频条目都有)
如果是这种场景,那你只需要做两件事:
- 把布局文件里的ImageView ID和代码里的统一,比如布局里是
android:id="@+id/completedTick",代码里就别写成completedTickImage。 - 确保先初始化控件,再调用
setVisibility():
@Override public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // 先初始化SharedPreferences loginPref = getContext().getSharedPreferences("loginPref", Context.MODE_PRIVATE); activityPref = getContext().getSharedPreferences("activityPref", Context.MODE_PRIVATE); activityCompleted = activityPref.getBoolean("activityCompleted", true); // 先找到控件! completedTick = view.findViewById(R.id.completedTick); // 再调用其他方法 initialiseRecyclerView(view); retrieveActivities(); // 最后设置可见性 if (activityCompleted == false || activityCompleted == null) { completedTick.setVisibility(View.INVISIBLE); } else { completedTick.setVisibility(View.VISIBLE); } }
情况2:对勾在RecyclerView的每个视频条目里(这才是你要的场景)
这应该是你真实的需求——每个视频旁边都有自己的完成对勾,这时候必须在RecyclerView的Adapter里处理,而不是在Fragment里直接操作:
第一步:修改RecyclerView的Adapter
public class ActivitiesAdapter extends RecyclerView.Adapter<ActivitiesAdapter.ViewHolder> { private List<YourActivityModel> activityList; // 替换成你的视频数据模型类 private SharedPreferences activityPref; // 构造方法传入数据和上下文,用来获取SharedPreferences public ActivitiesAdapter(List<YourActivityModel> activityList, Context context) { this.activityList = activityList; this.activityPref = context.getSharedPreferences("activityPref", Context.MODE_PRIVATE); } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { // 加载你的item布局 View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.your_activity_item_layout, parent, false); return new ViewHolder(itemView); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { YourActivityModel currentActivity = activityList.get(position); // 关键:用每个视频的唯一标识(比如activityId)作为SharedPreferences的key // 这样每个视频的完成状态是独立的 boolean isCompleted = activityPref.getBoolean("completed_" + currentActivity.getId(), false); // 根据状态设置对勾的可见性 if (isCompleted) { holder.completedTick.setVisibility(View.VISIBLE); } else { holder.completedTick.setVisibility(View.INVISIBLE); } // 这里设置视频的其他内容,比如标题、封面等 // holder.titleTextView.setText(currentActivity.getTitle()); } @Override public int getItemCount() { return activityList.size(); } // ViewHolder里初始化item里的控件 public static class ViewHolder extends RecyclerView.ViewHolder { ImageView completedTick; // 其他控件,比如TextView titleTextView; public ViewHolder(@NonNull View itemView) { super(itemView); completedTick = itemView.findViewById(R.id.completedTick); // titleTextView = itemView.findViewById(R.id.activityTitle); } } }
第二步:在Fragment里初始化Adapter
修改你的initialiseRecyclerView方法:
private void initialiseRecyclerView(View view) { mRecyclerView = view.findViewById(R.id.recyclerViewActivities); mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); // 假设你已经获取到了视频列表数据activityList ActivitiesAdapter adapter = new ActivitiesAdapter(activityList, getContext()); mRecyclerView.setAdapter(adapter); }
第三步:修改视频页面的完成状态保存逻辑
现在要保存单个视频的完成状态,而不是全局的一个值:
// 先从Intent里拿到当前视频的唯一ID(你需要在跳转视频页面时传递这个ID) private String currentActivityId; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.youtube_layout); activityPref = getSharedPreferences("activityPref", MODE_PRIVATE); // 获取传递过来的视频ID currentActivityId = getIntent().getStringExtra("ACTIVITY_ID"); // 其他初始化逻辑... markActivityAsCompleted(); } private void markActivityAsCompleted() { SharedPreferences.Editor editor = activityPref.edit(); // 用视频ID作为key的一部分,保存该视频已完成 editor.putBoolean("completed_" + currentActivityId, true); editor.apply(); }
最后再提醒两句
- 空指针的本质就是“你要操作的对象不存在”,遇到这种问题先检查对象是否初始化、ID是否匹配、控件所在的布局是否正确。
- 对于RecyclerView的item控件,绝对不能在Fragment/Activity的生命周期方法里直接获取,必须在Adapter的ViewHolder和onBindViewHolder里处理。
内容的提问来源于stack exchange,提问作者androidnewbie
相关产品推荐
相关产品推荐

