I am fairly new to Android coming from a c# background and was came across dependency injection with dagger. I managed to create a simple example but was wondering how i can use my repository (i tried to use the repository pattern here) in another activity. So my structure is following:
When i try to create a workout in my MainActivity class it works just fine. So i added following line to my AddWorkoutActivity class
@Inject
public WorkoutRepository workoutRepository;
But when i try to save the workout I always get a null reference error on the workoutRepository so i do miss something in my understanding how the DI works here. Maybe someone can give me a hint what i have to do so my repository is instantiated the correct way in my Activity.
// Edit: I think the problem is that i call the DaggerAppComponent.builder()... in the onCreate Method in my MainActivity class, so the AddWorkoutActivity won`t know anything of that. But where do i initialize the DaggerAppComponent so that both activities can acces it correctly?
Best regards
App Component:
package jh.projects.wodm8.di;
import android.app.Application;
import javax.inject.Singleton;
import dagger.Component;
import jh.projects.wodm8.view.MainActivity;
import jh.projects.wodm8.data.WorkoutDao;
import jh.projects.wodm8.repository.DemoDatabase;
import jh.projects.wodm8.repository.WorkoutRepository;
@Singleton
@Component(modules = {AppModule.class, RoomModule.class})
public interface AppComponent {
void inject(MainActivity mainActivity);
WorkoutDao workoutDao();
DemoDatabase demoDatabase();
WorkoutRepository productRepository();
Application application();
}
AppModule
package jh.projects.wodm8.di;
import android.app.Application;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AppModule {
Application mApplication;
public AppModule(Application application) {
mApplication = application;
}
@Provides
@Singleton
Application providesApplication() {
return mApplication;
}
}
RoomModule
package jh.projects.wodm8.di;
import android.app.Application;
import androidx.room.Room;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import jh.projects.wodm8.data.WorkoutDao;
import jh.projects.wodm8.repository.DemoDatabase;
import jh.projects.wodm8.repository.WorkoutDataSource;
import jh.projects.wodm8.repository.WorkoutRepository;
@Module
public class RoomModule{
private DemoDatabase demoDatabase;
public RoomModule(Application mApplication) {
demoDatabase = Room.databaseBuilder(mApplication, DemoDatabase.class, "demo-db").allowMainThreadQueries().build();
}
@Singleton
@Provides
DemoDatabase providesRoomDatabase() {
return demoDatabase;
}
@Singleton
@Provides
WorkoutDao providesWorkoutDao(DemoDatabase demoDatabase) {
return demoDatabase.getWorkoutDao();
}
@Singleton
@Provides
WorkoutRepository providesWorkoutRepository(WorkoutDao workoutDao) {
return new WorkoutDataSource(workoutDao);
}
}
WorkoutDataSource
package jh.projects.wodm8.repository;
import androidx.lifecycle.LiveData;
import java.util.List;
import javax.inject.Inject;
import jh.projects.wodm8.data.Workout;
import jh.projects.wodm8.data.WorkoutDao;
public class WorkoutDataSource implements WorkoutRepository {
private WorkoutDao workoutDao;
@Inject
public WorkoutDataSource(WorkoutDao workoutDao) {
this.workoutDao = workoutDao;
}
@Override
public LiveData<Workout> findById(int id) {
return workoutDao.findById(id);
}
@Override
public LiveData<List<Workout>> findAll() {
return workoutDao.findAll();
}
@Override
public void insert(Workout workout) {
workoutDao.insert(workout);
}
@Override
public int delete(Workout workout) {
return workoutDao.delete(workout);
}
}
WorkoutRepository
package jh.projects.wodm8.repository;
import androidx.lifecycle.LiveData;
import java.util.List;
import jh.projects.wodm8.data.Workout;
public interface WorkoutRepository {
LiveData<Workout> findById(int id);
LiveData<List<Workout>> findAll();
void insert(Workout workout);
int delete(Workout workout);
}
MainActivity package jh.projects.wodm8.view;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.List;
import javax.inject.Inject;
import jh.projects.wodm8.R;
import jh.projects.wodm8.data.Workout;
import jh.projects.wodm8.di.AppModule;
import jh.projects.wodm8.di.DaggerAppComponent;
import jh.projects.wodm8.di.RoomModule;
import jh.projects.wodm8.repository.WorkoutRepository;
public class MainActivity extends AppCompatActivity {
@Inject
public WorkoutRepository workoutRepository;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(view.getContext(), AddWorkoutActivity.class);
startActivity(intent);
}
});
DaggerAppComponent.builder()
.appModule(new AppModule(getApplication()))
.roomModule(new RoomModule(getApplication()))
.build()
.inject(this);
workoutRepository.findAll().observe(this, new Observer<List<Workout>>() {
@Override
public void onChanged(@Nullable List<Workout> products) {
Toast.makeText(MainActivity.this, String.format("Product size: %s", products.size()), Toast.LENGTH_SHORT).show();
}
});
}
}
AddWorkoutActivity
package jh.projects.wodm8.view;
import androidx.appcompat.app.AppCompatActivity;
import jh.projects.wodm8.R;
import jh.projects.wodm8.data.Workout;
import jh.projects.wodm8.di.AppModule;
import jh.projects.wodm8.di.DaggerAppComponent;
import jh.projects.wodm8.di.RoomModule;
import jh.projects.wodm8.repository.DemoDatabase;
import jh.projects.wodm8.repository.WorkoutRepository;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import javax.inject.Inject;
public class AddWorkoutActivity extends AppCompatActivity {
@Inject
public WorkoutRepository workoutRepository;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_workout);
final Button button = findViewById(R.id.saveWorkout);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Workout workout = new Workout();
EditText txtTitle = (EditText) findViewById(R.id.workoutTitleText);
workout.setTitle(txtTitle.getText().toString());
try {
workoutRepository.insert(workout);
} catch (Exception e) {
Log.v("AddWorkout", e.getMessage());
}
Toast.makeText(AddWorkoutActivity.this, "Inserted", Toast.LENGTH_SHORT).show();
}
});
}
}
// EDIT: Thanks to a_local_nobody for the links to start with Dagger: https://youtu.be/Qwk7ESmaCq0
I found another source to start with dagger that helped me too: https://www.raywenderlich.com/262-dependency-injection-in-android-with-dagger-2-and-kotlin#toc-anchor-005
to give you a bit of a more complete answer, taken from this online resource https://github.com/MindorksOpenSource/android-dagger2-example/blob/master/app/src/main/java/com/mindorks/example/android_dagger2_example/DemoApplication.java
(i'm just going over it briefly to give you a better understanding)
Create an application class which extends Application and implement this :
@Override
public void onCreate() {
super.onCreate();
applicationComponent = DaggerApplicationComponent
.builder()
.applicationModule(new ApplicationModule(this))
.build();
applicationComponent.inject(this);
}
you have to define your own applicationComponent though, just going through this briefly.
after that, you should be able to use your repositories in several different places with the annotation of @Inject
where you need them, just remember to actually call the injection where you need it, making use of
getActivityComponent().inject(this);
or AndroidInjection.inject(this)
where you need to, hopefully this github example and the tutorials are enough to answer some of your questions