I'm trying to use the new Architecture Components, but I'm also still new to dagger and I'm missing stuff.
With the below code, I'm getting a NullPointerException, can't locate where. Also if there's something else I need to fix or improve, please suggest.
CODE : ViewModel
public class PostsVM extends ViewModel {
private LiveData<StoryPost> post;
private Repository repository;
@Inject
public PostsVM(Repository repository) {
this.repository = repository;
}
public void init() {
if (this.post != null) {
return;
}
post = repository.getPosts();
}
public LiveData<StoryPost> getPost() {
return post;
}
}
Repository
@Singleton
public class Repository {
private final MutableLiveData<StoryPost> data = new MutableLiveData<>();
public LiveData<StoryPost> getPosts() {
//
new GetUser(post.getUid()) {
@Override
public void onSuccess(@NonNull User user) {
// this is where I setValue//
data.setValue(post);
}
@Override
public void onError() {
}
@Override
public void userNotFound() {
}
};
return data;
}
}
Singleton Factory
@Singleton
public class ViewModelFactory implements ViewModelProvider.Factory {
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;
@Inject
public ViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
this.creators = creators;
}
@SuppressWarnings("unchecked")
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
Provider<? extends ViewModel> creator = creators.get(modelClass);
if (creator == null) {
for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {
if (modelClass.isAssignableFrom(entry.getKey())) {
creator = entry.getValue();
break;
}
}
}
if (creator == null) {
throw new IllegalArgumentException("unknown model class " + modelClass);
}
try {
return (T) creator.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
DAO
@Dao
public interface PostDao {
@Query("SELECT * FROM posts ORDER by time DESC")
LiveData<List<StoryPost>> getAll();
@Query("SELECT * FROM posts WHERE id = :id")
LiveData<List<StoryPost>> getPost(String id);
@Insert(onConflict = OnConflictStrategy.REPLACE)
@NonNull
void insert(StoryPost... posts);
@Delete
void delete(StoryPost post);
@Update
void update(StoryPost post);
}
Then in MainActivity:
@Inject public ViewModelFactory factory;
//...
//*onCreate*
PostsVM model = ViewModelProviders.of(this, factory).get(PostsVM.class);
model.init();
final Observer<StoryPost> observer = post -> storyAdapter.insert(post);
model.getPost().observe(this, observer);
Logcat :
... java.lang.NullPointerException: Attempt to invoke interface method
'android.arch.lifecycle.ViewModel android.arch.lifecycle.ViewModelProvider
$Factory.create(java.lang.Class)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2479)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2539)
at android.app.ActivityThread.access$900(ActivityThread.java:168)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1378)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:150)
at android.app.ActivityThread.main(ActivityThread.java:5665)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:799)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:689)
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'android.arch.lifecycle.ViewModel android.arch.lifecycle.ViewModelProvider$Factory.create(java.lang.Class)' on a null object reference
at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:128)
at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:96)
at com.aollay.smartpaper.MainActivity.bindDatabase(MainActivity.java:238)
at com.aollay.smartpaper.MainActivity.populateNews(MainActivity.java:233)
at com.aollay.smartpaper.MainActivity.config(MainActivity.java:159)
at com.aollay.smartpaper.MainActivity.onCreate(MainActivity.java:74)
at android.app.Activity.performCreate(Activity.java:6372)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2432)
Dagger 2 is a compile-time android dependency injection framework that uses Java Specification Request 330 and Annotations. Some of the basic annotations that are used in dagger 2 are: @Module This annotation is used over the class which is used to construct objects and provide the dependencies.
Dagger is arguably the most used Dependency Injection, or DI, framework for Android. Many Android projects use Dagger to simplify building and providing dependencies across the app. It gives you the ability to create specific scopes, modules, and components, where each forms a piece of a puzzle: The dependency graph.
The issue is caused by the ViewModelFactory
instance being null inside your MainActivity
, as the NPE suggests. This itself is most probably caused by the fact that the ViewModelFactory
is not being injected properly, thus remaining null. As Orest suggests inside the comments, you need to make sure that the MainActivity
is properly injected from your AppModule
:
MainActivity:
public class MainActivity extends AppCompatActivity implements HasSupportFragmentInjector
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
AndroidInjection.inject(activity);
super.onCreate(savedInstanceState);
}
// if your Activity also has Fragments which need to be injected
@Inject
DispatchingAndroidInjector<Fragment> androidInjector;
@Override
public DispatchingAndroidInjector<Fragment> supportFragmentInjector()
{
return androidInjector;
}
}
You can take a look at most of the DI classes being used in a related question I posted earlier over at AndroidInjector<android.app.Activity> cannot be provided without an @Provides- or @Produces-annotated method and see if that setup helps you out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With