不确定发生了什么。我正在运行两个查询,然后使用MediatorLiveData和Transformations.map进行合并和转换。我正在将这个几乎完全相同的代码用于另外两个查询,没有问题。但是,当我将其用于这些特定查询时,该应用程序会因以下错误而崩溃。
请注意:我已经尝试观察MediatorLiveData,并且我可以得到两个查询的结果而没有错误。仅当我尝试通过Transformations.map运行它们时,我才会收到错误并导致应用崩溃。
这是我用来测试MediatorLiveData的观察值,可以正常工作:
viewModel.getAllValidEventsLiveDataMerger().observe(this, new Observer<AllValidEventsSnapshot>() {
@Override
public void onChanged(@Nullable AllValidEventsSnapshot allValidEventsSnapshot) {
if (allValidEventsSnapshot.isComplete()) {
List<Event> nonRepeatEventList;
List<Event> repeatEventList;
List<Event> eventList = new ArrayList<>();
nonRepeatEventList = allValidEventsSnapshot.getValidNonRepeatableEventsSnapshot().toObjects(Event.class);
repeatEventList = allValidEventsSnapshot.getValidRepeatableEventsSnapshot().toObjects(Event.class);
eventList.addAll(nonRepeatEventList);
eventList.addAll(repeatEventList);
Log.d(TAG, "EVENTLIST: " + eventList.toString());
}
}
});
以下是通过Transformations.map进行观察的结果:
viewModel.getAllValidEventsLiveData().observe(this, new Observer<List<Event>>() {
@Override
public void onChanged(@Nullable List<Event> eventList) {
if (eventList != null) {
Log.d(TAG, "EventList: " + eventList.toString());
}
}
});
代码如下:
ViewModel.java
private static final String TAG = "ViewModel";
private FirebaseRepository repository = new FirebaseRepository(getApplication());
public ViewModel(@NonNull Application application) {
super(application);
}
/*
*
* Selected Device Events Live Data
*
*/
private FirebaseQueryLiveData selectedDeviceEventsLiveData = new FirebaseQueryLiveData(repository.getSelectedDeviceEventsQuery());
@NonNull
public FirebaseQueryLiveData getSelectedDeviceEventsLiveData() {
return selectedDeviceEventsLiveData;
}
/*
*
* Selected device nonRepeat valid events Live Data
*
*/
private FirebaseQueryLiveData validNonRepeatEventsLiveData = new FirebaseQueryLiveData(repository.getValidNonRepeatEventsQuery());
@NonNull
public FirebaseQueryLiveData getValidNonRepeatEventsLiveData() {
return validNonRepeatEventsLiveData;
}
/*
*
* MediatorLiveData that merges all valid events (repeatable and nonRepeatable)
*
*/
//MediatorLiveData method that merges all valid repeatable and nonRepeatable liveData
//into a eventList of Event Objects
private MediatorLiveData<AllValidEventsSnapshot> allValidEventsLiveDataMerger() {
final MediatorLiveData<AllValidEventsSnapshot> mediatorLiveData = new MediatorLiveData<>();
final AllValidEventsSnapshot current = new AllValidEventsSnapshot();
mediatorLiveData.addSource(validRepeatEventsLiveData, new Observer<QuerySnapshot>() {
@Override
public void onChanged(@Nullable QuerySnapshot querySnapshot) {
current.setValidRepeatableEventsSnapshot(querySnapshot);
mediatorLiveData.setValue(current);
}
});
mediatorLiveData.addSource(validNonRepeatEventsLiveData, new Observer<QuerySnapshot>() {
@Override
public void onChanged(@Nullable QuerySnapshot querySnapshot) {
current.setValidNonRepeatableEventsSnapshot(querySnapshot);
mediatorLiveData.setValue(current);
}
});
return mediatorLiveData;
}
//Accessor method to get the result of the mediatorMerge
public MediatorLiveData<AllValidEventsSnapshot> getAllValidEventsLiveDataMerger() {
return allValidEventsLiveDataMerger();
}
/*
*
* Transforming the MediatorLiveData that merges repeatable and nonRepeatable valid events
* into one combined eventList
*
*/
//live data that transforms our MediatorLiveData repeatable and nonRepeatable eventList
private final LiveData<List<Event>> allValidEventsLiveData =
Transformations.map(allValidEventsLiveDataMerger(), new GetAllValidEvents());
//sub-class that implements Function to convert our two valid eventLists into one
private class GetAllValidEvents implements Function<AllValidEventsSnapshot, List<Event>> {
@Override
public List<Event> apply(AllValidEventsSnapshot input) {
List<Event> eventList = new ArrayList<>();
if (input != null && input.isComplete()) {
List<Event> repeatEventList = input.getValidRepeatableEventsSnapshot().toObjects(Event.class);
List<Event> nonRepeatEventList = input.getValidNonRepeatableEventsSnapshot().toObjects(Event.class);
//merge valid repeat and nonRepeatable event lists
eventList.addAll(repeatEventList);
eventList.addAll(nonRepeatEventList);
}
return eventList;
}
}
//accessor method to get our transformed users/devices/admin live data into the NavDrawer object
public LiveData<List<Event>> getAllValidEventsLiveData() {
return allValidEventsLiveData;
}
查询:
//getValidNonRepeatEvents query using FirebaseQueryLiveData class
public Query getValidNonRepeatEventsQuery () {
query = FirebaseFirestore.getInstance()
.collection("devices")
.document(docID)
.collection("events")
.whereGreaterThanOrEqualTo("eventDate", firstDayThisWeekObj);
return query;
}
//getValidRepeatEvents query using FirebaseQueryLiveData class
public Query getValidRepeatEventsQuery () {
query = FirebaseFirestore.getInstance()
.collection("devices")
.document(docID)
.collection("events")
.whereEqualTo("repeats", true);
return query;
}
AllValidEventsSnapshot.java对象类
public class AllValidEventsSnapshot {
private QuerySnapshot validRepeatableEventsSnapshot;
private QuerySnapshot validNonRepeatableEventsSnapshot;
//default constructor
public AllValidEventsSnapshot() {
}
public QuerySnapshot getValidRepeatableEventsSnapshot() {
return validRepeatableEventsSnapshot;
}
public void setValidRepeatableEventsSnapshot(QuerySnapshot validRepeatableEventsSnapshot) {
this.validRepeatableEventsSnapshot = validRepeatableEventsSnapshot;
}
public QuerySnapshot getValidNonRepeatableEventsSnapshot() {
return validNonRepeatableEventsSnapshot;
}
public void setValidNonRepeatableEventsSnapshot(QuerySnapshot validNonRepeatableEventsSnapshot) {
this.validNonRepeatableEventsSnapshot = validNonRepeatableEventsSnapshot;
}
public boolean isComplete() {
return (validRepeatableEventsSnapshot != null && validNonRepeatableEventsSnapshot != null);
}
}
FirebaseQueryLiveData.java
public class FirebaseQueryLiveData extends LiveData<QuerySnapshot> {
public static final String TAG = "FbaseQueryLiveData";
private Query query;
private final MyValueEventListener listener = new MyValueEventListener();
private ListenerRegistration listenerRegistration;
private boolean listenerRemovePending = false;
private final Handler handler = new Handler();
public FirebaseQueryLiveData(Query query) {
this.query = query;
}
private final Runnable removeListener = new Runnable() {
@Override
public void run() {
listenerRegistration.remove();
listenerRemovePending = false;
}
};
@Override
protected void onActive() {
super.onActive();
Log.d(TAG, "onActive");
if (listenerRemovePending) {
handler.removeCallbacks(removeListener);
}
else {
listenerRegistration = query.addSnapshotListener(listener);
}
listenerRemovePending = false;
}
@Override
protected void onInactive() {
super.onInactive();
Log.d(TAG, "onInactive: ");
// Listener removal is schedule on a two second delay
handler.postDelayed(removeListener, 2000);
listenerRemovePending = true;
}
private class MyValueEventListener implements EventListener<QuerySnapshot> {
@Override
public void onEvent(@Nullable QuerySnapshot querySnapshot, @Nullable FirebaseFirestoreException e) {
if (e != null){
Log.e(TAG, "Can't listen to query snapshots: " + querySnapshot + ":::" + e.getMessage());
return;
}
setValue(querySnapshot);
}
}
}
以下是我得到的traceStack错误:
2018-12-16 14:29:15.238 27558-27558/com.vuedeu.vuedeu E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.vuedeu.vuedeu, PID: 27558
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.vuedeu.vuedeu/activities.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class viewModels.ViewModel
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
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)
Caused by: java.lang.RuntimeException: Cannot create an instance of class viewModels.ViewModel
at android.arch.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:207)
at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:134)
at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:102)
at activities.MainActivity.onCreate(MainActivity.java:193)
at android.app.Activity.performCreate(Activity.java:6679)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
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)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:430)
at android.arch.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:199)
at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:134)
at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:102)
at activities.MainActivity.onCreate(MainActivity.java:193)
at android.app.Activity.performCreate(Activity.java:6679)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
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)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Object.equals(java.lang.Object)' on a null object reference
at android.arch.core.internal.SafeIterableMap.get(SafeIterableMap.java:47)
at android.arch.core.internal.SafeIterableMap.putIfAbsent(SafeIterableMap.java:65)
at android.arch.lifecycle.MediatorLiveData.addSource(MediatorLiveData.java:87)
at viewModels.ViewModel.allValidEventsLiveDataMerger(ViewModel.java:102)
at viewModels.ViewModel.<init>(ViewModel.java:126)
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:430)
at android.arch.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:199)
at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:134)
at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:102)
at activities.MainActivity.onCreate(MainActivity.java:193)
at android.app.Activity.performCreate(Activity.java:6679)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
任何帮助解决此问题的方法将不胜感激!
谢谢!
答案 0 :(得分:2)
解决了!看来是由于我的queryLiveData方法放在Transformations.map方法之后而引起了空指针异常。在上面的示例中,为了清楚起见,我将queryLiveData方法放在Transformations.map上方(删除了流程中不相关的方法),但没有意识到我将这些方法放在了不同的顺序中。
因此,总而言之:上面的代码可以正常工作。我只需要将queryLiveData方法放在Transforms.map方法之上(上面实际上已显示)。关于顺序的奇怪之处在于,mediatorLiveData似乎并不关心顺序,而Transformations.map确实关心。