ViewModel 观察者方法 returns 空
ViewModel observer method returns null
我收到以下错误
Attempt to invoke virtual method 'void android.arch.lifecycle.LiveData.observe on a null object reference
来自我的主要片段中的以下代码部分
mReleasesViewModel = ViewModelProviders.of(this).get(ReleasesViewModel.class);
mReleasesViewModel.getUpcomingReleases(filter).observe(this, new Observer<List<_Release>>() {
@Override
public void onChanged(@Nullable List<_Release> releases) {
// whenever the list is changed
if (releases != null) {
mUpcomingGamesAdapter.setData(releases);
mUpcomingGamesAdapter.notifyDataSetChanged();
}
mDatabaseLoading.setVisibility(View.GONE);
}
});
错误专门抛在这一行(当我附加观察者时)
mReleasesViewModel.getUpcomingReleases(filter) ...
我的 ViewModel class:
public class ReleasesViewModel extends ViewModel {
// fragment name and list
private HashMap<String, MutableLiveData<List<_Release>>> upcomingReleasesListMap = new HashMap<>();
private ReleasesRepository releasesRepository;
private ArrayList<Integer> platforms;
private String region;
public ReleasesViewModel() {
// Shared to all fragments : User settings region & platforms
region = SharedPrefManager.read(SharedPrefManager.KEY_PREF_REGION, "North America");
Set<String> defaultPlatformsSet = new HashSet<>();
platforms = SharedPrefManager.read(SharedPrefManager.PLATFORM_IDS, defaultPlatformsSet);
}
public MutableLiveData<List<_Release>> getUpcomingReleases(String filter) {
// ReleasesRepository takes a different monthly filter
releasesRepository = new ReleasesRepository(region, filter, platforms);
if (upcomingReleasesListMap.containsKey(filter)) {
// Double check if it isn't null, just in case
if (upcomingReleasesListMap.get(filter) == null) {
// if null; try again to send a new request
loadReleases(filter);
} // else just don't do anything, the list is already in the Map
} else {
// Load it in if this filter was never added to the map [New filter and new list]
loadReleases(filter);
}
return upcomingReleasesListMap.get(filter);
}
private void loadReleases(final String filter) {
releasesRepository.addListener(new FirebaseDatabaseRepository.FirebaseDatabaseRepositoryCallback<_Release>() {
@Override
public void onSuccess(List<_Release> result) {
// sort by release date
if (platforms.size() > 1) {
// Will only sort for multiple platforms filter
Collections.sort(result);
}
MutableLiveData<List<_Release>> releases = new MutableLiveData<>();
releases.setValue(result);
upcomingReleasesListMap.put(filter, releases);
}
@Override
public void onError(Exception e) {
// Log.e(TAG, e.getMessage());
MutableLiveData<List<_Release>> releases = new MutableLiveData<>();
releases.setValue(null);
upcomingReleasesListMap.put(filter, releases);
}
});
}
}
Hashmap 是我如何向片段提供数据的不可或缺的一部分。由于我现在在我的应用程序中维护 6 个片段,我需要为所有六个片段使用一个 ViewModel。每个片段都有一个包含相同类型数据(对象和视图)的回收视图,但它们对该数据应用不同的过滤器。请查看 ViewModel 中的 String filter
参数,此参数将过滤器应用于数据。当然,我在 ViewModel 中维护所有 6 个片段。因为它们都需要同时更新(当用户完成更改 platforms
列表等操作时)
您有异步代码,在实现这些方法时没有考虑到这些代码,最终得到一个空的 LiveData,您在该代码上调用 observe() 并抛出异常。您目前使用的流程:
- 使用未知过滤器调用 getUpcomingReleases()
- 此过滤器不在地图中,因此您调用 loadReleases()
- loadReleases() 只是为后台操作 (firebase) 和 returns 立即设置监听器
- 你到达 return upcomingReleasesListMap.get(filter); 这行 return null 因为 firebase 侦听器很可能没有' t 完成并且您没有在该过滤器值的映射中放置任何内容
- 使用空 LiveData 并失败
您需要类似下面的代码才能使其正常工作:
public MutableLiveData<List<_Release>> getUpcomingReleases(String filter) {
...
if (upcomingReleasesListMap.get(filter) == null) {
// we don't have a mapping for this filter so create one in the map
MutableLiveData<List<_Release>> releases = new MutableLiveData<>();
upcomingReleasesListMap.put(filter, releases);
// also call this method to update the LiveData
loadReleases(filter);
}
// for now just return the empty LiveData so our ui can use it
// when the firebase listener returns we will update it
return upcomingReleasesListMap.get(filter);
}
private void loadReleases(final String filter) {
releasesRepository.addListener(new FirebaseDatabaseRepository.FirebaseDatabaseRepositoryCallback<_Release>() {
@Override
public void onSuccess(List<_Release> result) {
// sort by release date
if (platforms.size() > 1) {
// Will only sort for multiple platforms filter
Collections.sort(result);
}
// just use the previous created LiveData, this time with the data we got
MutableLiveData<List<_Release>> releases = upcomingReleasesListMap.get(filter);
releases.setValue(result);
}
@Override
public void onError(Exception e) {
// Log.e(TAG, e.getMessage());
MutableLiveData<List<_Release>> releases = upcomingReleasesListMap.get(filter);
releases.setValue(null);
}
});
}
我收到以下错误
Attempt to invoke virtual method 'void android.arch.lifecycle.LiveData.observe on a null object reference
来自我的主要片段中的以下代码部分
mReleasesViewModel = ViewModelProviders.of(this).get(ReleasesViewModel.class);
mReleasesViewModel.getUpcomingReleases(filter).observe(this, new Observer<List<_Release>>() {
@Override
public void onChanged(@Nullable List<_Release> releases) {
// whenever the list is changed
if (releases != null) {
mUpcomingGamesAdapter.setData(releases);
mUpcomingGamesAdapter.notifyDataSetChanged();
}
mDatabaseLoading.setVisibility(View.GONE);
}
});
错误专门抛在这一行(当我附加观察者时)
mReleasesViewModel.getUpcomingReleases(filter) ...
我的 ViewModel class:
public class ReleasesViewModel extends ViewModel {
// fragment name and list
private HashMap<String, MutableLiveData<List<_Release>>> upcomingReleasesListMap = new HashMap<>();
private ReleasesRepository releasesRepository;
private ArrayList<Integer> platforms;
private String region;
public ReleasesViewModel() {
// Shared to all fragments : User settings region & platforms
region = SharedPrefManager.read(SharedPrefManager.KEY_PREF_REGION, "North America");
Set<String> defaultPlatformsSet = new HashSet<>();
platforms = SharedPrefManager.read(SharedPrefManager.PLATFORM_IDS, defaultPlatformsSet);
}
public MutableLiveData<List<_Release>> getUpcomingReleases(String filter) {
// ReleasesRepository takes a different monthly filter
releasesRepository = new ReleasesRepository(region, filter, platforms);
if (upcomingReleasesListMap.containsKey(filter)) {
// Double check if it isn't null, just in case
if (upcomingReleasesListMap.get(filter) == null) {
// if null; try again to send a new request
loadReleases(filter);
} // else just don't do anything, the list is already in the Map
} else {
// Load it in if this filter was never added to the map [New filter and new list]
loadReleases(filter);
}
return upcomingReleasesListMap.get(filter);
}
private void loadReleases(final String filter) {
releasesRepository.addListener(new FirebaseDatabaseRepository.FirebaseDatabaseRepositoryCallback<_Release>() {
@Override
public void onSuccess(List<_Release> result) {
// sort by release date
if (platforms.size() > 1) {
// Will only sort for multiple platforms filter
Collections.sort(result);
}
MutableLiveData<List<_Release>> releases = new MutableLiveData<>();
releases.setValue(result);
upcomingReleasesListMap.put(filter, releases);
}
@Override
public void onError(Exception e) {
// Log.e(TAG, e.getMessage());
MutableLiveData<List<_Release>> releases = new MutableLiveData<>();
releases.setValue(null);
upcomingReleasesListMap.put(filter, releases);
}
});
}
}
Hashmap 是我如何向片段提供数据的不可或缺的一部分。由于我现在在我的应用程序中维护 6 个片段,我需要为所有六个片段使用一个 ViewModel。每个片段都有一个包含相同类型数据(对象和视图)的回收视图,但它们对该数据应用不同的过滤器。请查看 ViewModel 中的 String filter
参数,此参数将过滤器应用于数据。当然,我在 ViewModel 中维护所有 6 个片段。因为它们都需要同时更新(当用户完成更改 platforms
列表等操作时)
您有异步代码,在实现这些方法时没有考虑到这些代码,最终得到一个空的 LiveData,您在该代码上调用 observe() 并抛出异常。您目前使用的流程:
- 使用未知过滤器调用 getUpcomingReleases()
- 此过滤器不在地图中,因此您调用 loadReleases()
- loadReleases() 只是为后台操作 (firebase) 和 returns 立即设置监听器
- 你到达 return upcomingReleasesListMap.get(filter); 这行 return null 因为 firebase 侦听器很可能没有' t 完成并且您没有在该过滤器值的映射中放置任何内容
- 使用空 LiveData 并失败
您需要类似下面的代码才能使其正常工作:
public MutableLiveData<List<_Release>> getUpcomingReleases(String filter) {
...
if (upcomingReleasesListMap.get(filter) == null) {
// we don't have a mapping for this filter so create one in the map
MutableLiveData<List<_Release>> releases = new MutableLiveData<>();
upcomingReleasesListMap.put(filter, releases);
// also call this method to update the LiveData
loadReleases(filter);
}
// for now just return the empty LiveData so our ui can use it
// when the firebase listener returns we will update it
return upcomingReleasesListMap.get(filter);
}
private void loadReleases(final String filter) {
releasesRepository.addListener(new FirebaseDatabaseRepository.FirebaseDatabaseRepositoryCallback<_Release>() {
@Override
public void onSuccess(List<_Release> result) {
// sort by release date
if (platforms.size() > 1) {
// Will only sort for multiple platforms filter
Collections.sort(result);
}
// just use the previous created LiveData, this time with the data we got
MutableLiveData<List<_Release>> releases = upcomingReleasesListMap.get(filter);
releases.setValue(result);
}
@Override
public void onError(Exception e) {
// Log.e(TAG, e.getMessage());
MutableLiveData<List<_Release>> releases = upcomingReleasesListMap.get(filter);
releases.setValue(null);
}
});
}