amrz
amrz

Reputation: 111

Not navigate to fragment with @Inject constructor

I'm trying to create a simple news app, but when I used of @Inject constructor in my fragment, the navigation component not worked and show the below error... while, before used injection, it's worked without any problem

what I doing to fix this error?! thank you so much for your help

NewsActivity:

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())

    }
}

BreakingNewsFragment:

class BreakingNewsFragment @Inject constructor(
    val newsItemAdapter: NewsAdapter,
    var viewModel: MainViewModel? = null
) : Fragment(R.layout.fragment_breaking_news) {
...
}

Error message:

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

at com.example.simplenewsapp.ui.NewsActivity.onCreate(NewsActivity.kt:26) is:

    setContentView(R.layout.activity_news)

Upvotes: 1

Views: 2095

Answers (3)

m0skit0
m0skit0

Reputation: 25873

Fragments should have an empty constructor since they are managed by Android, same as activities. Anything you want to inject you have to inject inside the fragment, not through the constructor.

For view-models, it's trivial through the viewModels() API:

private val viewModel: MainViewModel by viewModels()

Don't forget to annotate the fragment with @AndroidEntryPoint and the view-model with @HiltViewModel.

Upvotes: 3

Andrew
Andrew

Reputation: 4712

All the provided answers are wrong as fragments constructor do NOT have to be empty! You can easily constructor inject your dependencies inside your fragments, but you have to use a fragment factory in order to do so.

Here is an example for you:

Fragment

@AndroidEntryPoint
class BreakingNewsFragment(
    val newsItemAdapter: NewsAdapter,
) : Fragment(R.layout.fragment_breaking_news) {
...
}

Fragment Factory

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
    }
}

Then in order to use your new NavHostFragment, you have to change your 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" />

The important line being here "android:name="yourPath.MainNavHostFragment" or for example "android:name="com.example.app.ui.MainNavHostFragment"

With this you can constructor inject inside your fragment.

NOTE:

You can NOT constructor inject your viewmodel! You should also be careful with using this method and constructor injecting adapters as they can possibility cause a memory leak. With adapters, I would advise you to field inject them

Upvotes: 5

Jujare Vinayak
Jujare Vinayak

Reputation: 123

Add @AndroidEntryPoint to your fragment and initialize NewsAdapter() in onViewCreated method of fragments. Get MainViewModel by using

private val MainViewModel by viewModels()

Fragments MUST have an empty constructor since they are created by System OS.

Upvotes: 0

Related Questions