Android应用InflateException报错求助:RecyclerView加载海报布局失败
Android RecyclerView布局膨胀崩溃问题解决方案
问题场景
用Kotlin开发讲座推荐APP,通过Retrofit2获取图片URL并在主界面RecyclerView展示海报时,APP崩溃,报错信息如下:
E/RecyclerView: No adapter attached; skipping layout D/AndroidRuntime: Shutting down VM E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.looc, PID: 19848 android.view.InflateException: Binary XML file line #2 in com.example.looc:layout/item_poster: Binary XML file line #2 in com.example.looc:layout/item_poster: Error inflating class <unknown> Caused by: android.view.InflateException: Binary XML file line #2 in com.example.looc:layout/item_poster: Error inflating class <unknown> Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Constructor.newInstance0(Native Method) ... Caused by: java.lang.UnsupportedOperationException: Failed to resolve attribute at index 35: TypedValue{t=0x2/d=0x7f03036b a=-1} at android.content.res.TypedArray.getDrawableForDensity(TypedArray.java:998) ...
相关代码与布局
item_poster.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="wrap_content" android:foreground="?selectableItemBackgroundBorderless" android:layout_margin="2dp" android:clickable="true" android:focusable="true" android:orientation="vertical" tools:targetApi="m" tools:ignore="UnusedAttribute"> <ImageView android:id="@+id/poster_image" android:layout_width="105dp" android:layout_height="140dp" android:scaleType="centerCrop" android:background="@drawable/poster_bg" /> </LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:background="@color/main_background_color" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".view.MainActivity"> <androidx.fragment.app.FragmentContainerView android:layout_width="match_parent" android:layout_height="260dp" android:layout_marginBottom="10dp" android:id="@+id/fragment_first" android:name="com.example.looc.view.FeedFragment"/> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recommend_recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:nestedScrollingEnabled="false" android:orientation="horizontal" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:listitem="@layout/item_poster" /> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_nav_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:background="@color/black" app:itemIconTint="@color/bottom_navigation_color" app:itemTextColor="@color/bottom_navigation_color" app:menu="@menu/bottom_navigation_menu" /> </LinearLayout>
MainActivity.kt
package com.example.looc.view import RetrofitInterface import android.content.Intent import android.graphics.Bitmap import android.graphics.BitmapFactory import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView import androidx.recyclerview.widget.RecyclerView import com.example.looc.R import com.example.looc.data.LectureDetailItem import com.example.looc.server.RetrofitClient import retrofit2.Call import retrofit2.Callback import retrofit2.Response import java.io.IOException import java.net.HttpURLConnection import java.net.URL class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val recommendRecyclerView = findViewById<RecyclerView>(R.id.recommend_recycler_view) val recommendLectureList = mutableListOf<String>() val retrofit = RetrofitClient.retrofit retrofit.create(RetrofitInterface::class.java).getLectures().enqueue(object : Callback<ArrayList<LectureDetailItem>>{ override fun onResponse( call: Call<ArrayList<LectureDetailItem>>, response: Response<ArrayList<LectureDetailItem>> ) { if(response.isSuccessful){ val lecturePoster = response.body() recommendLectureList.add("http://172.16.0.94:5000/static/images/"+lecturePoster!!.get(0).image) recommendRecyclerView.adapter = RecyclerViewAdapter(recommendLectureList, LayoutInflater.from(applicationContext)) } } override fun onFailure(call: Call<ArrayList<LectureDetailItem>>, t: Throwable) { Log.d("testt", "메인화면 이미지 불러오기 실패") } }) } } class RecyclerViewAdapter( var lectureList : List<String>, var inflater: LayoutInflater ) : RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>(){ inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){ val lectureImage : ImageView val context = itemView.context init { lectureImage = itemView.findViewById(R.id.poster_image) itemView.setOnClickListener { val intent = Intent(context, DetailedPageActivity::class.java) intent.run { context.startActivity(this) } } } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = inflater.inflate(R.layout.item_poster, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { // Log.d("testt", lectureList.get(0)) // holder.lectureImage.setImageBitmap(loadImage(lectureList.get(position))) } override fun getItemCount(): Int { return 1 } fun loadImage(imageUrl: String): Bitmap? { var bitmap: Bitmap? = null val connection: HttpURLConnection? try { val url = URL(imageUrl) connection = url.openConnection() as HttpURLConnection connection.requestMethod = "GET" connection.connectTimeout = 10000 connection.doOutput = true connection.doInput = true connection.useCaches = true connection.connect() val resCode = connection.responseCode if (resCode == HttpURLConnection.HTTP_OK) { val input = connection.inputStream bitmap = BitmapFactory.decodeStream(input) connection.disconnect() } } catch (e: IOException) { e.printStackTrace() } return bitmap } }
问题分析与解决步骤
1. 修复布局属性兼容性问题
报错核心是?selectableItemBackgroundBorderless仅在API 21+可用,即使添加tools:targetApi="m",低版本系统运行时仍会尝试解析该属性导致崩溃。
修改方案:
替换为兼容API 11+的属性?attr/selectableItemBackground,修改后的item_poster.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:foreground="?attr/selectableItemBackground" android:layout_margin="2dp" android:clickable="true" android:focusable="true" android:orientation="vertical"> <ImageView android:id="@+id/poster_image" android:layout_width="105dp" android:layout_height="140dp" android:scaleType="centerCrop" android:background="@drawable/poster_bg" /> </LinearLayout>
2. 提前设置RecyclerView适配器
No adapter attached; skipping layout是因为RecyclerView初始化时未设置适配器,网络请求完成后才赋值,导致布局测量阶段无适配器。
修改方案:
在onCreate中提前设置空适配器,网络请求成功后更新数据并通知适配器:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val recommendRecyclerView = findViewById<RecyclerView>(R.id.recommend_recycler_view) val recommendLectureList = mutableListOf<String>() // 提前初始化空适配器 val adapter = RecyclerViewAdapter(recommendLectureList, LayoutInflater.from(this)) recommendRecyclerView.adapter = adapter val retrofit = RetrofitClient.retrofit retrofit.create(RetrofitInterface::class.java).getLectures().enqueue(object : Callback<ArrayList<LectureDetailItem>>{ override fun onResponse( call: Call<ArrayList<LectureDetailItem>>, response: Response<ArrayList<LectureDetailItem>> ) { if(response.isSuccessful){ val lecturePoster = response.body() lecturePoster?.let { recommendLectureList.clear() recommendLectureList.add("http://172.16.0.94:5000/static/images/${it[0].image}") // 通知适配器数据更新 adapter.notifyDataSetChanged() } } } override fun onFailure(call: Call<ArrayList<LectureDetailItem>>, t: Throwable) { Log.d("testt", "메인화면 이미지 불러오기 실패") } }) }
3. 优化RecyclerView适配器
- 修改
getItemCount()返回列表实际长度,避免固定值导致数据展示异常:
override fun getItemCount(): Int { return lectureList.size }
- 替换手动图片加载逻辑,使用Glide库(需在
build.gradle添加依赖)避免主线程网络操作:
// 先添加Glide依赖 // implementation 'com.github.bumptech.glide:glide:4.16.0' // annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0' override fun onBindViewHolder(holder: ViewHolder, position: Int) { Glide.with(holder.context) .load(lectureList[position]) .placeholder(R.drawable.poster_bg) // 设置占位图 .into(holder.lectureImage) }
同时删除手动实现的loadImage方法。
4. 基础检查
- 确保
@drawable/poster_bg资源存在; - 在
AndroidManifest.xml中添加网络权限:<uses-permission android:name="android.permission.INTERNET" />。
内容的提问来源于stack exchange,提问作者kei
相关产品推荐
相关产品推荐

