首页 > 解决方案 > 不使用 @Inject 构造函数导航到片段

问题描述

我正在尝试创建一个简单的新闻应用程序,但是当我@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$3.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

在 com.example.simplenewsapp.ui.NewsActivity.onCreate(NewsActivity.kt:26) 是:

    setContentView(R.layout.activity_news)

标签: androidandroid-fragmentsdependency-injectionandroid-jetpackdagger-hilt

解决方案


所有提供的答案都是错误的,因为片段构造函数不必为空!您可以轻松地在片段中注入您的依赖项,您必须使用片段工厂才能这样做。

这是一个例子:

分段

@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"

有了这个,你可以在你的片段中注入构造函数。

笔记:

您不能构造函数注入您的视图模型!您还应该小心使用此方法和构造函数注入适配器,因为它们可能会导致内存泄漏。使用适配器,我建议您现场注入它们


推荐阅读