提问人:068-Arsyadana 提问时间:11/14/2023 更新时间:11/14/2023 访问量:29
在 MainActivity 中膨胀类 androidx.fragment.app.FragmentContainerView 时出错
Error inflating class androidx.fragment.app.FragmentContainerView in MainActivity
问:
我一直在尝试制作和运行此代码,但是在膨胀MainActivity时似乎遇到了一些问题。这是错误代码
Process: com.example.cleansound, PID: 3096
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.cleansound/com.example.cleansound.MainActivity}: android.view.InflateException: Binary XML file line #20 in com.example.cleansound:layout/activity_main: Binary XML file line #20 in com.example.cleansound:layout/activity_main: Error inflating class androidx.fragment.app.FragmentContainerView
...
Caused by: android.view.InflateException: Binary XML file line #20 in com.example.cleansound:layout/activity_main: Binary XML file line #20 in com.example.cleansound:layout/activity_main: Error inflating class androidx.fragment.app.FragmentContainerView
Caused by: android.view.InflateException: Binary XML file line #20 in com.example.cleansound:layout/activity_main: Error inflating class androidx.fragment.app.FragmentContainerView
Caused by: androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment com.example.cleansound.ui.auth.LoginFragment: calling Fragment constructor caused an exception
...
Caused by: java.lang.reflect.InvocationTargetException
...
Caused by: java.lang.IllegalStateException: Fragment LoginFragment{f63f08e} (6390a8be-00a8-47bb-9ad0-2de7d86dd3d2) not attached to an activity.
at androidx.fragment.app.Fragment.requireActivity(Fragment.java:1000)
at com.example.cleansound.ui.auth.LoginFragment.<init>(LoginFragment.kt:20)
我一直在搜索这个问题的解决方案并匹配 NavHostFragment 和 Nav_Graph 上的 ID。但我认为 LoginFragment 出了点问题,我不知道那是什么。我可以给你我的一些代码,希望你能更好地理解我的问题
// com.example.cleansound.MainActivity
package com.example.cleansound
class MainActivity : AppCompatActivity() {
...
val navView: BottomNavigationView = binding.navView
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
navView.setupWithNavController(navController)
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
}
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/mobile_navigation" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_nav_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
// mobile_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/mobile_navigation"
app:startDestination="@id/loginFragment">
<fragment
android:id="@+id/navigation_home"
android:name="com.example.cleansound.ui.home.HomeFragment"
android:label="@string/title_home"
tools:layout="@layout/fragment_home" />
<fragment
android:id="@+id/navigation_dashboard"
android:name="com.example.cleansound.ui.dashboard.DashboardFragment"
android:label="@string/title_dashboard"
tools:layout="@layout/fragment_dashboard" />
<fragment
android:id="@+id/navigation_notifications"
android:name="com.example.cleansound.ui.notifications.NotificationsFragment"
android:label="@string/title_notifications"
tools:layout="@layout/fragment_notifications" />
<fragment
android:id="@+id/loginFragment"
android:name="com.example.cleansound.ui.auth.LoginFragment"
android:label="LoginFragment"
tools:layout="@layout/fragment_login">
<action
android:id="@+id/action_loginFragment_to_navigation_home"
app:destination="@id/navigation_home"
app:popUpTo="@id/loginFragment"
app:popUpToInclusive="true" />
<action
android:id="@+id/action_loginFragment_to_registerFragment"
app:destination="@id/registerFragment"
app:popUpTo="@id/loginFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/registerFragment"
android:name="com.example.cleansound.ui.auth.RegisterFragment"
android:label="RegisterFragment"
tools:layout="@layout/fragment_register">
<action
android:id="@+id/action_registerFragment_to_loginFragment"
app:destination="@id/loginFragment" />
</fragment>
</navigation>
它本身是负责用户的登录输入,并使用 ViewModel 来使用 for 登录。如果你愿意,我可以告诉你后者。LoginFragment
Firebase.auth
ViewModel
// com.example.cleansound.ui.auth.LoginFragment
package com.example.cleansound.ui.auth
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.example.cleansound.R
import com.example.cleansound.databinding.FragmentLoginBinding
import com.google.firebase.Firebase
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.auth
class LoginFragment : Fragment() {
private val viewModel : AuthViewModel = ViewModelProvider(
this,
AuthViewModelFactory.getInstance(requireActivity().application)
).get(AuthViewModel::class.java)
private lateinit var auth: FirebaseAuth
private var _binding: FragmentLoginBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentLoginBinding.inflate(inflater)
val root = binding.root
// Setting the Firebase auth instance
auth = Firebase.auth
viewModel.userData.observe(viewLifecycleOwner, Observer {firebaseUser ->
if (firebaseUser != null) {
findNavController().navigate(R.id.action_loginFragment_to_navigation_home)
}
})
return root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Redirecting to the register page
binding.signInBtn.setOnClickListener {
val email = binding.emailEditSignUp.text.toString()
val password = binding.passEditSignUp.text.toString()
if (!email.isNotEmpty() && !password.isNotEmpty()) {
viewModel.login(email, password)
}
}
binding.signUpText.setOnClickListener {
findNavController().navigate(R.id.action_loginFragment_to_registerFragment)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
这是我的第一个项目,如果你们能帮助我并在我的工作项目中给我建议,我真的很高兴
答:
1赞
ianhanniballake
11/14/2023
#1
取代:
private val viewModel : AuthViewModel = ViewModelProvider(
this,
AuthViewModelFactory.getInstance(requireActivity().application)
).get(AuthViewModel::class.java)
使用 by viewModels()
方法,如 ViewModel 作用域 API 指南中所述:
private val viewModel : AuthViewModel by viewModels {
AuthViewModelFactory.getInstance(requireActivity().application)
}
错误消息中提到了原始代码不起作用的原因:
Caused by: java.lang.IllegalStateException: Fragment LoginFragment{f63f08e} (6390a8be-00a8-47bb-9ad0-2de7d86dd3d2) not attached to an activity.
at androidx.fragment.app.Fragment.requireActivity(Fragment.java:1000)
at com.example.cleansound.ui.auth.LoginFragment.<init>(LoginFragment.kt:20)
这说明,作为 Fragment 初始化的一部分(在 Fragment 实际经历任何生命周期方法之前),您正在调用 - 您正在调用它作为初始化对象的一部分。requireActivity()
AuthViewModel
这是一个委托属性 - 实质上它为您控制 ViewModel 的创建。重要的是,它是懒惰的 - 它实际上只在你第一次访问对象时才创建 ViewModel。由于您访问它的第一个位置是 ,因此您的 fragment 已经经历了生命周期方法,这使得懒惰地创建 和调用它成为一件完全有效的事情。by viewModels
viewModel
onCreateView
AuthViewModelFactory
requireActivity()
评论