Pra*_*ina 46 android mvvm android-architecture-components
我正在关注此文档以了解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;
}
}
Run Code Online (Sandbox Code Playgroud)
但是,当我运行代码时,我得到异常:
final UserViewModelviewModel = ViewModelProviders.of(this).get(UserViewModel.class);
Run Code Online (Sandbox Code Playgroud)
引起:java.lang.RuntimeException:无法创建类UserViewModel的实例引起:java.lang.InstantiationException:java.lang.Class没有零参数构造函数
Sha*_*med 44
在初始化ViewModelusing的子类时ViewModelProviders,默认情况下它期望您的UserModel类具有零参数构造函数.在你的情况下,你的构造函数有参数MutableLiveData<User> user
解决此问题的一种方法是为您设置默认的无arg构造函数 UserModel
否则,如果您希望ViewModel类具有非零参数构造函数,则可能必须创建一个自定义ViewModelFactory类来初始化ViewModel实例,该实例将实现ViewModelProvider.Factory接口.
我还没有尝试过这个,但是这里有链接到google的优秀样本:github.com/googlesamples/android-architecture-components.具体来说,结帐此类GithubViewModelFactory.java用于Java代码,此类GithubViewModelFactory.kt用于相应的Kotlin代码
Dim*_*sus 35
在我使用 HILT 的情况下,它在具有 ViewModel 的 Fragment 上方缺少一个注释:@AndroidEntryPoint
@AndroidEntryPoint
class BestFragment : Fragment() {
....
Run Code Online (Sandbox Code Playgroud)
当然,在您的 ViewModel 类中,您还需要使用 HILT 需要的内容进行注释:@ViewModelInject
class BestFragmentViewModel @ViewModelInject constructor(var userManager: UserManager) : ViewModel() {
....
}
Run Code Online (Sandbox Code Playgroud)
For*_*ran 32
对于刀柄:
简单添加@AndroidEntryPoint主要活动和片段以及@HiltViewModel视图模型
之后的示例:
@HiltViewModel
class SplashViewModel @Inject constructor(
@AndroidEntryPoint
class SplashFragment : Fragment() {
private lateinit var b: SplashFragmentBinding
private val vm: SplashViewModel by viewModels()
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
Run Code Online (Sandbox Code Playgroud)
yoA*_*ex5 28
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();
}
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
ViewModelKey 是一个注释,用于在地图中使用作为键,看起来像
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@MapKey
@interface ViewModelKey {
Class<? extends ViewModel> value();
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以创建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;
}
}
Run Code Online (Sandbox Code Playgroud)
实例化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);
}
}
Run Code Online (Sandbox Code Playgroud)
并且不要伪造添加ViewModelModule到modules列表中
@Singleton
@Component(modules = {ApplicationModule.class, ViewModelModule.class})
public interface ApplicationComponent {
//
}
Run Code Online (Sandbox Code Playgroud)
2020 年初,Google 弃用了 androidx 生命周期库 2.2.0 版中的 ViewModelProviders 类。
不再需要使用 ViewModelProviders 来创建 ViewModel 的实例,您可以将 Fragment 或 Activity 实例传递给 ViewModelProvider 构造函数。
如果您使用以下代码:
val viewModel = ViewModelProviders.of(this).get(CalculatorViewModel::class.java)
Run Code Online (Sandbox Code Playgroud)
您会收到一条警告,指出ViewModelProviders 已被弃用。
你可以这样做:
val viewModel = ViewModelProvider(this).get(CalculatorViewModel::class.java)
Run Code Online (Sandbox Code Playgroud)
或者,要使用委托,请进行以下更改。
在 build.gradle (Module: app) 文件中,使用生命周期组件的 2.2.0 版本:
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
还添加
implementation "androidx.activity:activity-ktx:1.1.0"
如果您想使用 Fragment 中的 ViewModel,请使用
implementation "androidx.fragment:fragment-ktx:1.2.2"
fragment-ktx 自动包含 activity-ktx,因此您无需在依赖项中同时指定两者。
您需要在 android 部分指定 Java 8:
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.kgandroid.calculator"
minSdkVersion 17
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
kotlinOptions {
jvmTarget = "1.8"
}
}
Run Code Online (Sandbox Code Playgroud)
在您的片段或活动中,将导入更改为:
导入 androidx.activity.viewModels
然后创建 ViewModel 的代码变为:
val viewModel: CalculatorViewModel by viewModels()
代替
val viewModel = ViewModelProviders.of(this).get(CalculatorViewModel::class.java)
将 viewModel 对象用作:
val viewModel: CalculatorViewModel by viewModels()
viewModel.newNumber.observe(this, Observer { stringResult -> newNumber.setText(stringResult) })
其中newNumer 是一个 LiveData 对象
In a Fragment that you want to share the Activity's ViewModel, you'd use
`val viewModel: CalculatorViewModel by activityViewModels()`
**That's the equivalent of passing the Activity instance in the (deprecated)
ViewModelProviders.of() function.**
Run Code Online (Sandbox Code Playgroud)
我遇到了一些问题,@ViewModelInject因为它已被 HILT 弃用。要解决此问题,请更改此代码:
class MainViewModel @ViewModelInject constructor(
val mainRepository: MainRepository
): ViewModel()
Run Code Online (Sandbox Code Playgroud)
和:
@HiltViewModel
class MainViewModel @Inject constructor(
val mainRepository: MainRepository
): ViewModel()
Run Code Online (Sandbox Code Playgroud)
当然,请记住@AndroidEntryPoint在您的片段或活动(无论您在哪里实例化ViewModel)上方添加注释,如下所示:
@AndroidEntryPoint
class UsageFragment : Fragment(R.layout.fragment_usage) {
.
.
.
}
Run Code Online (Sandbox Code Playgroud)
终极提示:
您可以立即查看 HILT 是否正常工作,查看ViewModel.
在这里它不起作用:
在这里它确实有效:
如果您在更新代码后没有看到它们,请单击 Build -> Rebuild Project
2020-07-29 10:13:25
对于lifecycle_version = '2.2.0'ViewProviders.of API 已弃用。这是我的情况:
class MainActivityViewModel(application: Application) : AndroidViewModel(application) {
private var repository: UserRepository
val allUsers: LiveData<List<User>>
......
error:
val userViewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)
success:
val factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application)
userViewModel = ViewModelProvider(this,factory).get(MainActivityViewModel::class.java)
Run Code Online (Sandbox Code Playgroud)
通过application由APIViewModelProvider.AndroidViewModelFactory.getInstance
小智 5
我有同样的错误。我正在使用Hilt,在我的例子中,它缺少第二个 hilt 编译器依赖项
现在我两者都有:
kapt com.google.dagger:hilt-android-compiler:#version
Run Code Online (Sandbox Code Playgroud)
和
kapt androidx.hilt:hilt-compiler:#version
Run Code Online (Sandbox Code Playgroud)
在我的应用程序级别 build.gradle 文件中,它可以工作。
当您使用 Hilt Android Gradle 插件(请参阅文档)时,需要com.google.dagger :hilt- android-compiler ; 当您想要 Hilt 和 Jetpack 集成(例如注入 Android)时,显然需要 androidx.hilt:hilt-compiler:#version Jetpack ViewModel(请参阅文档)
| 归档时间: |
|
| 查看次数: |
19916 次 |
| 最近记录: |