How to use ParseObjects with a RecyclerView?

泪湿孤枕 提交于 2020-01-06 04:56:12

问题


I am attempting to pull data from my parse server and display an image and text within a RecyclerView of CardViews. I have encountered a few issues, some of which may not have been corrected appropriately, so please feel free to correct any novice code you find below outside of my two current issues. Finally my two issues are.

  1. The data does not display initially. I have 3 tabs in a ViewPager and I have to swipe over twice in order for it to display. If I'm on tab 1 the data doesn't appear until I swipe to tab 3 and return to tab 1, and vice versa. Because there isn't a tab 4, tab 2 never displays.

  2. The second issue I am currently faced with is that at times the data will not match up. It will have the picture from one row matched with the description from another entity.

Below is my MusicFragment.java

public class MusicFragment extends Fragment {

    private ArrayList<String> titles = new ArrayList<>();
    private ArrayList<Bitmap> bitmaps = new ArrayList<>();
    private ArrayList<String> descriptions = new ArrayList<>();

    private boolean notComplete = true;

    public MusicFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        //  Inflate the layout for this fragment
        RecyclerView musicRecycler = (RecyclerView)inflater.inflate(
                            R.layout.fragment_music, container, false);

        if (notComplete) {
            //  Get the MusicFragImages class as a reference.
            ParseQuery<ParseObject> query = new ParseQuery<>("MusicFragImages");

            query.findInBackground(new FindCallback<ParseObject>() {
                @Override
                public void done(List<ParseObject> objects, ParseException e) {

                    if (e == null) {
                        for (ParseObject object : objects) {
                            String description = (String) object.get("description");
                            ParseFile file = (ParseFile) object.get("image");
                            String title = (String) object.get("title");

                            titles.add(title);
                            descriptions.add(description);

                            file.getDataInBackground(new GetDataCallback() {
                                @Override
                                public void done(byte[] data, ParseException e) {
                                    if (e == null && data != null) {
                                        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                                        bitmaps.add(bitmap);
                                    }
                                }
                            });
                        }
                    } else {
                        Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                }

            });
            notComplete = false;
        }
        //  Create captioned images and registers it to the adapter.
        CaptionedImagesAdapter adapter = new CaptionedImagesAdapter(titles, bitmaps, descriptions);
        musicRecycler.setAdapter(adapter);

        //  Set up the layout.
        GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 1);
        musicRecycler.setLayoutManager(layoutManager);

        adapter.setListener(new CaptionedImagesAdapter.Listener() {
           public void onClick(int position) {
               Intent intent;
               switch (position) {
                   case 0:
                       intent = new Intent(getActivity(), AudioActivity.class);
                       getActivity().startActivity(intent);
                       break;
                   case 1:
                       intent = new Intent(getActivity(), VideoActivity.class);
                       getActivity().startActivity(intent);
                       break;
               }
           }
        });

        return musicRecycler;
    }
}

Additionally, here is my CaptionedImagesAdapter

class CaptionedImagesAdapter extends
    RecyclerView.Adapter<CaptionedImagesAdapter.ViewHolder> {

    private final ArrayList<String> captions;
    private final ArrayList<Bitmap> bitmaps;
    private final ArrayList<String> descriptions;

    private Listener listener;

    interface Listener {
        void onClick(int position);
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {

        private final CardView cardView;

        public ViewHolder(CardView v) {
            super(v);
            cardView = v;
        }
    }

    public CaptionedImagesAdapter(ArrayList<String> captions, ArrayList<Bitmap> bitmaps, ArrayList<String> descriptions) {
        this.captions = captions;
        this.bitmaps = bitmaps;
        this.descriptions = descriptions;
    }

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

    public void setListener(Listener listener) {
        this.listener = listener;
    }
    @Override
    public CaptionedImagesAdapter.ViewHolder onCreateViewHolder(
            ViewGroup parent, int viewType) {
        CardView cv = (CardView) LayoutInflater.from(parent.getContext()).inflate(R.layout.card_selection_2, parent, false);
        return new ViewHolder(cv);
    }
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        final int index = position;

        //  Creates a CardView
        CardView cardView = holder.cardView;

        ImageView imageView = cardView.findViewById(R.id.type_image);
        imageView.setImageBitmap(bitmaps.get(index));

        imageView.setContentDescription(descriptions.get(index));

        //  Populate the caption.
        TextView textView = cardView.findViewById(R.id.type_text);
        textView.setText(captions.get(index));
        cardView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v){
                if (listener != null)
                    listener.onClick(index);
            }
        });
    }
}

