问题描述
我正在寻找帮助,以更好地了解Android中的LiveData.
I am looking for help to better understand LiveData in Android.
我创建了一个应用程序,允许用户查看,编辑或创建数据库中的条目.
I have created an application that allows a user to view, edit or create entries in a db.
我在表单活动上使用了一个视图模型,以在活动和片段之间共享信息,并使数据具有生命周期意识.
I have used a viewmodel on the form activity to share information between the activity and fragments and to also make the data Lifecycle aware.
当我从数据库中加载一个条目时,代码工作得很好.捕获所有更改并将其保存回数据库
The code works great when I load a entry from the database. Any changes are captured and saved back to the database
但是,当我想使用相同的代码创建新条目时,原因:java.lang.NullPointerException:当我尝试更新视图模型中的对象时,尝试调用虚拟方法... null对象引用.下面的示例尝试在用户输入新名称时设置Name值:
However when I want to create a new entry using the same code I getCaused by: java.lang.NullPointerException: Attempt to invoke virtual method ...null object reference when I try to update the object in the viewmodel. Sample below tries to set the Name value when a user enters a new one:
public void afterTextChanged(Editable s) {
patternViewModel.getPattern().getValue().setName(s.toString());
((FlyPatternDetailActivity)getActivity()).setHasChanged(true);
((FlyPatternDetailActivity)getActivity()).setActionBar(s.toString());
}
我的问题是,如果我没有从数据库中获取对象,而是要创建一个新条目,该如何更新实体的livedata对象.
My question is how to update the livedata object of my entity if I dont get an object back from my database and I am going to create a new entry.
我的视图模型是:
public class PatternViewModel extends AndroidViewModel {
private PatternRepository repo;
private LiveData<FlyPattern> mObservablePattern;
public PatternViewModel(@NonNull Application application) {
super(application);
if (mObservablePattern == null) {
mObservablePattern = new MutableLiveData<>();
}
repo = PatternRepository.getInstance(((FlyTyingJournalApplicationClass) application).getDatabase());
}
public void loadPattern(final long id){
if(id != -1)
mObservablePattern = repo.getPattern(id);
}
public LiveData<FlyPattern> getPattern(){
return mObservablePattern;
}
public void insertPattern() {
repo.insertPattern(mObservablePattern.getValue());
}
public void updateFlyPattern(){
repo.updatePattern(mObservablePattern.getValue());
}
public void deleteFlyPattern(){
repo.deletePattern(mObservablePattern.getValue());
}
}
我了解为什么会收到nullpointException.
I understand why I am getting the nullpointException.
我的问题是如何实例化我的mObservablePattern以便更新它.
My question is how to instantiate my mObservablePattern so I can update it.
如果loadPattern返回一个对象,它将被实例化.
It gets instantiated if the loadPattern returns an object.
如果loaddata没有运行或确实从数据库返回了一个对象,那么我将无法更新mObservablePattern.
If the loaddata does not run or does return an object from the database then I cannot update mObservablePattern.
错误的堆栈跟踪:
Process: com.rb.android.flytyingjournal, PID: 4957
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.rb.android.flytyingjournal.entities.FlyPattern.setType(java.lang.String)' on a null object reference
at com.rb.android.flytyingjournal.flypatterndetails.PatternDetailsFragment$5.onItemSelected(PatternDetailsFragment.java:325)
at android.widget.AdapterView.fireOnSelected(AdapterView.java:931)
at android.widget.AdapterView.dispatchOnItemSelected(AdapterView.java:920)
at android.widget.AdapterView.-wrap1(AdapterView.java)
at android.widget.AdapterView$SelectionNotifier.run(AdapterView.java:890)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
推荐答案
您正试图在NULL
上调用setName()
.因为patternViewModel.getPattern().getValue()
返回保存在LiveData
中的值,在您的情况下可能为NULL
.您可以添加一个空检查:
You are trying to call setName()
on a NULL
. Because patternViewModel.getPattern().getValue()
returns the value that is held in the LiveData
, which might be NULL
in your case. You can add a null check:
if (patternViewModel.getPattern().getValue() == null) {
FlyPattern flyPattern = new FlyPattern();
flyPattern.setName("foo");
patternViewModel.getPattern().setValue(flyPattern);
} else {
patternViewModel.getPattern().getValue().setName("foo");
}
或者您可以在ViewModel中创建一个函数,例如setFlyPatternName()并使用它来更新数据库.
在您的PatternViewModel.java
Or you can create a function in the ViewModel called e.g. setFlyPatternName() and use it to update your DB.
In your PatternViewModel.java
public void setFlyPatternName(String name) {
if (mObservablePattern.getValue == null) {
FlyPattern flyPattern = new FlyPattern();
flyPattern.setName(name);
mObservablePattern.setValue(flyPattern);
repo.insertFlyPattern();
} else {
mObservablePattern.getValue().setName(name);
repo.updateFlyPattern();
}
}
执行此操作的正确方法实际上有所不同.通常,您的存储库函数需要在后台线程上运行,因为您正在处理I/O,但是如果您希望它们在mainThread上运行,则需要至少创建一个回调并将该回调对象传递给您的存储库函数,插入/更新/删除数据时将调用.当调用回调函数时,您需要在LiveData
上调用setValue()
并将数据设置为livedata对象.
The proper way of doing this is actually a bit different.Normally your repository functions need to work on the background thread, since you are dealing with i/o, but if you want them to work on the mainThread you need to at least create a callback and pass that callback object to your repository function, which will be called when the data is inserted/updated/deleted. And when the callback function is called you need to call the setValue()
on the LiveData
and set the data to your livedata object.
创建一个回调接口:
public interface InsertCallback {
void onDataInserted(FlyPattern flyPattern);
void onDataInsertFailed();
}
更改存储库插入函数的主体以接受Callback
对象作为参数
Change your repositories insert function's body to accept the Callback
object as parameter
public void insertFlyPattern(FlyPattern flyPattern, InsertCallback insertCallback) {
// Do your insertion and if it is successful call insertCallback.onDataInserted(flyPattern), otherwise call insertCallback.onDataInsertFailed();
}
在您的ViewModel中实现InsertCallback
及其方法
In your ViewModel implement InsertCallback
and it's method
public class PatternViewModel extends AndroidViewModel implements InsertCallback {
//....
public void onDataInserted(FlyPattern flyPattern) {
mObservablePattern.setValue(flyPattern);
}
public void onDataInsertFailed() {
//Show error message
}
}
这篇关于尝试更新对象时,Android LiveData空错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!