How to load Youtube thumbnails in a RecyclerView using Youtube API

I'm trying to load Youtube video thumbnails in a RecyclerView. I'm facing some issues.

Here is what I'm doing in my adapter:

public static class ItemViewHolder extends RecyclerView.ViewHolder {

    private YouTubeThumbnailView thumb;
    public  Post                 post;

    public ItemViewHolder(View v) {
        thumb = (YouTubeThumbnailView) v.findViewById(R.id.youtube_thumbnail);
    }

    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
        if (holder instanceof ItemViewHolder) {

            ((ItemViewHolder) holder).thumb.initialize(YOUTUPEKEY, new YouTubeThumbnailView.OnInitializedListener() {
                @Override
                public void onInitializationSuccess(YouTubeThumbnailView youTubeThumbnailView, YouTubeThumbnailLoader youTubeThumbnailLoader) {
                    youTubeThumbnailLoader.setVideo(VIDEOID);

                }

                @Override
                public void onInitializationFailure(YouTubeThumbnailView youTubeThumbnailView, YouTubeInitializationResult youTubeInitializationResult) {

                }});
}}}

It works fine, but I don't I'm doing it right. When I'm using the same adapter in another activity I get this Error:

Activity com.example.yasser.version6.Mespublications has leaked ServiceConnection com.google.android.youtube.player.internal.r$e@4252bcb8 that was originally bound here

and it takes time to load thumbnails and sometimes it mix between them when swiping.

I added a function to release all the Youtube Loaders:

public void ReleaseLoaders() {
    for (YouTubeThumbnailLoader loader : loaders.values()) {
        loader.release();
    }
}

and I'm calling this function from the Activity Onstop() :

@Override
public void onStop() {
    super.onStop();
    mAdapter.ReleaseLoaders();
}

It worked fine for some time, but the crashes sometimes.


You can try this maybe ? It doesnt use the API but its quick.

Load the image in the recycler view with Picasso from this URL:

https://img.youtube.com/vi/"here goes your video id"/default.jpg

-- Edit --

After some research and experiments:

To get the default full size thumbnail do this instead of default.jpg

https://img.youtube.com/vi/"here goes your video id"/0.jpg

Here is the link: http://www.reelseo.com/youtube-thumbnail-image/

Edit 2:

Just found someone in SO already gave an answer like mine with this quick and easy solution and has way more explanation and options you could choose from.

How do I get a YouTube video thumbnail from the YouTube API?


Final Edit:

This is working code. I went in and made an app recently with the api so I found out why you are getting the error. Its because you are not releasing the loader properly.

You can release the loader/loaders in two ways.

First

(Preferred, you will see why in a sec) You would want to release it after the image has been loaded into view and theres a listener for that and its called OnThumbNailLoadedListener. Thats where I released it (if you pay attention to the code below). This means you dont have to deal with this instance anymore. Once thumbnail is loaded youre done.

Second

Since getView() is called all the time there's new instances of YouTubeThumbnailLoader that you have to release. This means you have to store all of these in an ArrayList. You just do an advanced for loop and call release in all of them when activity is onStop();

Now you probably see why the first way is preferred. And I know you did the second option so just letting you know the first option will always be guaranteed to work (at least in my case). I used a YouTubeSupportFragment in an Activity and it worked fine. No issues whatsoever. You can definitely make the second option work but you would have to handle a lot of special cases I think.

final YouTubeThumbnailView youTubeThumbnailView = (YouTubeThumbnailView) convertView.findViewById(R.id.show_episode_thumbnail);
    youTubeThumbnailView.initialize(DeveloperKey.DEVELOPER_KEY, new YouTubeThumbnailView.OnInitializedListener() {
        @Override
        public void onInitializationSuccess(YouTubeThumbnailView youTubeThumbnailView, final YouTubeThumbnailLoader youTubeThumbnailLoader) {
            youTubeThumbnailLoader.setVideo(videoId);
            youTubeThumbnailLoader.setOnThumbnailLoadedListener(new YouTubeThumbnailLoader.OnThumbnailLoadedListener() {
                @Override
                public void onThumbnailLoaded(YouTubeThumbnailView youTubeThumbnailView, String s) {
                    youTubeThumbnailLoader.release();
                }

                @Override
                public void onThumbnailError(YouTubeThumbnailView youTubeThumbnailView, YouTubeThumbnailLoader.ErrorReason errorReason) {

                }
            });
        }

        @Override
        public void onInitializationFailure(YouTubeThumbnailView youTubeThumbnailView, YouTubeInitializationResult youTubeInitializationResult) {

        }
    });

In onBindViewHolder you are trying to initialize the same YoutubeThumbnailView again and again, Instead you can initialize it once when views are created in onCreateViewHolder . By setting video Id as tag to a YoutubeThumbnailView you can prevent mixing(or) wrong loading of thumbnails.


