Android 尝试更新对象时出现 LiveData 空错误
Android LiveData null error when trying to update object
我正在寻求帮助以更好地理解 Android 中的 LiveData。
我创建了一个应用程序,允许用户在数据库中查看、编辑或创建条目。
我在表单 activity 上使用了一个视图模型来在 activity 和片段之间共享信息,并使数据生命周期感知。
当我从数据库加载一个条目时,代码运行良好。捕获任何更改并将其保存回数据库
然而,当我想使用相同的代码创建一个新条目时,我得到
由以下原因引起:java.lang.NullPointerException:尝试调用虚方法...当我尝试更新视图模型中的对象时为空对象引用。下面的示例尝试在用户输入新名称时设置名称值:
public void afterTextChanged(Editable s) {
patternViewModel.getPattern().getValue().setName(s.toString());
((FlyPatternDetailActivity)getActivity()).setHasChanged(true);
((FlyPatternDetailActivity)getActivity()).setActionBar(s.toString());
}
我的问题是如果我没有从我的数据库中取回一个对象并且我要创建一个新条目,如何更新我实体的实时数据对象。
我的视图模型是:
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。
我的问题是如何实例化我的 mObservablePattern 以便我可以更新它。
如果 loadPattern return 是一个对象,它就会被实例化。
如果加载数据不是 运行 或 return 来自数据库的对象,那么我无法更新 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.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()
returns 保存在 LiveData
中的值,在您的情况下可能是 NULL
。您可以添加空检查:
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
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 上工作,您至少需要创建一个回调并将该回调对象传递给您的存储库函数,当数据为 inserted/updated/deleted 时将被调用。当调用回调函数时,您需要在 LiveData
上调用 setValue()
并将数据设置为您的 livedata 对象。
创建回调接口:
public interface InsertCallback {
void onDataInserted(FlyPattern flyPattern);
void onDataInsertFailed();
}
更改存储库插入函数的主体以接受 Callback
对象作为参数
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
及其方法
public class PatternViewModel extends AndroidViewModel implements InsertCallback {
//....
public void onDataInserted(FlyPattern flyPattern) {
mObservablePattern.setValue(flyPattern);
}
public void onDataInsertFailed() {
//Show error message
}
}
我正在寻求帮助以更好地理解 Android 中的 LiveData。
我创建了一个应用程序,允许用户在数据库中查看、编辑或创建条目。
我在表单 activity 上使用了一个视图模型来在 activity 和片段之间共享信息,并使数据生命周期感知。
当我从数据库加载一个条目时,代码运行良好。捕获任何更改并将其保存回数据库
然而,当我想使用相同的代码创建一个新条目时,我得到 由以下原因引起:java.lang.NullPointerException:尝试调用虚方法...当我尝试更新视图模型中的对象时为空对象引用。下面的示例尝试在用户输入新名称时设置名称值:
public void afterTextChanged(Editable s) {
patternViewModel.getPattern().getValue().setName(s.toString());
((FlyPatternDetailActivity)getActivity()).setHasChanged(true);
((FlyPatternDetailActivity)getActivity()).setActionBar(s.toString());
}
我的问题是如果我没有从我的数据库中取回一个对象并且我要创建一个新条目,如何更新我实体的实时数据对象。
我的视图模型是:
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。
我的问题是如何实例化我的 mObservablePattern 以便我可以更新它。
如果 loadPattern return 是一个对象,它就会被实例化。
如果加载数据不是 运行 或 return 来自数据库的对象,那么我无法更新 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.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()
returns 保存在 LiveData
中的值,在您的情况下可能是 NULL
。您可以添加空检查:
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
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 上工作,您至少需要创建一个回调并将该回调对象传递给您的存储库函数,当数据为 inserted/updated/deleted 时将被调用。当调用回调函数时,您需要在 LiveData
上调用 setValue()
并将数据设置为您的 livedata 对象。
创建回调接口:
public interface InsertCallback {
void onDataInserted(FlyPattern flyPattern);
void onDataInsertFailed();
}
更改存储库插入函数的主体以接受 Callback
对象作为参数
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
及其方法
public class PatternViewModel extends AndroidViewModel implements InsertCallback {
//....
public void onDataInserted(FlyPattern flyPattern) {
mObservablePattern.setValue(flyPattern);
}
public void onDataInsertFailed() {
//Show error message
}
}