Android ViewModel не имеет конструктора нулевого аргумента

Я этой документация, чтобы узнать о LiveData и ViewModel. В doc класс ViewModel имеет конструктор как таковой,

public class UserModel extends ViewModel {
  private MutableLiveData<User> user;

  @Inject UserModel(MutableLiveData<User> user) {
    this.user = user;
  }

  public void init() {
    if (this.user != null) {
      return;
    }
    this.user = new MutableLiveData<>();
  }

  public MutableLiveData<User> getUser() {
    return user;
  }
}

однако, когда я запускаю код, я получаю исключение:

final UserViewModelviewModel = ViewModelProviders.of(this).get(UserViewModel.class);

вызвано: java.ленг.RuntimeException: не удается создать экземпляр класса UserViewModel Вызвано: java.ленг.Исключение InstantiationException: Ява.ленг.Класс не имеет конструктора нулевого аргумента

4 ответов


при инициализации подклассов ViewModel используя ViewModelProviders по умолчанию он ожидает вашего UserModel класс для конструктора нулевого аргумента. В вашем случае ваш конструктор имеет аргумент MutableLiveData<User> user

один из способов исправить это-по умолчанию конструктор без аргументов для UserModel

в противном случае, если вы хотите иметь конструктор с ненулевым аргументом для класса ViewModel, вам может потребоваться создать пользовательский ViewModelFactory класс для инициализации экземпляра ViewModel, который будет реализовать ViewModelProvider.Factory интерфейс.

Я еще не пробовал это, но вот ссылка на отличный образец от google для того же: github.com/googlesamples/android-architecture-components. В частности, проверьте этот класс GithubViewModelFactory.java для кода Java и этого класса GithubViewModelFactory.kt для соответствующего кода Котлина


ViewModelFactory это предоставит нам право ViewModel от ViewModelModule

public class ViewModelFactory implements ViewModelProvider.Factory {
    private final Map<Class<? extends ViewModel>, Provider<ViewModel>> viewModels;

    @Inject
    public ViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> viewModels) {
        this.viewModels = viewModels;
    }

    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) {
        Provider<ViewModel> viewModelProvider = viewModels.get(modelClass);

        if (viewModelProvider == null) {
            throw new IllegalArgumentException("model class " + modelClass + " not found");
        }

        return (T) viewModelProvider.get();
    }
}

ViewModelModule отвечает за привязку всех классов ViewModel к
Map<Class<? extends ViewModel>, Provider<ViewModel>> viewModels

@Module
public abstract class ViewModelModule {

    @Binds
    abstract ViewModelProvider.Factory bindViewModelFactory(ViewModelFactory viewModelFactory); 
    //You are able to declare ViewModelProvider.Factory dependency in another module. For example in ApplicationModule.

    @Binds
    @IntoMap
    @ViewModelKey(UserViewModel.class)
    abstract ViewModel userViewModel(UserViewModel userViewModel);

    //Others ViewModels
}

ViewModelKey является аннотацией для использования в качестве ключа на карте и выглядит как

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@MapKey
@interface ViewModelKey {
    Class<? extends ViewModel> value();
}

теперь вы можете создать ViewModel и удовлетворить все необходимые зависимости от графика

public class UserViewModel extends ViewModel {
    private UserFacade userFacade;

    @Inject
    public UserViewModel(UserFacade userFacade) { // UserFacade should be defined in one of dagger modules
        this.userFacade = userFacade;
    }
} 

Создание Экземпляра ViewModel

public class MainActivity extends AppCompatActivity {

    @Inject
    ViewModelFactory viewModelFactory;
    UserViewModel userViewModel;

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

        ((App) getApplication()).getAppComponent().inject(this);

        userViewModel = ViewModelProviders.of(this, viewModelFactory).get(UserViewModel.class);

    }
}

и делать не подделыватель, чтобы добавить ViewModelModule на modules список

@Singleton
@Component(modules = {ApplicationModule.class, ViewModelModule.class})
public interface ApplicationComponent {
    //
}

Если у вас есть параметр в конструктор, то :

DAGGER 2 публичный конструктор для @ inject dependency

@Inject
public UserViewModel(UserFacade userFacade)
{ 
    this.userFacade = userFacade;
}

в противном случае dagger 2 отправит вам ошибку "не удается создать экземпляр объекта viewmodel"


проблема может быть решена путем расширения UserModel С AndroidViewModel который является контекстным приложением ViewModel и требует Application конструктор только для параметров. (документации)

Экс- (в Котлин)

class MyVm(application: Application) : AndroidViewModel(application)

это работает для версии 2.0.0-alpha1.