如何使用 Youtube API 在 RecyclerView 中加载 Youtube 缩略图

Posted

技术标签:

【中文标题】如何使用 Youtube API 在 RecyclerView 中加载 Youtube 缩略图【英文标题】:How to load Youtube thumbnails in a RecyclerView using Youtube API 【发布时间】:2016-03-26 02:20:59 【问题描述】:

我正在尝试在 RecyclerView 中加载 Youtube 视频缩略图。我遇到了一些问题。

这是我在适配器中所做的:

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) 

                );

它工作正常,但我不这样做是正确的。当我在另一个活动中使用相同的适配器时,我收到此错误:

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

加载缩略图需要时间,有时在滑动时会在它们之间混合。

我添加了一个释放所有 Youtube 加载器的功能:

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

我从 Activity Onstop() 调用这个函数:

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

它在一段时间内运行良好,但有时会崩溃。

【问题讨论】:

你检查过this SO ticket吗?您似乎遇到了同样的问题 - 内存泄漏问题,而不是 RecyclerView,似乎您已经处理了。 错误来自 Recyclerview 适配器 如何初始化适配器? 【参考方案1】:

onBindViewHolder 中,您试图一次又一次地初始化相同的YoutubeThumbnailView,相反,您可以在onCreateViewHolder 中创建视图时对其进行一次初始化。通过将视频 ID 作为标签设置为 YoutubeThumbnailView,您可以防止混合(或)错误加载缩略图。


适配器。

    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();
    


每一行使用的布局是。

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

<RelativeLayout
    android:layout_
    android:layout_>

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

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

</RelativeLayout>

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

<View
    android:id="@+id/seperator"
    android:layout_
    android:layout_
    android:layout_marginTop="5dp"
    android:layout_marginBottom="5dp"
    android:background="#FF642108"/>

</LinearLayout>

tags.xml。

位置: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>

【讨论】:

感谢您的回复,但我已经尝试过了,缩略图仍然混合! 我在我的应用程序中使用它。它工作正常。缩略图不会混淆。【参考方案2】:

你可以试试这个吗?它不使用 API,但速度很快。

使用 Picasso 从此 URL 将图像加载到回收站视图中:

https://img.youtube.com/vi/"这里是你的视频ID"/default.jpg

-- 编辑--

经过一些研究和实验:

要获得默认的全尺寸缩略图,请执行此操作而不是 default.jpg

https://img.youtube.com/vi/"这里是你的视频ID"/0.jpg

这里是链接:http://www.reelseo.com/youtube-thumbnail-image/

编辑 2:

刚刚在 SO 中发现有人已经用这个快速简单的解决方案给出了像我这样的答案,并且有更多的解释和选项可供您选择。

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


最终编辑:

这是工作代码。我最近用 api 制作了一个应用程序,所以我发现了你收到错误的原因。这是因为您没有正确释放加载程序。

您可以通过两种方式释放 loader/loaders。

第一

(首选,您将在几秒钟内了解原因) 您可能希望在图像加载到视图中之后释放它,并且有一个侦听器,它称为 OnThumbNailLoadedListener。那就是我发布它的地方(如果你注意下面的代码)。这意味着您不必再处理这个实例了。加载缩略图后,您就完成了。

第二

由于 getView() 一直被调用,因此您必须释放 YouTubeThumbnailLoader 的新实例。这意味着您必须将所有这些存储在一个 ArrayList 中。当活动为 onStop() 时,您只需执行高级 for 循环并在所有这些循环中调用 release;

现在您可能明白为什么首选第一种方式了。而且我知道你做了第二个选项,所以只要让你知道第一个选项总是可以保证工作(至少在我的情况下)。我在 Activity 中使用了 YouTubeSupportFragment,它运行良好。没有任何问题。您绝对可以使第二个选项起作用,但我认为您必须处理很多特殊情况。

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) 

        
    );

【讨论】:

刚刚对我的回答做了很好的编辑。我建议你看看。 非常感谢老兄..!!【参考方案3】:
public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoHolder> 

    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;
    

【讨论】:

【参考方案4】:

从此网址获取高质量图片:

https://img.youtube.com/vi/<VIDEO_ID_HERE>/maxresdefault.jpg

然后使用 picasso 或 glide 库加载它。

对于此视频“https://www.youtube.com/watch?v=BEScHJrjsmU”,VIDEO_ID 为“BEScHJrjsmU”

【讨论】:

以上是关于如何使用 Youtube API 在 RecyclerView 中加载 Youtube 缩略图的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 中使用 youtube 数据 API 搜索视频

如何使用 Youtube API 为 Youtube 视频添加字幕?

您如何使用 YouTube 数据 API 获取过去的直播流

如何获取 Youtube API 配额的每日使用量?

如何使用 Youtube javascript API 在特定“秒”获取 youtube 视频的缩略图或快照?

如何使用YouTube Api下载YouTube视频[关闭]