写入文件后RecyclerView无法显示数据的技术问题咨询
问题:写入JSON到文件后RecyclerView无法显示数据
问题背景
我在Android项目中尝试把JSON数据同时写入文件并在RecyclerView中展示,但遇到了一个奇怪的问题:
- 不添加
bw.write()和bw.close()时,RecyclerView能正常显示数据 - 添加这两行代码后,数据成功写入文件,但RecyclerView完全不显示内容
以下是我的相关代码:
1. 创建目录与文件的代码
public void filecreation() throws IOException { File mediaStorageDir = new File(getActivity().getFilesDir() + "/" + "Zerribelum"); if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { Log.d("App", "failed to create directory"); } else { Log.d("Apppppp", "create directory"); File textfolder = new File(mediaStorageDir, "Text"); if (!textfolder.exists()) { textfolder.mkdirs(); File newtext = new File(textfolder, "dummy.txt"); stream = new FileOutputStream(newtext); bw = new BufferedWriter(new OutputStreamWriter(stream)); } File imagefolder = new File(mediaStorageDir, "Image"); if (!imagefolder.exists()) { imagefolder.mkdirs(); } File videofolder = new File(mediaStorageDir, "Video"); if (!videofolder.exists()) { videofolder.mkdirs(); } } } }
2. 处理JSON并写入文件、更新RecyclerView的代码
try { JSONArray mJsonTopicArray = mJsonObject.getJSONArray(AppConstants.APIKeys.TOPICS_LIST); for (int i = 0; i < mJsonTopicArray.length(); i++) { Topics mTopics = new Topics(); mTopics.setId(mJsonTopicArray.getJSONObject(i).getString(AppConstants.APIKeys.ID)); mTopics.setTitle(mJsonTopicArray.getJSONObject(i).getString(AppConstants.APIKeys.TOPICS)); mTopics.setImage(mJsonTopicArray.getJSONObject(i).getString(AppConstants.APIKeys.TOPICS_IMAGE)); mTopics.setDescription(mJsonTopicArray.getJSONObject(i).getString(AppConstants.APIKeys.DESCRIPTION)); mTopicsArrayList.add(mTopics); bw.write(mJsonTopicArray.getJSONObject(i).getString(AppConstants.APIKeys.DESCRIPTION)); bw.newLine(); } bw.close(); mCategoryListRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); mCategoryListRecyclerView.setHasFixedSize(true); mCategoryListRecyclerView.setAdapter(new ParallaxRecyclerAdapter(context, HomeFragment.this, mTopicsArrayList)); } catch (JSONException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); }
注:已经初始化了public FileOutputStream stream;和public BufferedWriter bw;
问题根源分析
兄弟,我一眼就揪出问题所在了——你的BufferedWriter初始化逻辑有严重漏洞,而且宽泛的异常处理把关键错误给掩盖了!
仔细看你的filecreation()方法:
- 只有当
Zerribelum目录不存在、并且成功创建的情况下,才会进入初始化bw的分支 - 如果
Text目录已经存在(比如第二次运行APP),也不会初始化bw
这就导致:只要不是第一次全新安装运行APP,bw都会是null!这时候你调用bw.write()或bw.close(),直接就会抛出NullPointerException,但你的catch (Exception e)只是打印堆栈,不会中断流程?不对——实际上抛出异常后,try块里后面的RecyclerView初始化代码根本不会执行!
你以为数据成功写入文件?那只有第一次运行时才会发生,第二次运行时bw是null,抛异常后数据根本没写入,RecyclerView的代码也没执行,所以才会出现“写入文件后RecyclerView不显示”的假象。
解决方案
1. 修复BufferedWriter的初始化逻辑
不管目录是否已经存在,都要确保bw被正确初始化,同时用更安全的路径构造方式:
public void filecreation() throws IOException { // 用File的构造函数拼接路径,避免手动拼接出现错误 File mediaStorageDir = new File(getActivity().getFilesDir(), "Zerribelum"); // 确保目录存在,不存在就创建 if (!mediaStorageDir.exists() && !mediaStorageDir.mkdirs()) { Log.d("App", "failed to create directory"); throw new IOException("Failed to create directory: " + mediaStorageDir.getAbsolutePath()); } File textfolder = new File(mediaStorageDir, "Text"); if (!textfolder.exists() && !textfolder.mkdirs()) { Log.d("App", "failed to create Text directory"); throw new IOException("Failed to create Text directory: " + textfolder.getAbsolutePath()); } File newtext = new File(textfolder, "dummy.txt"); // 如果需要追加内容,把第二个参数改成true stream = new FileOutputStream(newtext); bw = new BufferedWriter(new OutputStreamWriter(stream)); // 其他目录创建逻辑不变 File imagefolder = new File(mediaStorageDir, "Image"); if (!imagefolder.exists()) { imagefolder.mkdirs(); } File videofolder = new File(mediaStorageDir, "Video"); if (!videofolder.exists()) { videofolder.mkdirs(); } }
2. 优化异常处理,确保RecyclerView代码能执行
不要用catch (Exception e)这种大而化之的捕获,要精准捕获异常并打印详细信息,同时确保bw初始化后再使用:
try { // 先确保文件和流初始化完成 filecreation(); JSONArray mJsonTopicArray = mJsonObject.getJSONArray(AppConstants.APIKeys.TOPICS_LIST); mTopicsArrayList.clear(); // 先清空列表,避免重复添加旧数据 for (int i = 0; i < mJsonTopicArray.length(); i++) { JSONObject topicObj = mJsonTopicArray.getJSONObject(i); // 提取出来,减少重复调用 Topics mTopics = new Topics(); mTopics.setId(topicObj.getString(AppConstants.APIKeys.ID)); mTopics.setTitle(topicObj.getString(AppConstants.APIKeys.TOPICS)); mTopics.setImage(topicObj.getString(AppConstants.APIKeys.TOPICS_IMAGE)); mTopics.setDescription(topicObj.getString(AppConstants.APIKeys.DESCRIPTION)); mTopicsArrayList.add(mTopics); // 写入文件 bw.write(topicObj.getString(AppConstants.APIKeys.DESCRIPTION)); bw.newLine(); } // 先刷新流,确保数据写入文件,再关闭 bw.flush(); bw.close(); stream.close(); // 现在这部分代码肯定能执行到 mCategoryListRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); mCategoryListRecyclerView.setHasFixedSize(true); ParallaxRecyclerAdapter adapter = new ParallaxRecyclerAdapter(context, HomeFragment.this, mTopicsArrayList); mCategoryListRecyclerView.setAdapter(adapter); adapter.notifyDataSetChanged(); // 显式通知数据变化,确保RecyclerView更新 } catch (JSONException e) { Log.e("JSON_ERROR", "解析JSON失败", e); } catch (IOException e) { Log.e("FILE_ERROR", "文件操作失败", e); } catch (NullPointerException e) { Log.e("NULL_ERROR", "BufferedWriter未初始化", e); }
3. 额外优化建议
- 不要把
stream和bw声明为全局变量,最好在方法内部声明,避免资源泄漏 - 使用
try-with-resources语法,自动关闭流,不用手动调用close():
try (FileOutputStream stream = new FileOutputStream(newtext); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(stream))) { // 写入文件的逻辑 } catch (IOException e) { Log.e("FILE_ERROR", "写入文件失败", e); }
内容的提问来源于stack exchange,提问作者anju jo
相关产品推荐
相关产品推荐

