不使用@Inject 构造函数导航到片段
Not navigate to fragment with @Inject constructor
我正在尝试创建一个简单的新闻应用程序,但是当我在片段中使用 @Inject constructor
时,导航组件无法正常工作并显示以下错误...而在使用注入之前,它是工作没有任何问题
我正在做什么来修复这个错误?!非常感谢你的帮助
新闻活动:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.setupWithNavController
import com.example.simplenewsapp.R
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.android.synthetic.main.activity_news.*
@AndroidEntryPoint
class NewsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_news)
bottomNavigationView.setupWithNavController(newsNavHostFragment.findNavController())
}
}
突发新闻片段:
class BreakingNewsFragment @Inject constructor(
val newsItemAdapter: NewsAdapter,
var viewModel: MainViewModel? = null
) : Fragment(R.layout.fragment_breaking_news) {
...
}
错误信息:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.simplenewsapp, PID: 8558
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.simplenewsapp/com.example.simplenewsapp.ui.NewsActivity}: android.view.InflateException: Binary XML file line #17: Binary XML file line #17: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: android.view.InflateException: Binary XML file line #17: Binary XML file line #17: Error inflating class fragment
Caused by: android.view.InflateException: Binary XML file line #17: Error inflating class fragment
Caused by: androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment com.example.simplenewsapp.ui.fragments.BreakingNewsFragment: could not find Fragment constructor
at androidx.fragment.app.Fragment.instantiate(Fragment.java:625)
at androidx.fragment.app.FragmentContainer.instantiate(FragmentContainer.java:57)
at androidx.fragment.app.FragmentManager.instantiate(FragmentManager.java:483)
at androidx.navigation.fragment.FragmentNavigator.instantiateFragment(FragmentNavigator.java:132)
at androidx.navigation.fragment.FragmentNavigator.navigate(FragmentNavigator.java:162)
at androidx.navigation.fragment.FragmentNavigator.navigate(FragmentNavigator.java:58)
at androidx.navigation.NavGraphNavigator.navigate(NavGraphNavigator.java:71)
at androidx.navigation.NavGraphNavigator.navigate(NavGraphNavigator.java:28)
at androidx.navigation.NavController.navigate(NavController.java:1059)
at androidx.navigation.NavController.onGraphCreated(NavController.java:639)
at androidx.navigation.NavController.setGraph(NavController.java:592)
at androidx.navigation.NavController.setGraph(NavController.java:557)
at androidx.navigation.NavController.setGraph(NavController.java:539)
at androidx.navigation.fragment.NavHostFragment.onCreate(NavHostFragment.java:248)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2936)
at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:472)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:278)
at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:141)
at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:313)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:292)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:780)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:866)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at android.view.LayoutInflater.inflate(LayoutInflater.java:374) E/AndroidRuntime: at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:696)
at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:170)
at com.example.simplenewsapp.ui.NewsActivity.onCreate(NewsActivity.kt:26)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.NoSuchMethodException: <init> []
at java.lang.Class.getConstructor0(Class.java:2327)
at java.lang.Class.getConstructor(Class.java:1725)
at androidx.fragment.app.Fragment.instantiate(Fragment.java:610)
... 47 more
at
com.example.simplenewsapp.ui.NewsActivity.onCreate(NewsActivity.kt:26)
is:
setContentView(R.layout.activity_news)
片段应该有一个空的构造函数,因为它们由 Android 管理,与活动相同。任何你想注入的东西都必须注入片段内部,而不是通过构造函数。
对于视图模型,通过 viewModels() 很简单 API:
private val viewModel: MainViewModel by viewModels()
不要忘记用 @AndroidEntryPoint
注释片段,用 @HiltViewModel
注释视图模型。
将@AndroidEntryPoint 添加到您的片段并在片段的onViewCreated 方法中初始化NewsAdapter()。
使用
获取MainViewModel
private val MainViewModel by viewModels()
片段必须有一个空的构造函数,因为它们是由系统 OS 创建的。
所有提供的答案都是错误的,因为片段构造函数不必为空!您可以轻松地将构造函数注入片段中的依赖项,但是您必须使用片段工厂才能做到这一点。
下面是一个例子:
片段
@AndroidEntryPoint
class BreakingNewsFragment(
val newsItemAdapter: NewsAdapter,
) : Fragment(R.layout.fragment_breaking_news) {
...
}
片段工厂
class MainFragmentFactory @Inject constructor(
private val newsAdapter: NewsAdapter
// your dependencies
) : FragmentFactory() {
override fun instantiate(classLoader: ClassLoader, className: String): Fragment = when(className) {
BreakingNewsFragment::class.java.name -> BreakingNewsFragment(newsAdapter)
// here you can add every other fragment
else -> super.instantiate(classLoader, className)
}
}
MainNavHostFragment
@AndroidEntryPoint
class MainNavHostFragment : NavHostFragment() {
@Inject lateinit var mainFragmentFactory: MainFragmentFactory
override fun onAttach(context: Context) {
super.onAttach(context)
childFragmentManager.fragmentFactory = mainFragmentFactory
}
}
然后为了使用新的 NavHostFragment,您必须更改 activity_main.xml
Activity_main.xml
<fragment
android:id="@+id/fragment_container"
android:name="yourPath.MainNavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_main" />
重要的一行在这里“android:name="yourPath.MainNavHostFragment" 或者例如"android:name="com.example.app.ui.MainNavHostFragment"
有了这个你可以在你的片段中注入构造函数。
注意:
你不能构造函数注入你的视图模型!您还应该小心使用此方法和构造函数注入适配器,因为它们可能会导致内存泄漏。对于适配器,我建议您现场注入它们
我正在尝试创建一个简单的新闻应用程序,但是当我在片段中使用 @Inject constructor
时,导航组件无法正常工作并显示以下错误...而在使用注入之前,它是工作没有任何问题
我正在做什么来修复这个错误?!非常感谢你的帮助
新闻活动:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.setupWithNavController
import com.example.simplenewsapp.R
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.android.synthetic.main.activity_news.*
@AndroidEntryPoint
class NewsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_news)
bottomNavigationView.setupWithNavController(newsNavHostFragment.findNavController())
}
}
突发新闻片段:
class BreakingNewsFragment @Inject constructor(
val newsItemAdapter: NewsAdapter,
var viewModel: MainViewModel? = null
) : Fragment(R.layout.fragment_breaking_news) {
...
}
错误信息:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.simplenewsapp, PID: 8558
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.simplenewsapp/com.example.simplenewsapp.ui.NewsActivity}: android.view.InflateException: Binary XML file line #17: Binary XML file line #17: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: android.view.InflateException: Binary XML file line #17: Binary XML file line #17: Error inflating class fragment
Caused by: android.view.InflateException: Binary XML file line #17: Error inflating class fragment
Caused by: androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment com.example.simplenewsapp.ui.fragments.BreakingNewsFragment: could not find Fragment constructor
at androidx.fragment.app.Fragment.instantiate(Fragment.java:625)
at androidx.fragment.app.FragmentContainer.instantiate(FragmentContainer.java:57)
at androidx.fragment.app.FragmentManager.instantiate(FragmentManager.java:483)
at androidx.navigation.fragment.FragmentNavigator.instantiateFragment(FragmentNavigator.java:132)
at androidx.navigation.fragment.FragmentNavigator.navigate(FragmentNavigator.java:162)
at androidx.navigation.fragment.FragmentNavigator.navigate(FragmentNavigator.java:58)
at androidx.navigation.NavGraphNavigator.navigate(NavGraphNavigator.java:71)
at androidx.navigation.NavGraphNavigator.navigate(NavGraphNavigator.java:28)
at androidx.navigation.NavController.navigate(NavController.java:1059)
at androidx.navigation.NavController.onGraphCreated(NavController.java:639)
at androidx.navigation.NavController.setGraph(NavController.java:592)
at androidx.navigation.NavController.setGraph(NavController.java:557)
at androidx.navigation.NavController.setGraph(NavController.java:539)
at androidx.navigation.fragment.NavHostFragment.onCreate(NavHostFragment.java:248)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2936)
at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:472)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:278)
at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:141)
at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:313)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:292)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:780)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:866)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at android.view.LayoutInflater.inflate(LayoutInflater.java:374) E/AndroidRuntime: at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:696)
at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:170)
at com.example.simplenewsapp.ui.NewsActivity.onCreate(NewsActivity.kt:26)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.NoSuchMethodException: <init> []
at java.lang.Class.getConstructor0(Class.java:2327)
at java.lang.Class.getConstructor(Class.java:1725)
at androidx.fragment.app.Fragment.instantiate(Fragment.java:610)
... 47 more
at com.example.simplenewsapp.ui.NewsActivity.onCreate(NewsActivity.kt:26) is:
setContentView(R.layout.activity_news)
片段应该有一个空的构造函数,因为它们由 Android 管理,与活动相同。任何你想注入的东西都必须注入片段内部,而不是通过构造函数。
对于视图模型,通过 viewModels() 很简单 API:
private val viewModel: MainViewModel by viewModels()
不要忘记用 @AndroidEntryPoint
注释片段,用 @HiltViewModel
注释视图模型。
将@AndroidEntryPoint 添加到您的片段并在片段的onViewCreated 方法中初始化NewsAdapter()。 使用
获取MainViewModelprivate val MainViewModel by viewModels()
片段必须有一个空的构造函数,因为它们是由系统 OS 创建的。
所有提供的答案都是错误的,因为片段构造函数不必为空!您可以轻松地将构造函数注入片段中的依赖项,但是您必须使用片段工厂才能做到这一点。
下面是一个例子:
片段
@AndroidEntryPoint
class BreakingNewsFragment(
val newsItemAdapter: NewsAdapter,
) : Fragment(R.layout.fragment_breaking_news) {
...
}
片段工厂
class MainFragmentFactory @Inject constructor(
private val newsAdapter: NewsAdapter
// your dependencies
) : FragmentFactory() {
override fun instantiate(classLoader: ClassLoader, className: String): Fragment = when(className) {
BreakingNewsFragment::class.java.name -> BreakingNewsFragment(newsAdapter)
// here you can add every other fragment
else -> super.instantiate(classLoader, className)
}
}
MainNavHostFragment
@AndroidEntryPoint
class MainNavHostFragment : NavHostFragment() {
@Inject lateinit var mainFragmentFactory: MainFragmentFactory
override fun onAttach(context: Context) {
super.onAttach(context)
childFragmentManager.fragmentFactory = mainFragmentFactory
}
}
然后为了使用新的 NavHostFragment,您必须更改 activity_main.xml
Activity_main.xml
<fragment
android:id="@+id/fragment_container"
android:name="yourPath.MainNavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_main" />
重要的一行在这里“android:name="yourPath.MainNavHostFragment" 或者例如"android:name="com.example.app.ui.MainNavHostFragment"
有了这个你可以在你的片段中注入构造函数。
注意:
你不能构造函数注入你的视图模型!您还应该小心使用此方法和构造函数注入适配器,因为它们可能会导致内存泄漏。对于适配器,我建议您现场注入它们