[英]Android Architecture Components how to achieve two-way bindings for objects with ViewModel
[英]ViewModel instance - Activity UI - Android Architecture Components
public class WordViewModel extends AndroidViewModel {
private WordRepository mRepository;
private LiveData<List<Word>> mAllWords;
public WordViewModel(@NonNull Application application) {
super(application);
mRepository = new WordRepository(application);
mAllWords = mRepository.getAllWords();
}
LiveData<List<Word>> getAllWords() {
return mAllWords;
}
public void insert(Word word) {
mRepository.insert(word);
}
}
mWordViewModel = new ViewModelProvider(this,
new ViewModelProvider.AndroidViewModelFactory(getApplication()))
.get(WordViewModel.class);
public class WordRepository {
private WordDao mWordDao;
private LiveData<List<Word>> mAllWords;
public WordRepository(Application application) {
WordRoomDatabase db = WordRoomDatabase.getDatabase(application);
mWordDao = db.wordDao();
mAllWords = mWordDao.getAllWords();
}
LiveData<List<Word>> getAllWords() {
return mAllWords;
}
public void insert(Word word) {
new insertAsyncTask(mWordDao).execute(word);
}
private static class insertAsyncTask extends AsyncTask<Word, Void, Void> {
private WordDao mAsyncTaskDao;
insertAsyncTask(WordDao dao) {
mAsyncTaskDao = dao;
}
@Override
protected Void doInBackground(final Word... params) {
mAsyncTaskDao.insert(params[0]);
return null;
}
}
}
@Database(entities = {Word.class}, version = 1, exportSchema = false)
public abstract class WordRoomDatabase extends RoomDatabase {
public abstract WordDao wordDao();
private static WordRoomDatabase INSTANCE;
public static WordRoomDatabase getDatabase(Context context) {
if (INSTANCE == null) {
synchronized (WordRoomDatabase.class) {
if (INSTANCE == null) {
Room.databaseBuilder(context.getApplicationContext(),
WordRoomDatabase.class, "word_database")
.fallbackToDestructiveMigration()
.addCallback(sRoomDatabaseCallback)
.build();
}
}
}
return INSTANCE;
}
private static Callback sRoomDatabaseCallback =
new Callback() {
@Override
public void onOpen(@NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
new PopulateDbAsync(INSTANCE).execute();
}
};
/**
* Populate the database in the background.
*/
private static class PopulateDbAsync extends AsyncTask<Void, Void, Void> {
private final WordDao mDao;
String[] words = {"dolphin", "crocodile", "cobra"};
PopulateDbAsync(WordRoomDatabase db) {
mDao = db.wordDao();
}
@Override
protected Void doInBackground(final Void... params) {
// Start the app with a clean database every time.
// Not needed if you only populate the database
// when it is first created
mDao.deleteAll();
for (int i = 0; i <= words.length - 1; i++) {
Word word = new Word(words[i]);
mDao.insert(word);
}
return null;
}
}
}
我試圖在 MainActivity 的onCreate方法中實例化 ViewModel 類,但它顯示以下錯誤。
無法創建類 com.example.roomwords_sample.WordViewModel 的實例
我也嘗試使用ViewModelProviders.of(this).get(ViewModel.class)但它仍然顯示相同的錯誤。 我也在查看其他人對類似問題的回答,但它不起作用。 我幾乎嘗試了所有方法。 請幫幫我。
添加了堆棧跟蹤
2020-09-20 01:51:37.103 13578-13578/com.example.roomwords_sample E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.roomwords_sample, PID: 13578
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.roomwords_sample/com.example.roomwords_sample.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.example.roomwords_sample.WordViewModel
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.RuntimeException: Cannot create an instance of class com.example.roomwords_sample.WordViewModel
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:275)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at com.example.roomwords_sample.MainActivity.onCreate(MainActivity.java:32)
at android.app.Activity.performCreate(Activity.java:8000)
at android.app.Activity.performCreate(Activity.java:7984)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:267)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at com.example.roomwords_sample.MainActivity.onCreate(MainActivity.java:32)
at android.app.Activity.performCreate(Activity.java:8000)
at android.app.Activity.performCreate(Activity.java:7984)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'com.example.roomwords_sample.WordDao com.example.roomwords_sample.WordRoomDatabase.wordDao()' on a null object reference
at com.example.roomwords_sample.WordRepository.<init>(WordRepository.java:18)
at com.example.roomwords_sample.WordViewModel.<init>(WordViewModel.java:18)
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:267)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at com.example.roomwords_sample.MainActivity.onCreate(MainActivity.java:32)
at android.app.Activity.performCreate(Activity.java:8000)
at android.app.Activity.performCreate(Activity.java:7984)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
問題在於您的WordRoomDatabase.getDatabase(application)
方法
當你寫:
if (INSTANCE == null) {
Room.databaseBuilder(context.getApplicationContext(),
WordRoomDatabase.class, "word_database")
.fallbackToDestructiveMigration()
.addCallback(sRoomDatabaseCallback)
.build();
}
您創建了數據庫,但實際上並未將其分配給INSTANCE
變量。 這意味着您的INSTANCE
始終為空,而WordRoomDatabase.getDatabase(application)
實際上從不返回空值以外的任何內容。
您可以通過設置INSTANCE
變量來解決您的問題和來自它的NullPointerException
:
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
WordRoomDatabase.class, "word_database")
.fallbackToDestructiveMigration()
.addCallback(sRoomDatabaseCallback)
.build();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.