7

I have developed an application in which there are two posts

  • The image post using picasso
  • the Video post using Youtube Api.

I have implemented both by using RecyclerView and Firebase recyclerAdapter but the problem is that I dont know that how to differentiate both views, if I use Video view using Youtube Api it gets attached with image view and also gets copy to all of items in recyclerView, and then there is only one video playing in all items. What I want is that if I want to show an image then the item only gets image and if I want to show video then the reyclerView item only gets video without repetition. Like Instagram. I have searched many forums but did not got any help from them. please help. I am using Firebase as my database and ViewHolders are according to that.

Class file for Image and Video posts:

FirebaseRecyclerAdapter <post, postViewHolder> firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<post, postViewHolder>(
    post.class,
    R.layout.post_row_recycle_home,
    postViewHolder.class,
    mDatabaseReference
) {
    @Override
    protected void populateViewHolder(postViewHolder viewHolder, post model, int position) {
        viewHolder.setimage(getApplicationContext(), model.getImage());
        viewHolder.setYoutube(model.getYoutube()); 
    }
};

mrecyclerView.setAdapter(firebaseRecyclerAdapter);

Holder:

public static class postViewHolder extends RecyclerViewPager.ViewHolder{

    View mView;

    public postViewHolder(View itemView) {
        super(itemView);
        mView = itemView;
    }

    public void setYoutube(final String youtube){
        final YouTubePlayerView youPlay = (YouTubePlayerView) mView.findViewById(R.id.youtuber);
        youPlay.initialize("SOME KEY",
            new YouTubePlayer.OnInitializedListener() {
                @Override
                public void onInitializationSuccess(YouTubePlayer.Provider provider,
                                                    YouTubePlayer youTubePlayer, boolean b) {

                    youTubePlayer.cueVideo(youtube);
                }
                @Override
                public void onInitializationFailure(YouTubePlayer.Provider provider,
                                                    YouTubeInitializationResult youTubeInitializationResult) {

            }
        });
    }

    public void setimage(final Context ctx, final String image){
        final ImageView post_image = (ImageView)mView.findViewById(R.id.post_image);

         Picasso.with(ctx).load(image)
            .networkPolicy(NetworkPolicy.OFFLINE).into(post_image, new Callback() {

            @Override
            public void onSuccess() {
            }
            @Override
            public void onError() {
                Picasso.with(ctx).load(image).into(post_image);
            }
        });
    }
}

Example screenshot:

enter image description here

Nick Cardoso
  • 20,807
  • 14
  • 73
  • 124
Rohit B
  • 165
  • 2
  • 26

3 Answers3

10

You can decide which type of view to show with the adapters getItemViewType method. Inside firebaseRecyclerAdapter add the following:

private static final int TYPE_YOUTUBE = 1111;
private static final int TYPE_IMAGE = 2222;

@Override
public int getItemViewType(int position) {
    //note: classes should start with uppercase
    Post model = getItem(position);
    if (model.isYoutube()) { //note: you'll have to define this method
        return TYPE_YOUTUBE; 
    } else {
        return TYPE_IMAGE;
    }
}

Then inside onCreateViewHolder you check which type to create:

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    RecyclerView.ViewHolder holder;
    switch (viewType) {
        case TYPE_YOUTUBE:
                //note: save an inflater when you construct the adapter
                return new YtViewHolder(inflater.inflate(R.layout.item_youtube, parent, false));
        case TYPE_IMAGE:
                return new ImgViewHolder(inflater.inflate(R.layout.item_image, parent, false));
        }

    }

Separate your VH models:

public abstract class PostViewHolder extends RecyclerView.ViewHolder { //note: extends changed
    public abstract void bind(final String input){
}

public static class YtViewHolder extends PostViewHolder { //note: extends changed

    private YouTubePlayerView mView;

    public YtViewHolder(View itemView) {
        super(itemView);
        mView = (YouTubePlayerView) itemView.findViewById(R.id.youtuber);
    }

    public void bind(final String youtube){
        mView.initialize("SOME KEY",
            new YouTubePlayer.OnInitializedListener() {
                @Override
                public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean b) {
                    youTubePlayer.cueVideo(youtube);
                }

                @Override
                public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {

                }
        });
    }

}

public static class ImgViewHolder extends PostViewHolder {

    private ImageView mView;

    public ImageView(View itemView) {
        super(itemView);
        mView = (ImageView) itemView.findViewById(R.id.post_image);
    }

    public void bind(final String image){
        Picasso.with(mView.getContext()).load(image).networkPolicy(NetworkPolicy.OFFLINE).into(mView, new Callback() {

            @Override
            public void onSuccess() {
            }
            @Override
            public void onError() {
                Picasso.with(ctx).load(image).into(mView);
            }
        });
    }

}

