0

I am using @ContributesAndroidInjector of Dagger 2.11.

It works without problems with the following sources.
@ActivityScope is also working.

class MainActivity : AppCompatActivity(), HasFragmentInjector {
    @Inject
    lateinit var androidInjector: DispatchingAndroidInjector<Fragment>
    override fun fragmentInjector() = androidInjector
    @Inject
    lateinit var fragment: MainFragment
    @Inject
    lateinit var viewModel: MainViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        AndroidInjection.inject(this)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        fragmentManager.beginTransaction()
                .replace(R.id.container, fragment)
                .commitAllowingStateLoss()
        viewModel.start("activity")
    }
}

class MainFragment @Inject constructor() : Fragment() {
    @Inject
    lateinit var viewModel: MainViewModel
    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater!!.inflate(R.layout.fragment_main, container, false)
        return view
    }

    override fun onAttach(context: Context?) {
        super.onAttach(context)
        viewModel.start("fragment")
    }
}

@Module
abstract class AndroidModule {
    @ActivityScope
    @ContributesAndroidInjector
    abstract fun contributeMainActivity(): MainActivity
}

@ActivityScope
class MainViewModel @Inject constructor() {
...

But when I read the document, I felt it was correct to use @ConstructsAndroidInjector as well as activity.

And also in the answer here, it is written as

public class MainActivity {
    @Inject CoffeeFragment coffeeFragment; //no! don't do this
    @Inject TeaFragment teaFragment; //no!

Is my implementation problematic?
What problems will occur with my implementation?

Sneh Pandya
  • 8,197
  • 7
  • 35
  • 50
ko2ic
  • 1,977
  • 14
  • 20

1 Answers1

0

Fragments are managed by, well, the FragmentManager in Android.

In subclasses of FragmentActivity, including AppCompatActivity, when onSaveInstanceState(Bundle outBundle) is called on your Activity it will save the state of your Fragments.

Likewise onCreate(Bundle savedInstanceState) will attempt to restore them. You can cause this to happen by turning on Developer Options / Don't keep Activities and navigating in and out of your app.

In this situation, if you request injection of your Fragment field again using Dagger 2, the Activity will reference two copies of the Fragment - the restored Fragment and the newly injected one. You don't want this! Instead, the correct idiom to get a handle on the Fragment in your onCreate is the following:

fragment = fragmentManager.findFragmentByTag("MAIN")
if (fragment == null) fragment = MainFragment.instantiate(null)
fragmentManager.beginTransaction()
            .replace(R.id.container, fragment, "MAIN")
            .commit()

where MainFragment.instantiate(Bundle args) is a static method in a companion object.

David Rawson
  • 20,912
  • 7
  • 88
  • 124
  • Thank you.I understood that there was a problem.But in the above code and by adding AndroidInjection.inject(this) in Fragment#onAttach, ViewModel of Activity and Fragment are not shared as @ActivityScope.Is there a way to share them? – ko2ic Nov 08 '17 at 13:24