Проблемы с вызовом notifyDataSetChange в RecyclerViewHolder - PullRequest
0 голосов
/ 24 апреля 2018

У меня проблемы с обновлением моего RecyclerView новыми данными.Если я нажму кнопку подтверждения на CardView на первой вкладке, карта будет добавлена ​​на вторую вкладку, но она не будет обновлять ее, пока я не поверну экран.Я получаю данные для карты от чтения текстового файла.Посоветуйте, пожалуйста, как вызвать метод notifyDataSetChange после того, как я добавил новые данные в свой текстовый файл.Я перепробовал все, и все, что я получаю, это NullPointerExceptions.RecyclerViews фрагментированы, и я использую FragementStatePagerAdapter.

Я поместу некоторые из моих классов здесь.Спросите, нужна ли вам дополнительная информация.

RecyclerViewAdapter.java

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
    private List<String> mListTitle;
    private List<String> mListDesc;
    private List<String> mListPoints;
    private List<String> mListDates;
    private String fragment_tag;

    public RecyclerViewAdapter() {
    }

    public RecyclerViewAdapter(List<List<String>> super_list, String tag) {
        this.mListTitle = super_list.get(0);
        this.mListDesc = super_list.get(1);
        this.mListPoints = super_list.get(2);
        this.mListDates = super_list.get(3);
        fragment_tag = tag;
    }

    @Override
    public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        return new RecyclerViewHolder(inflater, parent, fragment_tag);


    }

    @Override
    public void onBindViewHolder(RecyclerViewHolder holder, int position) {
        holder.mTitleText.setText(mListTitle.get(position));
        holder.mDescText.setText(mListDesc.get(position));
        holder.mPointsText.setText(mListPoints.get(position));
        if (fragment_tag.equals("completed")) {
            holder.mDateText.setText(mListDates.get(position));
        }

    }

    @Override
    public int getItemCount() {
        return mListTitle.size();
    }


}

class RecyclerViewHolder extends RecyclerView.ViewHolder {
    RecyclerView recyclerView;
    RecyclerViewAdapter mAdapter;
    public TextView mTitleText, mDescText, mDateText, mPointsText, popupTitle;
    public Button mConfButton, popCancelBtn, popAcceptBtn;

    public RecyclerViewHolder(View itemView) {
        super(itemView);
    }

    public RecyclerViewHolder(final LayoutInflater inflater, final ViewGroup container, String tag) {
        // Inflating the card layout depending on the tag parameter.
        super(inflater.inflate
                ((tag.equals("challenges")) ? R.layout.card_view_chall : R.layout.card_view_comp, container,
                        false));
        mTitleText = itemView.findViewById(R.id.title_holder);
        mDescText = itemView.findViewById(R.id.desc_holder);
        mPointsText = itemView.findViewById(R.id.points_holder);
        mDateText = itemView.findViewById(R.id.date_holder);


        if (tag.equals("challenges")) {
            mConfButton = itemView.findViewById(R.id.card_conf_button);

            mConfButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // Setting the layout inflater for popup window.
                    LayoutInflater pInflater = (LayoutInflater) itemView.getContext().getSystemService(LAYOUT_INFLATER_SERVICE);
                    ViewGroup container1 = (ViewGroup) pInflater.inflate(R.layout.confirmation_popup, null);
                    final PopupWindow popupWindow = new PopupWindow(container1, 700, 600, true);

                    popupTitle = container1.findViewById(R.id.popuptext);
                    popAcceptBtn = container1.findViewById(R.id.accept_button);
                    popCancelBtn = container1.findViewById(R.id.cancel_button);
                    popupTitle.setText(mTitleText.getText().toString());

                    // Dismisses the popup window
                    popCancelBtn.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            popupWindow.dismiss();
                        }
                    });

                    // Click listener for dialog accept button.
                    popAcceptBtn.setOnClickListener(new View.OnClickListener() {
                        String date;

                        @Override
                        public void onClick(View view) {
                            List<String> list = new ArrayList<>();
                            list.add(mTitleText.getText().toString());
                            list.add(mDescText.getText().toString());
                            list.add(mPointsText.getText().toString());
                            list.add(date = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date()));
                            // Saving data from current card into the completed challenges list.
                            TempDataReader reader = new TempDataReader(itemView.getContext());
                            new TempDataReader(itemView.getContext()).saveFile(list);
                            // I want to notify the dataset change here if possible!

                            popupWindow.dismiss();
                        }
                    });
                    popupWindow.showAtLocation(itemView, Gravity.CENTER, 25, 100);
                }
            });

        }

    }
}

