【问题标题】:ViewModel observer method returns nullViewModel 观察者方法返回 null
【发布时间】:2018-11-07 05:34:22
【问题描述】:

我收到以下错误

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 类:

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列表等操作时)

【问题讨论】:

    标签: android viewmodel android-livedata


    【解决方案1】:

    您在实现这些方法时没有考虑异步代码,最终得到一个 null LiveData,您在该代码上调用 observe() 并抛出异常。您当前使用的流程:

    • 使用未知过滤器调用 getUpcomingReleases()
    • 此过滤器不在地图中,因此您调用 loadReleases()
    • loadReleases() 只是为后台操作(firebase)设置一个监听器并立即返回
    • 您到达 returncomingcomingReleasesListMap.get(filter); 行,这将返回 null,因为 firebase 侦听器很可能没有完成,并且您没有在地图中为该过滤器添加任何内容价值
    • 使用 null 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);                
            }
        });
    }
    

    【讨论】:

    • 你是MVP。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多