Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Videos showing in wrong order when using TextureView in a ListView

I have a Listview which displays videos in some rows so the user can watch the video via the listview using TextureView. So far the videos load and play correctly but they seem to show up in the wrong order at times while scrolling. I believe this is due to the adapter recycling views but I am not sure how to fix this.

here is my implementation

There is the getView which handles rendering the views and then there is an AsyncTask started by the getView to setup the MediaPlayer for each view.

@Override
public View getView(int position, View view, ViewGroup parent) {
    final ViewHolder holder;

    final VoucherItem vItem = items.get(position);

    if (view == null) {
        view = inflater.inflate(R.layout.voucher_row, parent, false);
        holder = new ViewHolder();

        holder.list_img = (ImageView) view.findViewById(R.id.list_img);         
        holder.vid_play = (ImageView) view.findViewById(R.id.vid_play);
        holder.video = (TextureView) view.findViewById(R.id.texture_video);

        view.setTag(holder);
    } else {
        holder = (ViewHolder) view.getTag();
    }



        if (!vItem.photo.equals(""))
            Picasso.with(context).load(vItem.photo).fit().centerCrop()
                    .into(holder.list_img);
        else
            Picasso.with(context).load(R.drawable.default_spuare).fit()
                    .centerCrop().into(holder.list_img);


        if (!vItem.photo.equals("")){
            holder.vid_play.setVisibility(View.GONE);
            holder.video.setVisibility(View.GONE);
            holder.list_img.setVisibility(View.VISIBLE);
        } else {                
            holder.video.setVisibility(View.VISIBLE);
            holder.list_img.setVisibility(View.GONE);

            holder.video.setSurfaceTextureListener(new SurfaceTextureListener() {

                @Override
                public void onSurfaceTextureUpdated(SurfaceTexture arg0) {

                }

                @Override
                public void onSurfaceTextureSizeChanged(SurfaceTexture arg0, int arg1,
                        int arg2) {                     
                }

                @Override
                public boolean onSurfaceTextureDestroyed(SurfaceTexture arg0) {
                    return false;
                }

                @Override
                public void onSurfaceTextureAvailable(SurfaceTexture surface, int arg1, int arg2) {
                    final MediaPlayer mediaPlayer = new MediaPlayer();
                    holder.vid_play.setTag(mediaPlayer);
                    new SetVideotask().execute(surface, vItem, mediaPlayer, holder.vid_play);                       
                }
            });
        }
    }

    return view;
}

class SetVideotask extends AsyncTask<Object, Integer, String>{

    @Override
    protected String doInBackground(Object... o) {
        // TODO Auto-generated method stub
        final SurfaceTexture s = (SurfaceTexture) o[0];
        final VoucherItem item = (VoucherItem) o[1];
        final MediaPlayer mediaPlayer = (MediaPlayer) o[2];
        final View v = (View) o[3];


        mediaPlayer.setSurface(new Surface(s));
        try {

            mediaPlayer.setDataSource(item.video);
            mediaPlayer.prepare();
            mediaPlayer.start();
            //I do this so there is a frame in the video to act as a preview
            Thread.sleep(100);
            mediaPlayer.pause();    
            mediaPlayer.setOnErrorListener(VoucherAdapter.this);                
        } catch (Exception e) {
            e.printStackTrace();
        }           

        return null;
    }       
}



static class ViewHolder {
    ImageView list_img;
    ImageView vid_play;
    TextureView video;
}


@Override
public boolean onError(MediaPlayer arg0, int arg1, int arg2) {
    return true;
}
like image 736
Amanni Avatar asked Nov 23 '25 06:11

Amanni


1 Answers

This is because your AsyncTask instances created in onSurfaceTextureAvailable may not finish sequentially and when you are scrolling, the thread created for the new view may complete before the thread of the recycled view (so the old data is loaded).

I managed to solve this case by creating a single thread pool that I terminate while scrolling.

Also, this is the ultimate question for ListView loading.

like image 99
Mohamed_AbdAllah Avatar answered Nov 25 '25 19:11

Mohamed_AbdAllah



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!