【问题标题】:RecyclerView.Adapter return null object reference inside Fragment with viewPagerRecyclerView.Adapter 使用 viewPager 返回 Fragment 内的空对象引用
【发布时间】:2019-02-25 19:06:47
【问题描述】:

我正在尝试使用 mvvm 架构创建具有视图寻呼机的页面。

所以我想做的是通过使用可观察的方法在第一个选项卡的片段中显示 Recycler 视图。

但是当我尝试设置内容是我片段中的适配器时,我得到了

java.lang.NullPointerException: Attempt to invoke virtual method 'void com.xxxx.view.adapter.FoodListAdapter.setFoodList(java.util.List)' on a null object reference 

我的 FragmentStatePagerAdapter 适配器

@Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                Log.d("Food Pager", "get Item");
                FoodListFragment foodListFragment = new FoodListFragment();
                return foodListFragment;
            case 1:
                RestaurantListFragment restaurantListFragment2 = new RestaurantListFragment();
                return restaurantListFragment2;
            case 2:
                RestaurantListFragment restaurantListFragment3 = new RestaurantListFragment();
                return restaurantListFragment3;
            default:
                return null;
        }
    } 

我的活动

private void observeViewModel(final CategoryViewModel categoryViewModel) {
        // Observe Category Data
        categoryViewModel.getCategory().observe(this, new Observer<Category>() {
            @Override
            public void onChanged(@Nullable Category category) {
                // Update UI
                if (category != null) {
                    if (category.foods != null) {
                        startFoodListFragment(category.foods);
                    }
                } else {
                    Log.e(TAG, "Category Data is Null");
                }
            }
        });
    }

    private void startFoodListFragment(List<CategoryQuery.Food> foodList) {
        Log.d("startFoodListFragment", "yolo");
        FoodListFragment foodListFragment = new FoodListFragment();
        foodListFragment.setFoodList(foodList);
    }

所以在我的片段中

@Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        Log.d("Food LIst", "On create VIew");
        View rootView = inflater.inflate(R.layout.fragment_food_list, container, false);

        mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerview_food_list);
        // mLoadingIndicator = (ProgressBar) rootView.findViewById(R.id.food_list_loading_indicator);

        Integer gridColumns = 2;

        Float width = getScreenSize().get("width");

        if (width > 600) {
            gridColumns = 3;
        }

        // Create Pinterest Style RecyclerView
        StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(gridColumns, StaggeredGridLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(layoutManager);

        // Cool. it's Very easy ,but margin on my LinearLayout didn’t seem to work. So here’s a quick fix.
        SpacesItemDecoration decoration = new SpacesItemDecoration(8);
        mRecyclerView.addItemDecoration(decoration);

        mFoodListAdapter = new FoodListAdapter(foodListAdapterOnClickHandler);
        mRecyclerView.setAdapter(mFoodListAdapter);

        return rootView;
    }

@Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (mFoodList != null) {
            mFoodListAdapter.setFoodList(mFoodList);
        }
    }

    public void setFoodList(List<CategoryQuery.Food> foodList) {
        Log.d(TAG, "setFoodlist");
        if (foodList != null) {
            mFoodList = foodList;
            mFoodListAdapter.setFoodList(mFoodList);
            // mFoodListAdapter.notifyDataSetChanged();
        }
    }

这是我的适配器的一部分

public void setFoodList(final List<? extends CategoryQuery.Food> foodList) {
        if (this.foodList == null) {
            this.foodList = foodList;
            notifyItemRangeInserted(0, foodList.size());
        }
    }

这是我得到的相关日志

D/Food Pager: get Item
D/Food LIst: On create VIew
D/startFoodListFragment: yolo
D/Food List Fragment: setFoodlist
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main

然后错误继续

java.lang.NullPointerException: Attempt to invoke virtual method 'void com.xxx.view.adapter.FoodListAdapter.setFoodList(java.util.List)' on a null object reference

所以任何人都知道为什么我在调用FoodListAdapter 时得到空值,即使在我在onCreateView 内部初始化之后?

感谢您的帮助!

【问题讨论】:

    标签: android android-fragments android-recyclerview android-viewpager recyclerview-layout


    【解决方案1】:

    日志告诉我们什么?

    D/食物寻呼机:获取物品

    调用FragmentStatePagerAdapter.getItem(int position) 以显示FoodListFragment。这通常意味着Fragment 将被添加到屏幕上,因此接下来应该调用它的onCreateView()。实际上是这样的:

    D/Food LIst:在创建视图时

    另一方面,我们有一个Observer 来监听数据变化。每次触发时,都会调用startFoodListFragment()

    D/startFoodListFragment: yolo

    在此方法中,FoodListFragment 的新实例将被创建。您尝试通过调用setFoodList() 将新数据传递给它

    D/食物列表片段:setFoodlist

    但是由于这个新实例不会被附加到屏幕上,它的onCreateView() 还没有被调用。所以它的适配器还没有被实例化。这就是应用崩溃的原因:

    D/AndroidRuntime:关闭虚拟机 E/AndroidRuntime: 致命异常: main

    你能做什么?

    您应该将数据传递到FoodListFragment 的正确实例中。或者直接在FoodListFragment 中注册ObserverFragmentActivity 一样是生命周期所有者,所以我认为这种方法最适合您。

    【讨论】:

    • 在这种情况下,如果我想访问正确的FoodListFragment 实例,我该怎么做?
    • @Varis Darasirikul - 例如this post 通过保留所有片段的列表并重用它们来做到这一点。但我真的建议使用自己的 ViewModel 和 Observer 设置 Fragment。这是一种更清洁的方法
    • 谢谢!我已经做到了。通过从活动访问正确的实例,我必须这样做,因为在该活动上我有 1 个端点将部分数据发送到许多小部件。这就是为什么我无法观察 1 个片段内的视图模型。
    • @VarisDarasirikul - 我明白你的意思。当然,可以让 Activity 和 Fragment 都注册一个观察者并监听数据变化。但我并不是真正的建筑大师,所以我不确定什么是最好的。无论如何,很高兴听到你解决了你的问题:)
    【解决方案2】:

    在您的活动中,您有此方法startFoodListFragment(),它创建一个片段并在其上调用setFoodList() 方法,该方法在内部将数据设置为适配器。

    由于适配器实例是在onCreateView() 生命周期方法上创建的,因此在创建对象时不会初始化适配器。所以那时它将为空,这就是它抛出NullPointerException的原因。确保你访问adapter的时候,一定是在onCreateView()方法执行之后,这样你就再也不会得到NPE了!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-17
      • 1970-01-01
      • 2017-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多