Kotlin故事书App开发遇FileNotFoundException求助
问题描述
我是编程新手,正在使用Kotlin开发一款故事书App,计划在Home Fragment中通过Assets加载本地contents.json文件,并搭配Glide实现功能。但运行时触发了InvocationTargetException,其根源为FileNotFoundException,具体错误日志、相关代码如下,请求帮忙修复该问题:
报错信息
FATAL EXCEPTION: main Process: com.example.mykotlinapp, PID: 19988 java.lang.RuntimeException: java.lang.reflect.InvocationTargetException at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:558) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:957) Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Method.invoke(Native Method at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:957) Caused by: java.io.FileNotFoundException: contents.json
Home Fragment代码
private lateinit var bookAdapter: BookAdapter private lateinit var recyclerView: RecyclerView private lateinit var dataList: ArrayList<BooksData> override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { val view = inflater.inflate(R.layout.fragment_home, container, false) // Initialize the RecyclerView dataList = ArrayList() recyclerView = view.findViewById(R.id.bookRecyclerView) recyclerView.layoutManager = GridLayoutManager(requireContext(), 2) bookAdapter = BookAdapter(this@HomeFragment, dataList) recyclerView.adapter = bookAdapter recyclerView.setHasFixedSize(true) loadData() // loadJson() return view } private fun loadData() { val jsonString = loadJson("contents.json") val items = parseJson(jsonString) bookAdapter.setData(items) } private fun loadJson(contents: String): String { val inputStream = this.requireContext().assets.open(contents) val size = inputStream.available() val buffer = ByteArray(size) inputStream.read(buffer) inputStream.close() return String(buffer) } private fun parseJson(jsonString: String): ArrayList<BooksData> { val dataList = ArrayList<BooksData>() val jsonArray = JSONArray(jsonString) for (i in 0 until jsonArray.length()) { val jsonObject = jsonArray.getJSONObject(i) val bookName = jsonObject.getString("bookName") val imageUrl = jsonObject.getString("imageUrl") dataList.add(BooksData(imageUrl, bookName)) }; return dataList } }
数据类代码
data class BooksData(val bookName:String, val imageUrl:String){ }
Adapter代码
class BookAdapter(var context: HomeFragment, private var dataList: ArrayList<BooksData>) : RecyclerView.Adapter<BookAdapter.BookViewHolder>() { inner class BookViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { var bookNameTextView: TextView = itemView.findViewById(R.id.bookName) var bookImageView: ImageView = itemView.findViewById(R.id.imageUrl) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BookViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.book_category_item, parent, false) return BookViewHolder(view) } override fun getItemCount(): Int = dataList.size fun setData(data: ArrayList<BooksData>) { dataList.clear() dataList.addAll(data) notifyDataSetChanged() } override fun onBindViewHolder(holder: BookViewHolder, position: Int) { val item = dataList[position] holder.bookNameTextView.text = item.bookName Glide.with(context) .load(item.imageUrl) .placeholder(R.drawable.ic_launcher_background) .error(R.drawable.vec_quiz) .into(holder.bookImageView) } }
JSON文件内容
{ "items": [ { "bookName": "Basic Grammar", "imageUrl": "https://drive.google.com/uc?id=1_eVoTO4IeTW1gAbNBb_0-GWASecBNGgS" } , { "bookName": "Basic Grammar", "imageUrl": "https://drive.google.com/uc?id=1_eVoTO4IeTW1gAbNBb_0-GWASecBNGgS" } ] }
解决方案
1. 解决FileNotFoundException
- 检查assets目录结构:确保在
src/main目录下创建了assets文件夹(不是res目录下),并将contents.json文件放在该文件夹根目录。Android文件名区分大小写,确认文件名拼写完全一致(包括大小写)。 - 确认文件路径:如果JSON文件在assets的子文件夹中,需要传入完整路径(如
"books/contents.json"),当前代码使用的是根目录路径,确保文件位置正确。
2. 修复JSON解析错误
当前parseJson方法错误地将整个JSON对象当成JSONArray解析,实际JSON外层是包含items数组的JSONObject。修改方法如下:
private fun parseJson(jsonString: String): ArrayList<BooksData> { val dataList = ArrayList<BooksData>() // 先解析外层JSONObject val rootObject = JSONObject(jsonString) // 获取items数组 val jsonArray = rootObject.getJSONArray("items") for (i in 0 until jsonArray.length()) { val itemObj = jsonArray.getJSONObject(i) val bookName = itemObj.getString("bookName") val imageUrl = itemObj.getString("imageUrl") // 修正数据类参数顺序(原代码传反了) dataList.add(BooksData(bookName, imageUrl)) } return dataList }
3. 修正数据类参数传递顺序
原代码中BooksData(imageUrl, bookName)的参数顺序与数据类定义(bookName:String, imageUrl:String)相反,会导致数据错位,已经在上面的解析方法中修正。
4. 优化Adapter避免内存泄漏
Adapter中传入HomeFragment作为Context存在内存泄漏风险,改为传入Context:
// 修改Adapter构造函数 class BookAdapter(private val context: Context, private var dataList: ArrayList<BooksData>) : RecyclerView.Adapter<BookAdapter.BookViewHolder>() { // 其他代码不变,Glide使用context即可 override fun onBindViewHolder(holder: BookViewHolder, position: Int) { val item = dataList[position] holder.bookNameTextView.text = item.bookName Glide.with(context) .load(item.imageUrl) .placeholder(R.drawable.ic_launcher_background) .error(R.drawable.vec_quiz) .into(holder.bookImageView) } } // 在HomeFragment中初始化Adapter时修改为: bookAdapter = BookAdapter(requireContext(), dataList)
5. 添加异常处理增强稳定性
在loadJson方法中添加异常捕获,避免崩溃并便于调试:
private fun loadJson(filename: String): String? { return try { val inputStream = requireContext().assets.open(filename) val size = inputStream.available() val buffer = ByteArray(size) inputStream.read(buffer) inputStream.close() String(buffer) } catch (e: IOException) { e.printStackTrace() null } } // 对应的loadData方法增加空值判断: private fun loadData() { val jsonString = loadJson("contents.json") ?: run { Toast.makeText(requireContext(), "数据加载失败", Toast.LENGTH_SHORT).show() return } val items = parseJson(jsonString) bookAdapter.setData(items) }
内容的提问来源于stack exchange,提问作者Anoop Moji
相关产品推荐
相关产品推荐