FOR REFERENCE...... if needed MainActivity.java is below

    public class MainActivity extends AppCompatActivity {

//  Variables for the audio player.
public static MediaPlayer mediaPlayer;
public static int albumId;
public static int currentSong = -1;
public static boolean isPlaying = false;
private static int[] songs;

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

    Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    //  Attach the SectionsPageAdapter to the ViewPager
    SectionsPageAdapter pagerAdapter = new SectionsPageAdapter(getSupportFragmentManager());
    ViewPager pager = (ViewPager) findViewById(R.id.pager);
    pager.setAdapter(pagerAdapter);
    int currentTab = 0;
    pager.setCurrentItem(currentTab);

    //  Attach the ViewPager to the TabLayout
    TabLayout tabLayout = (TabLayout)findViewById(R.id.tabs);
    tabLayout.setupWithViewPager(pager);

    //  Starts the player.
    player();
}
public boolean onCreateOptionsMenu(Menu menu) {
    //  Inflate the menu; this adds items to the app bar.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    Intent intent;
    switch (item.getItemId()) {
        case R.id.action_contact:
            intent = new Intent(MainActivity.this, ContactActivity.class);
            startActivity(intent);
            return true;
        case R.id.action_cart:
            intent = new Intent(this, CartActivity.class);
            startActivity(intent);
            return true;
        case R.id.action_member:
            intent = new Intent(this, ProfileActivity.class);
            startActivity(intent);
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}
private class SectionsPageAdapter extends FragmentPagerAdapter {

    public SectionsPageAdapter(FragmentManager fm) {
        super(fm);
    }
    @Override
    public int getCount() {
        return 3;
    }
    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                return new MusicFragment();
            case 1:
                return new ArtFragment();
            case 2:
                return new FashionFragment();
        }
        return null;
    }
    @Override
    public CharSequence getPageTitle(int position) {
        switch (position) {
            case 0:
                return getResources().getText(R.string.title_music);
            case 1:
                return getResources().getText(R.string.title_art);
            case 2:
                return getResources().getText(R.string.title_fashion);
        }
        return null;
    }
}
private void player() {

    /*Create a background thread that will automatically advance to
                * the next song, as long as there is a next song.*/

    //  Get the songs.
    songs = AudioData.audio[albumId].getSongs();

    final Handler handler = new Handler();
    handler.post(new Runnable() {
        @Override
        public void run() {
            if (isPlaying) {
                if (!(mediaPlayer.isPlaying()) && currentSong < songs.length - 1) {
                    mediaPlayer.stop();
                    mediaPlayer.reset();
                    currentSong++;
                    mediaPlayer = MediaPlayer.create(MainActivity.this, songs[currentSong]);
                    mediaPlayer.start();
                    isPlaying = true;
                }
                //Set the flag to false at the end of the album.
                if (currentSong == songs.length) {
                    isPlaying = false;
                }
            }
            handler.postDelayed(this, 1000);
        }
    });
}

@Override
public void onBackPressed() {
    super.onBackPressed();
    finishAffinity();
}

}

Thanks again to Harikumar for correcting the first issue. I ended up correcting the second issue with the code below. It was within the enhance for loop.

    for (ParseObject object : objects) {
                        String description = (String) object.get("description");
                        ParseFile file = (ParseFile) object.get("image");
                        String title = (String) object.get("title");
                        Bitmap bitmap;


                        titles.add(title);
                        descriptions.add(description);

                        byte[] data;
                        try {
                            data = file.getData();
                            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                            bitmaps.add(bitmap);
                            adapter.notifyDataSetChanged(); //notify your adapter that data has changed
                        } catch (ParseException pe) {
                            Toast.makeText(getContext(), pe.getMessage(), Toast.LENGTH_SHORT).show();
                        }
                    }

回答1:


Data will be updated if you notify your adapter CaptionedImagesAdapter. Try modifying the code to:

public class MusicFragment extends Fragment {

    private ArrayList<String> titles = new ArrayList<>();
    private ArrayList<Bitmap> bitmaps = new ArrayList<>();
    private ArrayList<String> descriptions = new ArrayList<>();
    private CaptionedImagesAdapter adapter;


    private boolean notComplete = true;

    public MusicFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        //  Inflate the layout for this fragment
        RecyclerView musicRecycler = (RecyclerView)inflater.inflate(
                            R.layout.fragment_music, container, false);


        GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 1);
        musicRecycler.setLayoutManager(layoutManager);

        adapter = new CaptionedImagesAdapter(titles, bitmaps, descriptions);

        musicRecycler.setAdapter(adapter);

        if (notComplete) {
            //  Get the MusicFragImages class as a reference.
            ParseQuery<ParseObject> query = new ParseQuery<>("MusicFragImages");

            query.findInBackground(new FindCallback<ParseObject>() {
                @Override
                public void done(List<ParseObject> objects, ParseException e) {

                    if (e == null) {
                        for (ParseObject object : objects) {
                            String description = (String) object.get("description");
                            ParseFile file = (ParseFile) object.get("image");
                            String title = (String) object.get("title");

                            titles.add(title);
                            descriptions.add(description);

                            file.getDataInBackground(new GetDataCallback() {
                                @Override
                                public void done(byte[] data, ParseException e) {
                                    if (e == null && data != null) {
                                        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                                        bitmaps.add(bitmap);
                                        adapter.notifyDataSetChanged(); //notify your adapter that data has changed
                                    }
                                }
                            });
                        }
                    } else {
                        Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                }

            });
            notComplete = false;
        }


        adapter.setListener(new CaptionedImagesAdapter.Listener() {
           public void onClick(int position) {
               Intent intent;
               switch (position) {
                   case 0:
                       intent = new Intent(getActivity(), AudioActivity.class);
                       getActivity().startActivity(intent);
                       break;
                   case 1:
                       intent = new Intent(getActivity(), VideoActivity.class);
                       getActivity().startActivity(intent);
                       break;
               }
           }
        });

        return musicRecycler;
    }
}

Here is a small optimization for your 2nd solution: update notifyDataSetChanged() only once after the for loop (put it just outside the for loop). This is better in terms of performance.



来源:https://stackoverflow.com/questions/48382872/how-to-use-parseobjects-with-a-recyclerview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!