J'essaie de charger des miniatures de vidéos Youtube dans un RecyclerView. Je fais face à quelques problèmes.
Voici ce que je fais dans mon adaptateur:
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) {
}});
}}}
Cela fonctionne bien, mais je ne le fais pas correctement. Lorsque j'utilise le même adaptateur dans une autre activité, j'obtiens cette erreur:
Activity com.example.yasser.version6.Mespublications has leaked ServiceConnection com.google.Android.youtube.player.internal.r$e@4252bcb8 that was originally bound here
et il faut du temps pour charger les miniatures et parfois cela se mélange entre elles lors du glissement.
J'ai ajouté une fonction pour libérer tous les chargeurs Youtube:
public void ReleaseLoaders() {
for (YouTubeThumbnailLoader loader : loaders.values()) {
loader.release();
}
}
et j'appelle cette fonction à partir de l'activité Onstop ():
@Override
public void onStop() {
super.onStop();
mAdapter.ReleaseLoaders();
}
Cela a bien fonctionné pendant un certain temps, mais les plantages parfois.
Vous pouvez essayer ça peut-être? Il n'utilise pas l'API mais c'est rapide.
Chargez l'image dans la vue du recycleur avec Picasso à partir de cette URL:
https://img.youtube.com/vi/ "voici votre identifiant vidéo" /default.jpg
-- Éditer --
Après quelques recherches et expériences:
Pour obtenir la miniature pleine taille par défaut, faites ceci au lieu de default.jpg
https://img.youtube.com/vi/ "voici votre identifiant vidéo" /0.jpg
Voici le lien: http://www.reelseo.com/youtube-thumbnail-image/
Modifier 2:
Je viens de trouver quelqu'un dans SO a déjà donné une réponse comme la mienne avec cette solution rapide et facile et propose bien plus d'explications et d'options.
Comment puis-je obtenir une miniature de vidéo YouTube à partir de l'API YouTube?
Édition finale:
C'est du code qui fonctionne. Je suis entré et j'ai récemment créé une application avec l'API, j'ai donc découvert pourquoi vous obtenez l'erreur. C'est parce que vous ne libérez pas correctement le chargeur.
Vous pouvez libérer le ou les chargeurs de deux manières.
Premier
(De préférence, vous verrez pourquoi dans une seconde) Vous voudriez la libérer après que l'image a été chargée en vue et qu'il y ait un écouteur pour cela et son appelé OnThumbNailLoadedListener. C'est là que je l'ai publié (si vous faites attention au code ci-dessous). Cela signifie que vous n'avez plus à gérer cette instance. Une fois la vignette chargée, vous avez terminé.
Deuxième
Étant donné que getView () est appelée tout le temps, de nouvelles instances de YouTubeThumbnailLoader doivent être publiées. Cela signifie que vous devez stocker tous ces éléments dans une liste de tableaux. Vous faites juste une avancée pour la boucle et la libération d'appel dans chacun d'eux lorsque l'activité est onStop ();
Maintenant, vous voyez probablement pourquoi la première voie est préférée. Et je sais que vous avez fait la deuxième option, donc juste vous faire savoir que la première option sera toujours garantie de fonctionner (au moins dans mon cas). J'ai utilisé un YouTubeSupportFragment dans une activité et cela a bien fonctionné. Aucun problème. Vous pouvez certainement faire fonctionner la deuxième option, mais vous devrez gérer un grand nombre de cas spéciaux, je pense.
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) {
}
});
Dans onBindViewHolder
, vous essayez d'initialiser le même YoutubeThumbnailView
encore et encore. Au lieu de cela, vous pouvez l'initialiser une fois lorsque les vues sont créées dans onCreateViewHolder
. En définissant l'identifiant vidéo comme balise sur YoutubeThumbnailView
, vous pouvez empêcher le mixage (ou) le chargement incorrect des miniatures.
Adaptateur.
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();
}
}
La disposition utilisée pour chaque ligne est.
<?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.
Emplacement: 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<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;
}
}