3

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;
}
Amanni
  • 1,924
  • 6
  • 31
  • 51

1 Answers1

1

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.

Community
  • 1
  • 1
Mohamed_AbdAllah
  • 5,311
  • 3
  • 28
  • 47
  • With AsyncTasks I believe you cannot reuse instances, a new one has to be created. Would it be better if I were to add an instance in my ViewHolder class? Could you please be more specific with regards to my case, maybe some pseudo code as well. – Amanni Aug 28 '14 at 14:30
  • I've tried using a global variable for my SetVideotask and cancelling before I start a new one but that doesn't work. – Amanni Aug 28 '14 at 15:16