Android MVVM Todo应用启动报错:无法实例化HomeFragment
问题:Fragment实例化失败引发InflateException错误
我正在开发一款基于MVVM架构的Todo应用,包含两个Fragment:用户可在AddNoteFragment中输入笔记,笔记会在HomeFragment的RecyclerView中展示。已将HomeFragment设置为导航组件的起始目标,但编写完RecyclerView Adapter后,应用启动时出现android.view.InflateException错误,完整错误信息显示无法实例化HomeFragment,找不到无参构造函数。
相关代码
navigation.xml
<?xml version="1.0" encoding="utf-8"?> <navigation 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:id="@+id/navigation" app:startDestination="@id/homeFragment"> <fragment android:id="@+id/homeFragment" android:name="com.enestigli.todoapp.presentation.home.home.HomeFragment" android:label="fragment_home" tools:layout="@layout/fragment_home" > <action android:id="@+id/action_homeFragment_to_addNoteFragment" app:destination="@id/addNoteFragment" /> </fragment> <fragment android:id="@+id/addNoteFragment" android:name="com.enestigli.todoapp.presentation.home.addnote.AddNoteFragment" android:label="fragment_add_note" tools:layout="@layout/fragment_add_note" > <action android:id="@+id/action_addNoteFragment_to_homeFragment" app:destination="@id/homeFragment" /> </fragment> </navigation>
HomeFragment
@AndroidEntryPoint class HomeFragment @Inject constructor( private val homeRecyclerAdapter:HomeRecyclerAdapter ): Fragment(R.layout.fragment_home) { private lateinit var viewModel: HomeViewModel private var fragmentBinding : FragmentHomeBinding? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel = ViewModelProvider(requireActivity()).get(HomeViewModel::class.java) val binding = FragmentHomeBinding.bind(view) fragmentBinding = binding subscribeToObservers() binding.HomeFragmentRecyclerView.adapter = homeRecyclerAdapter binding.HomeFragmentRecyclerView.layoutManager = LinearLayoutManager(requireContext()) binding.fab.setOnClickListener{ findNavController().navigate(HomeFragmentDirections.actionHomeFragmentToAddNoteFragment()) } } private fun subscribeToObservers(){ viewModel.noteList.observe(viewLifecycleOwner, Observer { homeRecyclerAdapter.noteList = it }) } override fun onDestroy() { fragmentBinding = null super.onDestroy() } }
HomeViewModel
@HiltViewModel class HomeViewModel @Inject constructor( private val repository: INoteRepository ): ViewModel() { val noteList = repository.getNote() }
HomeRecyclerAdapter
class HomeRecyclerAdapter : RecyclerView.Adapter<HomeRecyclerAdapter.HomeViewHolder>(){ private val diffUtil = object : DiffUtil.ItemCallback<Note>(){ override fun areItemsTheSame(oldItem: Note, newItem: Note): Boolean { return oldItem == newItem } override fun areContentsTheSame(oldItem: Note, newItem: Note): Boolean { return oldItem == newItem } } //DiffUtil helper private val recyclerListDiffer = AsyncListDiffer(this,diffUtil) var noteList :List<Note> get() = recyclerListDiffer.currentList set(value) = recyclerListDiffer.submitList(value) class HomeViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.home_row,parent,false) return HomeViewHolder(view) } override fun onBindViewHolder(holder: HomeViewHolder, position: Int) { val title = holder.itemView.findViewById<TextView>(R.id.AddNoteFragmentTxtTitle) val desc = holder.itemView.findViewById<TextView>(R.id.AddNoteFragmentTxtNote) val priority = holder.itemView.findViewById<TextView>(R.id.AddNoteFragmentRadioGroup) val note = noteList[position] holder.itemView.apply { title?.text = "Title: ${note.title}" } } override fun getItemCount(): Int { return noteList.size } }
完整错误栈
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.enestigli.todoapp, PID: 6741 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.enestigli.todoapp/com.enestigli.todoapp.presentation.home.main.MainActivity}: android.view.InflateException: Binary XML file line #10 in com.enestigli.todoapp:layout/activity_main: Binary XML file line #10 in com.enestigli.todoapp:layout/activity_main: Error inflating class androidx.fragment.app.FragmentContainerView at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3676) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3813) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:201) at android.os.Looper.loop(Looper.java:288) at android.app.ActivityThread.main(ActivityThread.java:7898) 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:936) Caused by: android.view.InflateException: Binary XML file line #10 in com.enestigli.todoapp:layout/activity_main: Binary XML file line #10 in com.enestigli.todoapp:layout/activity_main: Error inflating class androidx.fragment.app.FragmentContainerView Caused by: android.view.InflateException: Binary XML file line #10 in com.enestigli.todoapp:layout/activity_main: Error inflating class androidx.fragment.app.FragmentContainerView Caused by: androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment com.enestigli.todoapp.presentation.home.home.HomeFragment: could not find Fragment constructor at androidx.fragment.app.Fragment.instantiate(Fragment.java:678) at androidx.fragment.app.FragmentContainer.instantiate(FragmentContainer.java:57) at androidx.fragment.app.FragmentManager$3.instantiate(FragmentManager.java:498) at androidx.navigation.fragment.FragmentNavigator.navigate(FragmentNavigator.kt:190) at androidx.navigation.fragment.FragmentNavigator.navigate(FragmentNavigator.kt:162) at androidx.navigation.NavGraphNavigator.navigate(NavGraphNavigator.kt:83) at androidx.navigation.NavGraphNavigator.navigate(NavGraphNavigator.kt:49) at androidx.navigation.NavController.navigateInternal(NavController.kt:260) at androidx.navigation.NavController.navigate(NavController.kt:1719) at androidx.navigation.NavController.onGraphCreated(NavController.kt:1161) at androidx.navigation.NavController.setGraph(NavController.kt:1086) at androidx.navigation.NavController.setGraph(NavController.kt:1039) at androidx.navigation.fragment.NavHostFragment.onCreate(NavHostFragment.kt:155) at androidx.fragment.app.Fragment.performCreate(Fragment.java:3090) at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:475) at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:257) at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1890) at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1814) at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1720) at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:323) at androidx.fragment.app.FragmentContainerView.<init>(FragmentContainerView.kt:158) at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:53) at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:136) at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:248) E/AndroidRuntime: at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:227) at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1073) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1001) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:965) at android.view.LayoutInflater.rInflate(LayoutInflater.java:1127) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1088) at android.view.LayoutInflater.inflate(LayoutInflater.java:686) at android.view.LayoutInflater.inflate(LayoutInflater.java:538) at android.view.LayoutInflater.inflate(LayoutInflater.java:485) at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:710) at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:195) at com.enestigli.todoapp.presentation.home.main.MainActivity.onCreate(MainActivity.kt:17) at android.app.Activity.performCreate(Activity.java:8290) at android.app.Activity.performCreate(Activity.java:8269) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1384) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3657) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3813) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:201) at android.os.Looper.loop(Looper.java:288) at android.app.ActivityThread.main(ActivityThread.java:7898) 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:936) Caused by: java.lang.NoSuchMethodException: com.enestigli.todoapp.presentation.home.home.HomeFragment.<init> [] at java.lang.Class.getConstructor0(Class.java:2363) at java.lang.Class.getConstructor(Class.java:1759) at androidx.fragment.app.Fragment.instantiate(Fragment.java:663) ... 51 more
问题根源
HomeFragment使用带参数的@Inject构造函数,但Android系统实例化Fragment必须要有无参构造函数,导致实例化失败进而引发InflateException。
解决方案
将HomeRecyclerAdapter改为字段注入,移除带参数的构造函数,修改后的HomeFragment代码如下:
@AndroidEntryPoint class HomeFragment : Fragment(R.layout.fragment_home) { @Inject lateinit var homeRecyclerAdapter: HomeRecyclerAdapter // 其他代码不变 }
内容的提问来源于stack exchange,提问作者NewPartizal
相关产品推荐
相关产品推荐