SectionsPagerAdapter.java

public class SectionsPagerAdapter extends FragmentStatePagerAdapter{
    private ViewPager viewPager;
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();



    public void addFragment(Fragment fragment, String title){
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    public SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }


    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }

    @Override
    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();


    }
}

CompletedFragment.java

public class CompletedFragment extends Fragment {
    RecyclerView recyclerView;
    RecyclerViewAdapter adapter;
    public Fragment newInstance() {
        return new CompletedFragment();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.completed_fragment, container, false);
        recyclerView = view.findViewById(R.id.completed_frag);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        TempDataReader reader = new TempDataReader(getActivity());
        List<List<String>> super_list = reader.readCompFile();

        if(super_list == null || super_list.size() < 1){
            return null;
        } else{
            adapter = new RecyclerViewAdapter(super_list,"completed");
            recyclerView.setAdapter(adapter);
            return view;
        }
    }
}

РЕДАКТИРОВАТЬ:
Добавлен код для второго фрагмента, который должен быть обновлен после onClick в RecyclerViewHolder-class.

Ответы [ 2 ]

0 голосов
/ 24 апреля 2018

Вы можете создать интерфейс и использовать в качестве обратного вызова.Отправьте его в качестве параметра RecyclerViewAdapter, а затем в свой RecyclerViewHolder.Когда элемент должен быть добавлен, вы вызываете функцию обратного вызова, которая вернет вас к вашему фрагменту.Там вы можете снова прочитать файл и вызвать notifyDataSetChanged.

Я знаю, что объясняю довольно плохо, поэтому я попытаюсь изменить ваш код так, чтобы он делал то, что я сказал:

это будет ваш RecyclerViewAdapter:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
    private List<String> mListTitle;
    private List<String> mListDesc;
    private List<String> mListPoints;
    private List<String> mListDates;
    private String fragment_tag;

    private Runnable callback;

    public RecyclerViewAdapter() {
    }

    public RecyclerViewAdapter(List<List<String>> super_list, String tag, Runnable callBack) { 
//add the callback here(Runnable) and save it into a local variable

        this.callback=callback;

        this.mListTitle = super_list.get(0);
        this.mListDesc = super_list.get(1);
        this.mListPoints = super_list.get(2);
        this.mListDates = super_list.get(3);
        fragment_tag = tag;
    }

    @Override
    public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        return new RecyclerViewHolder(inflater, parent, fragment_tag, callback);
//send the callback to your viewHolder


    }

    @Override
    public void onBindViewHolder(RecyclerViewHolder holder, int position) {
        holder.mTitleText.setText(mListTitle.get(position));
        holder.mDescText.setText(mListDesc.get(position));
        holder.mPointsText.setText(mListPoints.get(position));
        if (fragment_tag.equals("completed")) {
            holder.mDateText.setText(mListDates.get(position));
        }

    }

    @Override
    public int getItemCount() {
        return mListTitle.size();
    }


}

class RecyclerViewHolder extends RecyclerView.ViewHolder {
    RecyclerView recyclerView;
    RecyclerViewAdapter mAdapter;
    public TextView mTitleText, mDescText, mDateText, mPointsText, popupTitle;
    public Button mConfButton, popCancelBtn, popAcceptBtn;

    public RecyclerViewHolder(View itemView) {
        super(itemView);
    }

