Search code examples
javaandroidandroid-recyclerviewandroid-viewpager2

Update recyclerview data


since several days I try to handle data in recyclerview in viewpager2. The viewpager has an adapter managing the data in recyclerview. But everything I try to do seems to not work. Maybe I missundersteand the purpose or something. I hope you can help me.

This activity manages the viewpager and its adapter. It sends the data to the inner recyclerview:

public class AudioFilePanel extends AppCompatActivity
{
    private String currentTab;
    private ViewPagerAdapter adapter;
    private ViewPager2 viewPager;
    private TabLayout tabLayout;
    private Map<String, List<String>> content;

    private String path;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_audio_file_panel);

        viewPager = findViewById(R.id.view_pager2);
        tabLayout = findViewById(R.id.tabs);
        Button addFilesByTag = findViewById(R.id.add_files_with_tag);

        if (null == currentTab)
        {
            currentTab = "music";
        }

        content = listByTag();

        adapter = new ViewPagerAdapter(getApplicationContext(), new ArrayList<>(content.values()));
        viewPager.setAdapter(adapter);
        new TabLayoutMediator(tabLayout, viewPager,
            (tab, position) -> tab.setText(content.keySet().toArray()[position].toString())).attach();

        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener()
        {
            @Override
            public void onTabSelected(TabLayout.Tab tab)
            {
                currentTab = tab.getText().toString();
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab)
            {
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab)
            {
            }
        });
        addFilesByTag.setOnClickListener(l ->
        {
            Intent fileBrowser = new Intent(AudioFilePanel.this, FileBrowser.class);
            startActivityForResult(fileBrowser, 1);
        });
    }

    private void updateViweData()
    {
        content = listByTag();
        adapter = new ViewPagerAdapter(getApplicationContext(), new ArrayList<>(content.values()));
        viewPager.setAdapter(adapter);
    }

    private Map<String, List<String>> listByTag()
    {
        Map<String, List<String>> result = new HashMap<>();
        DirectoryDao dao = new DirectoryDao(getApplicationContext());
        String[] categories = {"music", "ambience", "effect"};

        for (String category : categories)
        {
            List<String> directories =
                dao.getDirectoriesForCategory(category).stream().map(Directory::getPath).collect(Collectors.toList());

            result.put(category, directories);
        }
        return result;
    }

This is the view pager adapter. It takes the data directly from the activity and should trigger data update in the inner recyclerview every time when an item will be clicked. See line 118-128:

public class ViewPagerAdapter extends RecyclerView.Adapter<ViewPagerAdapter.ViewHolder>
{

    private List<List<String>> filesListsByCategory;
    private LayoutInflater mInflater;
    private Context ctx;
    private ItemListAdapter adapter;
    private List<String> categoryFiles;

    public ViewPagerAdapter(Context context, List<List<String>> data)
    {
        this.mInflater = LayoutInflater.from(context);
        this.filesListsByCategory = data;
        this.ctx = context;
    }

    @NotNull
    @Override
    public ViewHolder onCreateViewHolder(@NotNull ViewGroup parent, int viewType)
    {
        return new ViewHolder(mInflater.inflate(R.layout.item_viewpager, parent, false));
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position)
    {
        FileBrowserService fbs = new FileBrowserService();
        categoryFiles = filesListsByCategory.get(position);

        adapter = new ItemListAdapter(categoryFiles, new ItemList.OnListFragmentInteractionListener()
        {
            @Override
            public void onListFragmentInteraction(String item)
            {
                categoryFiles = fbs.getFiles(categoryFiles.get(position));
                categoryFiles.add(0, "previous directory");
                updateUi(adapter, holder);
            }
        });
        holder.myView.setAdapter(adapter);
    }

    private void updateUi(ItemListAdapter adapter, ViewHolder holder)
    {
        adapter.notifyDataSetChanged();
        holder.myView.setAdapter(adapter);
    }

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

    class ViewHolder extends RecyclerView.ViewHolder
    {
        RecyclerView myView;
        RelativeLayout relativeLayout;

