TransWikia.com

Hilt injected adapter via builder is null

Stack Overflow Asked by martinseal1987 on December 7, 2021

I’m new to dagger and hilt, I’m trying to use Hilt to get my adapter injected to my fragment using a builder (the fragment is actually in a fragment pager adapter so there’s multiple instance of it and the adapter), it seems set up correctly, I build the component before super in onCreate but the adapter is null when trying to access it later in the fragment, I wonder if maybe I need to provide it somehow later on so for instance I have my adapter in my fragment

@AndroidEntryPoint
public class CardHolderFragment extends Fragment {

    public CardAdapter cardAdapter;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    DaggerCardAdapterComponent.builder()
            .cardAdapterDependencies(() -> layoutIdentifier)
            .build().inject(this);
    super.onCreate(savedInstanceState);
    cardAdapter.notifyDataSetChanged(); // CardAdapter.notifyDataSetChanged()' on a null object reference

so my question is if the component is setup correctly should this work or am I missing a step?
What I feel like doing is something like cardAdapter = DaggerCardAdapterComponent.getCardAdapter but I can’t put a provides methods in a component, I had a look through the dagger migration guide here which is a little complicated for me as I only had a few weeks with dagger before switching to hilt, but the guide mentions

Finally, you may have to redesign some things if they were configured differently for different activity or fragment components. For example, you could use a new interface on the activity to provide the object.

so I tried this which makes me implement the interface and then return a card adapter but I wasn’t sure what I should be returning here, any help welcome

heres my card adapter component

@Component(dependencies = CardAdapterDependencies.class, modules = {TypeFactoryModule.class, 
ItemTouchListenerModule.class, GlideModule.class})

public interface CardAdapterComponent {

void inject(CardHolderFragment cardHolderFragment);

@Component.Builder
interface Builder {
    Builder cardAdapterDependencies(CardAdapterDependencies cardAdapterDependencies);
    CardAdapterComponent build();
}

interface HasCardAdapter{
    CardAdapter getCardAdapter();
}
} 

and heres my card adapter constructor

@Inject
public CardAdapter(
        ItemTouchListener onItemTouchListener,
        String layoutIdentifier,
        TypeFactory typeFactory,
        RequestManager glide
) {
    this.onItemTouchListener = onItemTouchListener;
    this.typeFactory = typeFactory;
    this.layoutIdentifier = layoutIdentifier;
    this.glide = glide;
    this.elements = new ArrayList<>();
}

One Answer

First of all you don't need to use @AndroidEntryPoint if you are building your dependent component, even in my case at dynamic feature modules using @AndroidEntryPoint caused it not to compile.

Edit: In your situation building a dependent component or building component with builder does not look necessary. If so, you can use the answer below will help, if you don't need dependent component I will add another edit to do it simple way.

You should use EntryPointAccessors.fromApplication(), EntryPointAccessors.fromActivity() or EntryPointAccessors.fromFragment() to create an interface that has provision methods with @InstallIn and @EntryPoint annotations. I explained here how to build with dependent components and dynamic feature modules using Hilt and you can find the full sample in this git repo.

First create a module with dependencies you provide:

@Module
@InstallIn(ApplicationComponent::class)
class CoreModule {

    @Singleton
    @Provides
    fun provideCoreDependency(application: Application) = CoreDependency(application)

    @Provides
    fun provideCoreActivityDependency(context: Application) = CoreActivityDependency(context)
}

You can change ApplicationComponent to ActivityComponent or FragmentComponent depending on your structure.

Then build a dependencies interface with @EntryPoint and @InstallIn annotations and provision methods which is how you provide the dependencies to dependent components.

@EntryPoint
@InstallIn(ApplicationComponent::class)
interface CoreDependencies {

    /*
     * Provision methods to provide dependencies to components that
     * depend on this component
     */
    fun coreDependency(): CoreDependency

    fun coreActivityDependency(): CoreActivityDependency

}

Now build the component you should create, it's CardAdapterComponent for you

@Component(
        dependencies = [CoreDependencies::class],
        modules = [CameraModule::class]
)
interface CameraComponent {

    fun inject(cameraFragment1: CameraFragment1)
    fun inject(cameraFragment2: CameraFragment2)


    fun inject(cameraActivity: CameraActivity)

    @Component.Factory
    interface Factory {
        fun create(coreDependencies: CoreDependencies, @BindsInstance application: Application): CameraComponent
    }

}

I used factory pattern, you can use builder if you wish, both the same.

To inject your dependent component to Activity you need to get component using EntryPoints.

private fun initHiltDependencyInjection() {

    val coreComponentDependencies = EntryPointAccessors.fromApplication(
            applicationContext,
            CoreDependencies::class.java
    )

    DaggerCameraComponent.factory().create(
            coreComponentDependencies,
            application
    )
            .inject(this)


}

To inject to the Fragment:

private fun initCoreDependentInjection() {

    val coreComponentDependencies = EntryPointAccessors.fromApplication(
            requireActivity().applicationContext,
            CoreDependencies::class.java
    )

    DaggerCameraComponent.factory().create(
            coreComponentDependencies,
            requireActivity().application
    )
            .inject(this)

}

Answered by Thracian on December 7, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP