RecyclerView.Adapter возвращает нулевую ссылку на объект во фрагменте с помощью viewPager - PullRequest
0 голосов
/ 25 февраля 2019

Я пытаюсь создать страницу с пейджером представления с архитектурой 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?

Спасибо за вашу помощь!

Ответы [ 2 ]

0 голосов
/ 25 февраля 2019

Что говорит нам журнал?

D / Food Pager: get Item

FragmentStatePagerAdapter.getItem(int position) был вызван, чтобы показать FoodListFragment.Обычно это означает, что Fragment будет добавлен на экран, поэтому его onCreateView() следует вызывать следующим.На самом деле это так:

D / Food LIst: при создании VIew

С другой стороны, у нас есть Observer для прослушивания изменений данных.При каждом запуске startFoodListFragment() будет вызываться:

D / startFoodListFragment: yolo

В этом методе новый экземпляр FoodListFragment будетбыть созданным .Вы пытаетесь передать в него новые данные, вызывая setFoodList()

D / Food List Fragment: setFoodlist

Но так как этот новый экземпляр не собирается присоединятьсяна экран, его onCreateView() не был вызван.Таким образом, его адаптер не был создан.Вот почему происходит сбой приложения:

D / AndroidRuntime: завершение работы VM E / AndroidRuntime: ИСКЛЮЧИТЕЛЬНОЕ ИСКЛЮЧЕНИЕ: main

Что вы можете сделать?

Вы должны передать данные в правильный экземпляр FoodListFragment.Или просто зарегистрируйте Observer внутри FoodListFragment.Fragment является владельцем жизненного цикла, как и Activity, поэтому я думаю, что этот подход лучше всего подойдет вам.

0 голосов
/ 25 февраля 2019

В вашей деятельности у вас есть метод startFoodListFragment(), который создает фрагмент и вызывает для него метод setFoodList(), который внутренне устанавливает данные для адаптера.

Поскольку экземпляр адаптера создается с использованием метода жизненного цикла onCreateView(), адаптер не будет инициализирован во время создания объекта.поэтому он будет нулевым в то время, поэтому он выбрасывает NullPointerException.Убедитесь, что при доступе к адаптеру он должен быть после выполнения метода onCreateView(), чтобы вы никогда больше не получили NPE!

...