JakeWharton / dagger-reflect

A reflection-based implementation of the Dagger dependency injection library for fast IDE builds.
Apache License 2.0
655 stars 44 forks source link

ContributesAndroidInjector doesn't work for Fragment inside an Activity #174

Open kokeroulis opened 5 years ago

kokeroulis commented 5 years ago

If you have a nested ContributesAndroidInjector then it doesn't work properly. Dagger complains about a missing injector factory. Dagger with code generation works fine, only dagger reflect is crashing.

@Module
public interface ExampleActivityModule {

    @ContributesAndroidInjector
    ExampleFragment fragment();
}

Full Example here https://github.com/kokeroulis/dagger-reflect/commit/adbd4ab65ffd52847c68c5967d82f6454ba25090

stacktrace

E  java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example/com.example.ExampleActivity}: java.lang.IllegalArgumentException: No injector factory bound for Class<com.example.ExampleFragment>
E      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
E      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
E      at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
E      at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
E      at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
E      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
E      at android.os.Handler.dispatchMessage(Handler.java:106)
E      at android.os.Looper.loop(Looper.java:193)
E      at android.app.ActivityThread.main(ActivityThread.java:6669)
E      at java.lang.reflect.Method.git invoke(Native Method)
E      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
E      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
E  Caused by: java.lang.IllegalArgumentException: No injector factory bound for Class<com.example.ExampleFragment>
E      at dagger.android.DispatchingAndroidInjector.inject(DispatchingAndroidInjector.java:136)
E      at dagger.android.AndroidInjection.inject(AndroidInjection.java:181)
E      at dagger.android.AndroidInjection.inject(AndroidInjection.java:91)
E      at com.example.ExampleFragment.onAttach(ExampleFragment.java:11)
E      at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1242)
E      at android.app.FragmentManagerImpl.addAddedFragments(FragmentManager.java:2426)
E      at android.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2205)
E      at android.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2161)
E      at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2062)
E      at android.app.FragmentManagerImpl.dispatchMoveToState(FragmentManager.java:3051)
E      at android.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:2998)
E      at android.app.FragmentController.dispatchActivityCreated(FragmentController.java:182)
E      at android.app.Activity.performCreate(Activity.java:7143)
E      at android.app.Activity.performCreate(Activity.java:7127)
E      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
E      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
E      ... 11 more

Part of the code which reproduces this issue

@Component(modules = {
        AndroidInjectionModule.class,
        ActivityBindingModule.class
})
interface AppComponent {

    void inject(ExampleApp app);

    DispatchingAndroidInjector<Object> androidInjector();
}
public final class ExampleActivity extends Activity implements HasAndroidInjector {
    @Inject
    DispatchingAndroidInjector<Object> androidInjector;

    @SuppressLint("SetTextI18n")
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
        getFragmentManager().beginTransaction().add(new ExampleFragment(), "some tag").commit();
    }

    @Override
    public AndroidInjector<Object> androidInjector() {
        return androidInjector;
    }
}
@Module
public interface ExampleActivityModule {

    @ContributesAndroidInjector
    ExampleFragment fragment();
}
public final class ExampleApp extends Application implements HasAndroidInjector {
    private AppComponent component;

    @Inject
    DispatchingAndroidInjector<Object> androidInjector;

    @Override
    public void onCreate() {
        super.onCreate();
        component = Dagger.create(AppComponent.class);
        component.inject(this);
    }

    @Override
    public AndroidInjector<Object> androidInjector() {
        return androidInjector;
    }
}
public class ExampleFragment extends Fragment {

    @Override
    public void onAttach(Context context) {
        AndroidInjection.inject(this);
        super.onAttach(context);
    }
}
obsantos commented 4 years ago

@kokeroulis I having similar issue. Did you find a workaround for this?

kokeroulis commented 4 years ago

@obsantos I am using a forked version of this project with custom workarounds. the latest branch is this one https://github.com/kokeroulis/dagger-reflect/commits/atsiap/module_with_generic_try_to_add_workaround_new_fixes

The "workarounds" that are included there might not work for every case, this is why they are just left there instead of opening a PR here but the project in which i am using them is quite big and complicated, so they might be useful for you...

I will upload another branch in a few days which will include fixes for the @IntoMap.. In the above branch there are cases in which the @IntoMap doesn't work...

crgarridos commented 4 years ago

What about a PR only with this commit . It could make any sense?

milanga commented 4 years ago

It would be great to have this