Thracian
Thracian

Reputation: 66814

Dagger2 How to inject Objects unique and created once for each Activity?

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?

Upvotes: 1

Views: 966

Answers (3)

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.

Upvotes: 0

Wackaloon
Wackaloon

Reputation: 2365

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()

Upvotes: 0

tompee
tompee

Reputation: 1408

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.

Upvotes: 0

Related Questions