        ViewHolder(View itemView)
        {
            super(itemView);

            myView = itemView.findViewById(R.id.my_list);
            myView.setLayoutManager(new LinearLayoutManager(ctx));
            relativeLayout = itemView.findViewById(R.id.container);
        }
    }
}

It is the adapter of inner recyclerview. It represents just a list of elements:

public class ItemListAdapter extends RecyclerView.Adapter<ItemListAdapter.ViewHolder>
{
    private List<String> files;
    private final OnListFragmentInteractionListener mListener;

    public ItemListAdapter(List<String> items, OnListFragmentInteractionListener listener)
    {
        files = items;
        mListener = listener;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_item, parent, false));
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position)
    {
        holder.file = files.get(position);
        holder.mContentView.setText(files.get(position));

        holder.mView.setOnClickListener(v ->
        {
            if (null != mListener)
            {
                // Notify the active callbacks interface (the activity, if the
                // fragment is attached to one) that an item has been selected.
                mListener.onListFragmentInteraction(holder.file);

            }
        });
    }

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

    class ViewHolder extends RecyclerView.ViewHolder
    {
        private final View mView;
        private final TextView mContentView;
        private String file;

        private ViewHolder(View view)
        {
            super(view);
            mView = view;
            mContentView = view.findViewById(R.id.content);
        }
    }
}

The last thing is the ItemList fragment.

public class ItemList extends Fragment
{

    // TODO: Customize parameter argument names
    private static final String ARG_COLUMN_COUNT = "column-count";
    // TODO: Customize parameters
    private int mColumnCount = 1;
    private OnListFragmentInteractionListener mListener;

    /**
     * Mandatory empty constructor for the fragment manager to instantiate the fragment (e.g. upon screen orientation
     * changes).
     */
    public ItemList()
    {
    }

    // TODO: Customize parameter initialization
    @SuppressWarnings("unused")
    public static ItemList newInstance(int columnCount)
    {
        ItemList fragment = new ItemList();
        Bundle args = new Bundle();
        args.putInt(ARG_COLUMN_COUNT, columnCount);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onAttach(Context context)
    {
        super.onAttach(context);
        if (context instanceof OnListFragmentInteractionListener)
        {
            mListener = (OnListFragmentInteractionListener) context;
        } else
        {
            throw new RuntimeException(context.toString() + " must implement OnListFragmentInteractionListener");
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        if (getArguments() != null)
        {
            mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View view = inflater.inflate(R.layout.fragment_item_list, container, false);

        if (view instanceof RecyclerView)
        {
            Context context = view.getContext();
            RecyclerView recyclerView = (RecyclerView) view;
            if (mColumnCount <= 1)
            {
                recyclerView.setLayoutManager(new LinearLayoutManager(context));
            } else
            {
                recyclerView.setLayoutManager(new GridLayoutManager(context, mColumnCount));
            }
            recyclerView.setAdapter(new ItemListAdapter(getArguments().getStringArrayList("list"), mListener));
        }
        return view;
    }

    @Override
    public void onDetach()
    {
        super.onDetach();
        mListener = null;
    }

    /**
     * This interface must be implemented by activities that contain this fragment to allow an interaction in this
     * fragment to be communicated to the activity and potentially other fragments contained in that activity.
     * <p/>
     * See the Android Training lesson
     * <a href= "http://developer.android.com/training/basics/fragments/communicating.html"
     * >Communicating with Other Fragments</a> for more information.
     */
    public interface OnListFragmentInteractionListener
    {
        // TODO: Update argument type and name
        void onListFragmentInteraction(String item);
    }
}

When I click, the data won't update. What I would like to have is:

empdy description


Solution

  • This is what you have to do

    add this method into your adapter class

    public void updateData(List<String> filesList, int flag) {
        if (flag == 0) { //append
            for (int i = 0; i < filesList.size(); i++) {
                files.add(messageList.get(i));
                notifyItemInserted(getItemCount());
            }
        } else { //clear all
            files.clear();
            notifyDataSetChanged();
        }
    }
    

    Then whenever you need to update recycle view call like below

    mItemListAdapter.updateData(yourNewListOfItems, 0);
    

    if you need to reset recycle-view call like below

    mItemListAdapter.updateData(null, 1);