android10 / Android-CleanArchitecture

This is a sample app that is part of a series of blog posts I have written about how to architect an android application using Uncle Bob's clean architecture approach.
Apache License 2.0
15.52k stars 3.32k forks source link

Why there is no activity context injection? #130

Open jiaju-yang opened 8 years ago

jiaju-yang commented 8 years ago

I don't know this is a bug or just my misunderstanding?

  @Inject
  public UsersAdapter(Context context) {
    this.layoutInflater =
        (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    this.usersCollection = Collections.emptyList();
  }

Here you have injected an adapter. This adapter has a Context type parameter. Apparently this should be an activity context. Because application context lacks the app theme and so on. But there is no activity context provided in your di. Only application context has been provided.

@Provides @Singleton Context provideApplicationContext() {
    return this.application;
  }

And I found an activity dependancy provided in ActivityModule.

  @Provides @PerActivity Activity activity() {
    return this.activity;
  }

My question is: Do you replace activity context with application context? Or with an acitivity casted by di automatically? Or this is just a bug?

android10 commented 8 years ago

Always use the application context since it is a singleton application wide. I don't see any reason to use an activity context, cause that could be dangerous and create leaks.

technoplato commented 7 years ago

I believe one of the only places where using an application context will cause issues is if you're inflating any kind of UI such as a dialog. I could be wrong but I don't think the themes will be correct.

jiaju-yang commented 7 years ago

@lustigdev Thanks for your reply. I think you are right. Here explains why application context and activity context are different.

And the second answer shows us a picture to compare them:

Difference

So I think if you wanna start an activity or show a dialog or inflate a layout, you should use activity context instead of application context. According this I made a small change in my code:

@Qualifier
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface ForActivity {
}
@Qualifier
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface ForApplication {
}

I wrote two annotations to differentiate activity context and application context. And I use them like below:

@Module
public class ApplicationModule {
    private final AndroidApplication application;

    public ApplicationModule(AndroidApplication application) {
        this.application = application;
    }

    @Provides
    @Singleton
    @ForApplication
    Context provideApplicationContext() {
        return application;
    }
    ...
}

This is how I provide application context in di. Usage is simple, just declare @ForApplication:

 @Singleton
 public class Toaster {
     private final Context context;

     @Inject
     public Toaster(@ForApplication Context context) {
         if (context == null)
             throw new IllegalArgumentException("Context can not be null!");
         this.context = context;
     }
     ...
 }

Activity context is a bit more complex:

@Module
public class ActivityModule {

    private final Activity activity;

    public ActivityModule(Activity activity) {
        this.activity = activity;
    }

    @Provides
    @ForActivity
    Context provideActivityContext() {
        return activity;
    }
}
@ActivityScope
@Subcomponent(
        modules =
                {
                        ActivityModule.class
                })
public interface MainComponent {
    void inject(MainFragment fragment);
}

When I wanna inject context, I just declare @ForActivity:

public abstract class BaseFragment<P extends Presenter> extends Fragment {
    ...
    @Inject
    @ForActivity
    protected Context context;
    ...
}
public class MainFragment extends BaseFragment<MainPresenter> {
    //In this class I can use `context` to show a dialog or start an activity and so on when I need activity instead of application context.
}

Any suggestions are welcome^-^

technoplato commented 7 years ago

That's the exact chart I was thinking about, I was just too lazy to go find it. Will have a read here on your writeup! Really appreciate the time, and what a great issues tracker in general for learning more about CLEAN architecture.

android10 commented 7 years ago

@psychesworld awsome! I'm reopening this issue since the information here is very valuable. Great job!