Adapter.

    private class ThumbnailAdapter extends RecyclerView.Adapter{

    private final int UNINITIALIZED = 1;
    private final int INITIALIZING = 2;
    private final int INITIALIZED = 3;
    private int blackColor = Color.parseColor("#FF000000");
    private int transparentColor = Color.parseColor("#00000000");

    public class VideoViewHolder extends RecyclerView.ViewHolder{

        public YouTubeThumbnailView ytThubnailView = null;
        public ImageView ivYtLogo = null;
        public TextView tvTitle = null;

        public VideoViewHolder(View itemView) {
            super(itemView);
            ytThubnailView = (YouTubeThumbnailView) itemView.findViewById(R.id.yt_thumbnail);
            ivYtLogo = (ImageView) itemView.findViewById(R.id.iv_yt_logo);
            tvTitle = (TextView) itemView.findViewById(R.id.tv_title);

            initialize();
        }

        public void initialize(){
            ivYtLogo.setBackgroundColor(blackColor);
            ytThubnailView.setTag(R.id.initialize, INITIALIZING);
            ytThubnailView.setTag(R.id.thumbnailloader, null);
            ytThubnailView.setTag(R.id.videoid, "");

            ytThubnailView.initialize(API_KEY, new YouTubeThumbnailView.OnInitializedListener() {
                @Override
                public void onInitializationSuccess(YouTubeThumbnailView youTubeThumbnailView, YouTubeThumbnailLoader youTubeThumbnailLoader) {
                    ytThubnailView.setTag(R.id.initialize, INITIALIZED);
                    ytThubnailView.setTag(R.id.thumbnailloader, youTubeThumbnailLoader);

                    youTubeThumbnailLoader.setOnThumbnailLoadedListener(new YouTubeThumbnailLoader.OnThumbnailLoadedListener() {
                        @Override
                        public void onThumbnailLoaded(YouTubeThumbnailView youTubeThumbnailView, String loadedVideoId) {
                            String currentVideoId = (String) ytThubnailView.getTag(R.id.videoid);
                            if(currentVideoId.equals(loadedVideoId)) {
                                ivYtLogo.setBackgroundColor(transparentColor);
                            }
                            else{
                                ivYtLogo.setBackgroundColor(blackColor);
                            }
                        }

                        @Override
                        public void onThumbnailError(YouTubeThumbnailView youTubeThumbnailView, YouTubeThumbnailLoader.ErrorReason errorReason) {
                            ivYtLogo.setBackgroundColor(blackColor);
                        }
                    });

                    String videoId = (String) ytThubnailView.getTag(R.id.videoid);
                    if(videoId != null && !videoId.isEmpty()){
                        youTubeThumbnailLoader.setVideo(videoId);
                    }
                }

                @Override
                public void onInitializationFailure(YouTubeThumbnailView youTubeThumbnailView, YouTubeInitializationResult youTubeInitializationResult) {
                    ytThubnailView.setTag(R.id.initialize, UNINITIALIZED);
                    ivYtLogo.setBackgroundColor(blackColor);
                }
            });
        }
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = getLayoutInflater().inflate(R.layout.row_video_item, parent, false);
        VideoViewHolder videoViewHolder = new VideoViewHolder(view);
        return videoViewHolder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        final Entities e = entities.get(position);
        final VideoViewHolder videoViewHolder = (VideoViewHolder) holder;
        videoViewHolder.tvTitle.setText(e.name);
        videoViewHolder.ivYtLogo.setVisibility(View.VISIBLE);
        videoViewHolder.ytThubnailView.setTag(R.id.videoid, e.id);
        videoViewHolder.ivYtLogo.setBackgroundColor(blackColor);

        int state = (int) videoViewHolder.ytThubnailView.getTag(R.id.initialize);

        if(state == UNINITIALIZED){
            videoViewHolder.initialize();
        }
        else if(state == INITIALIZED){
            YouTubeThumbnailLoader loader = (YouTubeThumbnailLoader) videoViewHolder.ytThubnailView.getTag(R.id.thumbnailloader);
            loader.setVideo(e.id);
        }
    }

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

The layout used for each row is.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="200dp">

    <com.google.android.youtube.player.YouTubeThumbnailView
        android:id="@+id/yt_thumbnail"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <ImageView
        android:id="@+id/iv_yt_logo"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="center"
        android:src="@mipmap/youtube_play"
        android:background="#00000000"
        android:layout_centerInParent="true"/>

</RelativeLayout>

<TextView
    android:id="@+id/tv_title"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textColor="#FF000000"
    android:textSize="16sp"
    android:text="Title"/>

<View
    android:id="@+id/seperator"
    android:layout_width="match_parent"
    android:layout_height="2dp"
    android:layout_marginTop="5dp"
    android:layout_marginBottom="5dp"
    android:background="#FF642108"/>

</LinearLayout>

tags.xml.

Location : src/main/res/values/tags.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="initialize" />
<item type="id" name="videoid"/>
<item type="id" name="thumbnailloader"/>
</resources>

在这里输入图像描述


public class VideoAdapter extends RecyclerView.Adapter {

private List<VideoPojo> listvideo;
private VideoPojo videoPojo;
private Context mContext;
private boolean readyForLoadingYoutubeThumbnail = true;
String KEY = "AIzaSyA5kyaLgS7MKxS19uHf2CUsIOmDkv92DGU";

public VideoAdapter(Context context, List<VideoPojo> listvideo) {
    this.listvideo = listvideo;
    this.mContext = context;
    videoPojo = new VideoPojo();
}

@Override
public VideoAdapter.VideoHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.video_layout, parent, false);
    return new VideoHolder(view);
}

