1
votes

I'm learning Dagger2 and trying to keep it simple example and isolate other features as possible as i can to understand required parts.

*Edit: When i started learning, i'm still, Dagger seems too confusing for a beginner, i was asking if you can inject same User to same Activity whenever that Activity is created. User and Activity should have 1 to 1 relationship.

  1. Activity1 <- User(100) Numbers are arbitrary hashes
  2. Activity2 <-User(101)
  3. Activity3 <- User(102)

This is when first time Activities are created.

My question was you navigate back to Activity2 from Activity3, then if it's possible to inject User(101) again only using Dagger? You get back to Activity1 and you get User(100) not new User or Singleton object from component created inside Application.

I was thinking Dagger keeps object like a Pool does and linking Activity instances with objects hashes or keeping states or inner references about injected objects, I was asking if it's possible.*

How can i inject same instance of an object unique to an Activity, it's created when that Activity is created for the first time, and injected again when i navigate to or start that Activity using @ActivityScope? I use the snippets below to construct this example

public class User {

    private String name;

    private String email;

    public User() {
        name = "Unknown";
        email = "[email protected]";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

Scope

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}

Module class

@Module
public class UserModule {

    @ActivityScope
    @Provides
    User provideUser() {
        return new User();
    }
}

Component

@ActivityScope
@Component(modules = {UserModule.class})
public interface UserComponent {
    void inject(MainActivity mainActivity);

    void inject(SecondActivity secondActivity);

    void inject(ThirdActivity thirdActivity);
}

I get component from MyApplication and inside MainActivity to test injected objects using userComponent = DaggerUserComponent.create();

public class MainActivity extends AppCompatActivity {

    @Inject
    User user;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        UserComponent daggerUserComponent =  DaggerUserComponent.create();
        daggerUserComponent.inject(this);

        TextView textView = findViewById(R.id.textView);
        textView.setText("Main User: " + user.hashCode());


        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });

    }

}

This one returns different User every time device is rotated and it's expected behavior since new UserComponent is created every time.

public class SecondActivity extends AppCompatActivity {

    @Inject
    User user;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(SecondActivity.this, ThirdActivity.class);
                startActivity(intent);
            }
        });


        ((MyApplication) getApplication()).getUserComponent().inject(this);


        TextView textView = findViewById(R.id.textView);
        textView.setText("Second User: " + user.hashCode());
    }

}

Application class

public class MyApplication extends Application {

    private UserComponent userComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        userComponent = DaggerUserComponent.create();
    }


    public UserComponent getUserComponent() {
        return userComponent;
    }
}

SecondActivity and ThirdActivity uses UserComponent from MyApplication.

My question is why don't these classes get User unique for each Activity? They are injected with same User, how can i make these classes to have their own User even after navigation between?

3
Can you add the code where you create the component in your Application class? - Fred Porciúncula
@ThiagoPorciúncula added MyApplication class. I found that what i ask is not possible. You can't get unique User for each Activity that exist even after Activity is destroyed. I was just wondering if i restart ThirdActivity and get same instance i got last time or the one i will get next time will be the same as last with component from application class. It behaves same as @Singleton and return same User for ActivitySecond and ActivityThird - Thracian

3 Answers

0
votes

I am quite confused with your question. So I am going to answer both of them.

How can i inject same instance of an object to each activity with @ActivityScope? I use the snippets below to construct this example

To inject the same instance of an object to multiple classes, you have to use the same container and scope the provider method.

My question is why don't these classes get User unique for each Activity? They are injected with same User, how can i make these classes to have their own User even after navigation between?

That is because the provideUser is scoped with @ActivityScope. Since you are using the same component from your application, you will be getting the same instance of that object everytime.

To summarize, scoped means same instance for all classes using the same container. Unscoped means always a new object instance every inject.

0
votes

You need different components for each of your activities, then they will provide different users for each activity, and if you will keep component alive until the activity is destroyed - it will provide the same user for same activity even after a configuration change. You can achieve it by using ViewModel and destroy component in method onCleared()

0
votes

In the MyApplication you create an instance of UserComponent and you use that to inject the User in the SecondActivity class. But in MainActivity class you are recreating the UserComponent that is why you have different instances of User in each activity.

You need to use ((MyApplication) getApplication()).getUserComponent().inject(this); in MainActivity as well.