Как правильно использовать Dagger2 с новыми компонентами архитектуры Android

Я пытаюсь использовать новые компоненты архитектуры, но я все еще новичок в кинжале, и мне чего-то не хватает.

С приведенным ниже кодом я получаю NullPointerException, не могу найти, где. Также, если есть что-то еще, что мне нужно исправить или улучшить, пожалуйста, предложите.

КОД: 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;
    }
}

Репозиторий

@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
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
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);
}

Затем в 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);

Логкат :

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

person Relm    schedule 20.06.2017    source источник
comment
Вы вызвали InjectorClass.inject(this) в onCreate вашей деятельности?   -  person Orest Savchak    schedule 20.06.2017
comment
@OrestSavchak, нет, не знаю, что такое InjectorClass   -  person Relm    schedule 20.06.2017
comment
Я имею в виду, где вы создаете экземпляр ViewModelFactory?   -  person Orest Savchak    schedule 20.06.2017
comment
Я думал, что это делает это. @Inject public ViewModelProvider.Factory factory;, я ошибаюсь?   -  person Relm    schedule 20.06.2017
comment
Вам нужно вызвать AndroidInjection.inject(this) в начале метода onCreate. Но также для этого вам необходимо определить класс модуля с предоставлением правил и интерфейса компонента с методами ввода (активность MainActivity).   -  person Orest Savchak    schedule 20.06.2017
comment
@OrestSavchak, хорошо, я рассмотрел ваш комментарий выше, добавил ApplicationModule и другие классы, я добавлю новые вещи к вопросу, все еще пытаясь решить ошибку, из-за которой он не компилируется.   -  person Relm    schedule 20.06.2017
comment
Вы смогли решить эту Релм?   -  person Mohamed ALOUANE    schedule 04.09.2017
comment
@MohamedALOUANE, да, я много чего не понимал в этом, возможно, вам придется задать новый вопрос о вашей конкретной проблеме, постараюсь ответить на него.   -  person Relm    schedule 05.09.2017
comment
Привет, ты решил проблему?   -  person romaneso    schedule 15.10.2017


Ответы (1)


Проблема вызвана тем, что экземпляр ViewModelFactory имеет значение null внутри вашего MainActivity, как предполагает NPE. Это само по себе, скорее всего, вызвано тем, что ViewModelFactory не вводится должным образом, поэтому остается нулевым. Как предлагает Орест в комментариях, вам нужно убедиться, что MainActivity правильно вставлен из вашего AppModule:

Основная активность:

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;
    }
}

Вы можете взглянуть на большинство классов DI, используемых в соответствующем вопросе, который я разместил ранее, по адресу AndroidInjector‹android.app.Activity› не может быть предоставлен без аннотированного метода @Provides- или @Produces-, и посмотрите, поможет ли вам эта настройка.

person Bogdan Zurac    schedule 02.07.2017