Your populate method can then be simplified as follows:

@Override
protected void populateViewHolder(PostViewHolder viewHolder, post model, int position) {
    viewHolder.bind(model.isYoutube()? model.getYoutube() : model.getImage());
}

Different Items:

then there is only one video playing in all items

This is a bit concerning. If I understand correctly every single item in the list has the same image and video. This probably means you are returning the same model to every position. Make sure that if you implement getItem you return a different item for each position (the Firebase adapter will do this by default). Also make sure that model.getYoutube etc. are not returning static data.

Nick Cardoso
  • 20,807
  • 14
  • 73
  • 124
  • what should be defined in " if (model.isYoutube()) { //note: you'll have to define this method return TYPE_YOUTUBE; " – Rohit B Sep 21 '17 at 14:57
  • And do i have to add getter and setter in post.class for this " Post model = getItem(position);" – Rohit B Sep 21 '17 at 15:02
  • The `isYoutube` method is what you need to define. `getItem` is a method of the adapter. You should study the [RecyclerView](https://developer.android.com/guide/topics/ui/layout/recyclerview.html) basics – Nick Cardoso Sep 21 '17 at 15:39
2

Simply using viewType will solve this issue for you.

First of all FirebaseRecyclerAdapter should include RecyclerView.ViewHolder.class instead of postViewHolder.class

Then you switch between type in each child assume image carry type 1 and video carry type 2 and you achieve that in onCreateViewHolder between you handle that in getItemViewType

Code should be look like:-

protected void populateViewHolder(final RecyclerView.ViewHolder viewHolder, final post model,
                                          final int position) {
            switch (model.getType()) {
                case 1:
                    populateType1((ViewHolder1) viewHolder, model, position);
                    break;
                case 2:
                    populateType2((ViewHolder2) viewHolder, model, position);
                    break;
            }

onCreatView should be look like:-

 @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            switch (viewType) {
                case 1:
                    View modelType1 = LayoutInflater.from(parent.getContext())
                            .inflate(R.layout.item_type1, parent, false);
                    return new ViewHolder1(modelType1);
                case 2:
                    View modelType2 = LayoutInflater.from(parent.getContext())
                            .inflate(R.layout.item_type2, parent, false);
                    return new ViewHolder2(modelType2);
            }
            return super.onCreateViewHolder(parent, viewType);
        }

And getItemViewType

@Override
        public int getItemViewType(int position) {
            post model = getItem(position);
            switch (model.getType()) {
                case 1:
                    return model1;
                case 2:
                    return model2;

            }
            return super.getItemViewType(position);
        }
  • Where would i use load.image and youPlay.cueVideo() ? – Rohit B Sep 17 '17 at 10:37
  • @RohitB all changes should be in `populateViewHolder` case 1 you handle view for image and case 2 you handle view for video. –  Sep 17 '17 at 11:37
  • You've made a few mistakes in this code - for example model1 and model2 aren't defined. Nor are the Viewholder classes you use. By the way there's no reason he can't use a custom view holder (postViewHolder) as you suggest – Nick Cardoso Sep 19 '17 at 07:52
-1

viewHolders with two views

public class MultiViewAdapter extends RecyclerView.Adapter {

private ArrayList dataSet;
Context mContext;
int total_types;


/*
   Image TypeViewHolder
 */
public class ImageTypeViewHolder extends RecyclerView.ViewHolder {

    ImageView img;
    public ImageTypeViewHolder(View itemView) {
        super(itemView);
        this.img = (ImageView) itemView.findViewById(R.id.imageview);


    }
}

/*
    Youtube View Holder
 */
public  class YoutubeTypeViewHolder extends RecyclerView.ViewHolder {



    public YoutubeTypeViewHolder(View itemView) {
        super(itemView);

        // add

    }
}


public MultiViewAdapter(ArrayList data, Context context) {
    this.dataSet = data;
    this.mContext = context;
    total_types = dataSet.size();
}


@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View view;
    switch (viewType) {

        case typeImage:
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.type_image, parent, false);
            return new ImageTypeViewHolder(view);

        case typeVideo:
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.type_video, parent, false);
            return new YoutubeTypeViewHolder(view);
    }
    return null;
}

@Override
public int getItemViewType(int position) {

    switch (position) {

        case 0:
            return typeImage;
        case 1:
            return typeVideo;


    }
}


@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int listPosition) {

    Post object = getItem(listPosition);

    if (object != null) {
        switch (object.type) {

            case typeImage:

                ((ImageTypeViewHolder) holder).image.setImageResource(object.data);
                break;
            case typeVideo:
                // ADD video
                break;

        }
    }
}





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