    public RecyclerViewHolder(final LayoutInflater inflater, final ViewGroup container, String tag, Runnable callback) {
//ADD the callback to the parameters list here

        // Inflating the card layout depending on the tag parameter.
        super(inflater.inflate
                ((tag.equals("challenges")) ? R.layout.card_view_chall : R.layout.card_view_comp, container,
                        false));
        mTitleText = itemView.findViewById(R.id.title_holder);
        mDescText = itemView.findViewById(R.id.desc_holder);
        mPointsText = itemView.findViewById(R.id.points_holder);
        mDateText = itemView.findViewById(R.id.date_holder);


        if (tag.equals("challenges")) {
            mConfButton = itemView.findViewById(R.id.card_conf_button);

            mConfButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // Setting the layout inflater for popup window.
                    LayoutInflater pInflater = (LayoutInflater) itemView.getContext().getSystemService(LAYOUT_INFLATER_SERVICE);
                    ViewGroup container1 = (ViewGroup) pInflater.inflate(R.layout.confirmation_popup, null);
                    final PopupWindow popupWindow = new PopupWindow(container1, 700, 600, true);

                    popupTitle = container1.findViewById(R.id.popuptext);
                    popAcceptBtn = container1.findViewById(R.id.accept_button);
                    popCancelBtn = container1.findViewById(R.id.cancel_button);
                    popupTitle.setText(mTitleText.getText().toString());

                    // Dismisses the popup window
                    popCancelBtn.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            popupWindow.dismiss();
                        }
                    });

                    // Click listener for dialog accept button.
                    popAcceptBtn.setOnClickListener(new View.OnClickListener() {
                        String date;

                        @Override
                        public void onClick(View view) {
                            List<String> list = new ArrayList<>();
                            list.add(mTitleText.getText().toString());
                            list.add(mDescText.getText().toString());
                            list.add(mPointsText.getText().toString());
                            list.add(date = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date()));
                            // Saving data from current card into the completed challenges list.
                            TempDataReader reader = new TempDataReader(itemView.getContext());
                            new TempDataReader(itemView.getContext()).saveFile(list);
                            // I want to notify the dataset change here if possible!
//call the callback
callback.run();

                            popupWindow.dismiss();
                        }
                    });
                    popupWindow.showAtLocation(itemView, Gravity.CENTER, 25, 100);
                }
            });

        }

    }
}

И это будет ваш фрагмент:

public class CompletedFragment extends Fragment {
    RecyclerView recyclerView;
    RecyclerViewAdapter adapter;
    public Fragment newInstance() {
        return new CompletedFragment();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.completed_fragment, container, false);
        recyclerView = view.findViewById(R.id.completed_frag);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        TempDataReader reader = new TempDataReader(getActivity());
        List<List<String>> super_list = reader.readCompFile();

        if(super_list == null || super_list.size() < 1){
            return null;
        } else{
            adapter = new RecyclerViewAdapter(super_list,"completed", new Runnable() {
        @Override
        public void run() {
            //here read the list again and call notifyDataSetChanged on your recycler
        }
    });
);
            recyclerView.setAdapter(adapter);
            return view;
        }
    }
}

Надеюсь, это поможет, и это работает для вас.Если я сделал что-то не так, дайте мне знать, я не могу запустить код прямо сейчас, так что ...

отредактировано, я забыл добавить код в обратный вызов

0 голосов
/ 24 апреля 2018

Вам необходимо добавить функцию в свой адаптер для добавления данных:

public void addData(String title, String desc, String point, String date) {
    this.mListTitle.add(title);
    this.mListDesc.add(desc);
    this.mListPoints.add(point);
    this.mListDates.add(date);

    notifyDataSetChanged();
}

Если вы хотите включить анимацию, звоните notifyItemInserted() вместо notifyDataSetChanged();

Важно, чтобывы добавляете String в каждый список, потому что в вашем onBindViewHolder() вы получаете элемент для отображения из каждого списка с list.get(position).В противном случае вы получите IndexOutOfBoundsException.

...