@Override
public void onBindViewHolder(final VideoAdapter.VideoHolder holder, final int position) {

    holder.murl.setText(listvideo.get(position).getVideoUrl());
    final String url = listvideo.get(position).getVideoUrl();
    Log.d(TAG, "readyForLoadingYoutubeThumbnail" + readyForLoadingYoutubeThumbnail);
    if (readyForLoadingYoutubeThumbnail) {
        Log.d(TAG, "initializing for youtube thumbnail view...");
        readyForLoadingYoutubeThumbnail = false;
        holder.youTubeThumbnailView.initialize(KEY, new YouTubeThumbnailView.OnInitializedListener() {
            @Override
            public void onInitializationSuccess(final YouTubeThumbnailView youTubeThumbnailView, final YouTubeThumbnailLoader youTubeThumbnailLoader) {

                youTubeThumbnailLoader.setVideo(url);
                youTubeThumbnailLoader.setOnThumbnailLoadedListener(new YouTubeThumbnailLoader.OnThumbnailLoadedListener() {

                    @Override
                    public void onThumbnailLoaded(YouTubeThumbnailView childYouTubeThumbnailView, String s) {
                        holder.loding.setVisibility(View.GONE);
                        youTubeThumbnailLoader.release(); // spy ga memory lick
                    }

                    @Override
                    public void onThumbnailError(YouTubeThumbnailView youTubeThumbnailView, YouTubeThumbnailLoader.ErrorReason errorReason) {
                        youTubeThumbnailLoader.release(); // spy ga memory lick
                    }
                });

                readyForLoadingYoutubeThumbnail = true;
            }

            @Override
            public void onInitializationFailure(YouTubeThumbnailView youTubeThumbnailView, YouTubeInitializationResult youTubeInitializationResult) {
                //do nohing.. ada error, tambahin method ini jalan, error-nya lupa...
                readyForLoadingYoutubeThumbnail = true;
            }
        });
    }
    holder.mdelate.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            deleteVideoAlertDialog(listvideo.get(holder.getAdapterPosition()).getId(), holder.getAdapterPosition());
        }
    });

}

@Override
public int getItemCount() {
    // Log.v(VideoAdapter.class.getSimpleName(), "" + listvideo.size());
    return listvideo.size();
}

public class VideoHolder extends RecyclerView.ViewHolder {

    YouTubeThumbnailView youTubeThumbnailView;
    protected FrameLayout playButton;
    TextView murl, mdelate;
    ImageView loding;

    public VideoHolder(View itemView) {
        super(itemView);
        mdelate = itemView.findViewById(R.id.mdelate);
        murl = itemView.findViewById(R.id.murl);
        playButton = itemView.findViewById(R.id.btnYoutube_player);
        youTubeThumbnailView = itemView.findViewById(R.id.youtube_thumbnail);
        loding = itemView.findViewById(R.id.loding);

        playButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = getAdapterPosition();
                String url = listvideo.get(position).getVideoUrl();
                Toast.makeText(mContext, url, Toast.LENGTH_SHORT).show();
                Intent intent = YouTubeStandalonePlayer.createVideoIntent((Activity) mContext,
                        KEY, url, 100, false, true);
                mContext.startActivity(intent);
            }
        });
    }

}

private void deleteVideoAlertDialog(final int row_id, final int adapterPosition) {
    final AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);

    // Setting Dialog Title
    alertDialog.setTitle("Delete");
    // Setting Dialog Message
    alertDialog.setMessage("Are you sure you want to delete this video");
    alertDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            if (SQLiteHelper.deleteUser(mContext, row_id)) {
                listvideo.remove(adapterPosition);
                notifyItemRemoved(adapterPosition);
                notifyItemRangeChanged(adapterPosition, listvideo.size());
            } else {
                Toast.makeText(mContext, "internal issue ", Toast.LENGTH_SHORT).show();
            }
        }
    });
    // Setting Negative "NO" Button
    alertDialog.setNegativeButton("No", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            // Write your code here to invoke NO event
            dialog.cancel();
        }
    });
    // Showing Alert Message
    alertDialog.show();

}

public boolean addNewVideo(String Url, Context context) {
    videoPojo.setVideoUrl(Url);
    SQLiteHelper sqLiteHelper = new SQLiteHelper(context);
    if (sqLiteHelper.addNewVideo(context, videoPojo)) {
        listvideo.add(videoPojo);
        notifyDataSetChanged();
        Toast.makeText(context, "video Saved", Toast.LENGTH_SHORT).show();
        return true;
    }
    return false;
}

}

链接地址: http://www.djcxy.com/p/28914.html

上一篇: 如何使用javascript API和json获取YouTube播放列表

下一篇: 如何使用Youtube API在RecyclerView中加载Youtube缩略图