jjzjj

android - 在 RecyclerView 中播放视频 - 滚动到屏幕外时播放/暂停视频

coder 2023-12-20 原文

我已经实现了使用纹理 View 和媒体播放器实现的视频播放器的 Recycler View 。

如果我向下滚动列表,我可以单击该项目并播放视频。但是,对于回收器 View ,一旦 View 离开屏幕,它就会被回收以供重用。如果我向上滚动,所有 View 现在都是空白的(黑色)。

我希望添加这样的功能,即当用户将视频滚动到屏幕外时,它会暂停并保持对该视频的引用,这样如果他们滚动回该视频,它将从该点开始播放。

我检查了this out 但是我不想下载视频,我只想流式传输。我不是在找人为我做这件事,我只是在寻找一些指示并希望有人可以分享他们的知识...... 提前致谢

这是我到目前为止所做的:

视频播放器

public class CustomVideoPlayer implements TextureView.SurfaceTextureListener, VideoControllerView.MediaPlayerControl, MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnVideoSizeChangedListener {

    private Context mContext;
    private String mUrl;
    private MediaPlayer mMediaPlayer;
    private Surface mSurface;
    private VideoControllerView mControllerView;

    private TextureView mTextureView;
    private CardView mCardView;
    private ProgressBar mProgress;
    private FrameLayout mView;
    private RelativeLayout mLayout;


    public CustomVideoPlayer(Context ctx, TextureView view, ProgressBar progressDialog, FrameLayout holderView){

        this.mContext = ctx;
        mTextureView = view;
        mTextureView.setSurfaceTextureListener(this);
        mProgress = progressDialog;
        mControllerView = new VideoControllerView(ctx);
        mView = holderView;

        mTextureView.setOnTouchListener(new ControlTouchListener());
    }


    @Override
    public boolean canPause() {
        return true;
    }

    @Override
    public boolean canSeekBackward() {
        return true;
    }

    @Override
    public boolean canSeekForward() {
        return true;
    }

    @Override
    public int getBufferPercentage() {
        return 0;
    }

    @Override
    public int getCurrentPosition() {
        return mMediaPlayer.getCurrentPosition();
    }

    @Override
    public int getDuration() {
        return mMediaPlayer.getDuration();
    }

    @Override
    public boolean isPlaying() {
        return mMediaPlayer.isPlaying();
    }

    @Override
    public void pause() {
        mMediaPlayer.pause();
    }

    @Override
    public void seekTo(int i) {
        mMediaPlayer.seekTo(i);
    }

    @Override
    public void start() {
        mMediaPlayer.start();
    }

    @Override
    public boolean isFullScreen() {
        return false;
    }

    @Override
    public void toggleFullScreen() {

    }

    @Override
    public void onBufferingUpdate(MediaPlayer mp, int percent) {

    }

    @Override
    public void onCompletion(MediaPlayer mp) {

    }



    @Override
    public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {

    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        mSurface = new Surface(surface);
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

    }

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

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {

    }

    public void changePlayState(){
        if(mMediaPlayer.isPlaying()){
            mMediaPlayer.pause();
        }else{
            mMediaPlayer.start();
        }
    }

    public void startVideo(String url){
        if(mMediaPlayer!=null){
            mMediaPlayer.reset();
            mMediaPlayer.release();
            mMediaPlayer = new MediaPlayer();
        }else{
            mMediaPlayer = new MediaPlayer();
        }
        if(!mMediaPlayer.isPlaying()){
            try {
                mMediaPlayer.setSurface(mSurface);
                mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                mMediaPlayer.setDataSource(url);
                mMediaPlayer.prepareAsync();
                mMediaPlayer.setOnCompletionListener(this);
                mMediaPlayer.setOnBufferingUpdateListener(this);
                mMediaPlayer.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
                mMediaPlayer.setOnPreparedListener(this);

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    @Override
    public void onPrepared(MediaPlayer mp) {
        Log.i(VersysVideoPlayer.class.getSimpleName(), "ON PREPARED CALLED");
        mControllerView.setMediaPlayer(this);
        mControllerView.setAnchorView(mView);
        mControllerView.show();
        mProgress.setVisibility(View.GONE);
        mMediaPlayer.start();
    }

    //Touch listener to display video controls
    class ControlTouchListener implements View.OnTouchListener{

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if(event.getAction() == MotionEvent.ACTION_DOWN){
                mControllerView.show();
            }
            return false;
        }
    }
}

Activity/适配器

public class VideoViewListActivity extends AppCompatActivity   {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video_view_list);

        //Create instance of Recycler view
        final RecyclerView videoList = (RecyclerView) findViewById(R.id.feed_list);
        LinearLayoutManager llm = new LinearLayoutManager(this);
        videoList.setLayoutManager(llm);
        videoList.setHasFixedSize(true);

        final List<String> list = new ArrayList<>();
        list.add("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4");
        list.add("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4");
        list.add("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4");
        list.add("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4");
        list.add("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4");
        list.add("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4");
        final VideoAdapter adapter = new VideoAdapter(list, this);
        videoList.setAdapter(adapter);


        videoList.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                TextureView view = adapter.getVideoPlayer();
                Log.i("PERCENTAGE VISIBLE: ", String.valueOf(getVisiblePercent(adapter.getVideoPlayer())));
                if(getVisiblePercent(view)==100) {
                    return;
                }
              }
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_video_view_list, menu);
        return true;
    }


    public static int getVisiblePercent(View v) {
        if (v.isShown()) {
            Rect r = new Rect();
            v.getGlobalVisibleRect(r);
            double sVisible = r.width() * r.height();
            double sTotal = v.getWidth() * v.getHeight();
            return (int) (100 * sVisible / sTotal);
        } else {
            return -1;
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }


    /**
     * Recycler View Adapter
     */
    class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoFeedHolder> {

        public TextureView mPreview;
        private CardView mCardView;
        private List<String> mUrls;
        private Context mContext;
        private Surface mSurface;
        VideoControllerView controller;
        private View mAnchor;
        private ProgressBar mProgressDialog;
        private ImageView mHolder;
        private int mPosition;
        private VersysVideoPlayer mVideoPlayer;
        OnItemClickListener mItemClickListener;

        public VideoAdapter(List<String> url, Context ctx) {
            mUrls = url;
            mContext = ctx;
            controller = new VideoControllerView(ctx);
        }

        @Override
        public VideoAdapter.VideoFeedHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
            View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.video_item_feed, viewGroup, false);
            VideoFeedHolder holder = new VideoFeedHolder(v);
            return holder;
        }

        @Override
        public void onBindViewHolder(final VideoFeedHolder videoFeedHolder, final int i) {

            final VersysVideoPlayer videoPlayer = new VersysVideoPlayer(mContext, videoFeedHolder.mTexturePreview, mProgressDialog, videoFeedHolder.controlHolder);
            videoFeedHolder.placeholder.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    videoPlayer.startVideo(mUrls.get(i));
                    videoFeedHolder.placeholder.setVisibility(View.GONE);
                    videoFeedHolder.bar.setVisibility(View.VISIBLE);
                }
            });

            mPosition = i;
        }

        @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            super.onAttachedToRecyclerView(recyclerView);
        }


        public String getUrl() {
            return mUrls.get(mPosition);
        }


        @Override
        public int getItemCount() {

            return mUrls.size();
        }

        public TextureView getVideoPlayer() {
            return mPreview;
        }


        public class VideoFeedHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

            TextureView mTexturePreview;
            ProgressBar bar;
            ImageView placeholder;
            FrameLayout controlHolder;
            RelativeLayout touchLayout;
            public VideoFeedHolder(View itemView) {
                super(itemView);

                mTexturePreview = (TextureView) itemView.findViewById(R.id.video_player);
                mPreview = mTexturePreview;
                mCardView = (CardView) itemView.findViewById(R.id.cv);
                bar = (ProgressBar)itemView.findViewById(R.id.buffereing);
                placeholder = (ImageView) itemView.findViewById(R.id.holder);
                mProgressDialog = bar;

                controlHolder = (FrameLayout) itemView.findViewById(R.id.media_controller_anchor);

            }

            @Override
            public void onClick(View v) {
                if (mItemClickListener != null) {
                    mItemClickListener.onItemClick(v, getAdapterPosition());
                }
            }
        }

     }
}

视频源项目 XML

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

    <android.support.v7.widget.CardView
        android:layout_margin="10dp"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:id="@+id/cv">
        <RelativeLayout
            android:id="@+id/anchor"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <RelativeLayout
                android:id="@+id/detail_layout"
                android:layout_marginTop="10dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">
                <ImageView
                    android:id="@+id/profile_pic"
                    android:background="@drawable/profiler"
                    android:layout_marginLeft="10dp"
                    android:layout_width="50dp"
                    android:layout_height="50dp" />

                <TextView
                    android:id="@+id/user_name"
                    android:layout_alignTop="@+id/profile_pic"
                    android:layout_toRightOf="@+id/profile_pic"
                    android:text="Joe Bloggs"
                    android:layout_marginLeft="10dp"
                    android:textColor="#000000"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content" />

                <TextView
                    android:id="@+id/date"
                    android:layout_below="@+id/user_name"
                    android:layout_toRightOf="@+id/profile_pic"
                    android:layout_marginLeft="10dp"
                    android:text="10 Aug 2015"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content" />

                <TextView
                    android:id="@+id/desc"
                    android:layout_below="@+id/profile_pic"
                    android:layout_marginLeft="10dp"
                    android:text="This a sample video of a bird getting hit on the head and a rabbit waking from a nap!!"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content" />
            </RelativeLayout>
            <RelativeLayout
                android:layout_below="@+id/detail_layout"
                android:layout_margin="10dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">
                    <TextureView
                        android:id="@+id/video_player"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent" />
                   <FrameLayout
                       android:id="@+id/media_controller_anchor"
                       android:layout_alignParentBottom="true"
                       android:layout_width="match_parent"
                       android:layout_height="wrap_content">
                   </FrameLayout>

                    <ImageView
                        android:id="@+id/holder"
                        android:layout_centerInParent="true"
                        android:background="@drawable/default_video_poster"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content" />

                    <ProgressBar
                        android:id="@+id/buffereing"
                        android:visibility="gone"
                        android:layout_centerInParent="true"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content" />
            </RelativeLayout>
        </RelativeLayout>
    </android.support.v7.widget.CardView>
</RelativeLayout>

最佳答案

通过覆盖 onViewAttachedToWindow(VH holder) onViewDetachedFromWindow(VH holder) 在您的适配器中,当每个项目进入或退出 RecyclerView 的可见区域时,您会收到通知.因此可以保存项目状态。例如,您可以创建一个 HashMap<Integer, Long>在保存最后一次播放的适配器类中。这样,我们应该暂停视频并将视频播放时间存储在HashMap中。以项目位置为键,在 onViewDetachedFromWindow 中.然后在onViewAttachedToWindow从 map 中恢复它并...

基于文档:

onViewAttachedToWindow is called when a view created by this adapter has been attached to a window.

onViewDetachedFromWindow is called when a view created by this adapter has been detached from its window.


视觉效果:

关于android - 在 RecyclerView 中播放视频 - 滚动到屏幕外时播放/暂停视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31937896/

有关android - 在 RecyclerView 中播放视频 - 滚动到屏幕外时播放/暂停视频的更多相关文章

  1. 屏幕录制为什么没声音?检查这2项,轻松解决 - 2

    相信很多人在录制视频的时候都会遇到各种各样的问题,比如录制的视频没有声音。屏幕录制为什么没声音?今天小编就和大家分享一下如何录制音画同步视频的具体操作方法。如果你有录制的视频没有声音,你可以试试这个方法。 一、检查是否打开电脑系统声音相信很多小伙伴在录制视频后会发现录制的视频没有声音,屏幕录制为什么没声音?如果当时没有打开音频录制,则录制好的视频是没有声音的。因此,建议在录制前进行检查。屏幕上没有声音,很可能是因为你的电脑系统的声音被禁止了。您只需打开电脑系统的声音,即可录制音频和图画同步视频。操作方法:步骤1:点击电脑屏幕右下侧的“小喇叭”图案,在上方的选项中,选择“声音”。 步骤2:在“声

  2. 动漫制作技巧如何制作动漫视频 - 2

    动漫制作技巧是很多新人想了解的问题,今天小编就来解答与大家分享一下动漫制作流程,为了帮助有兴趣的同学理解,大多数人会选择动漫培训机构,那么今天小编就带大家来看看动漫制作要掌握哪些技巧?一、动漫作品首先完成草图设计和原型制作。设计草图要有目的、有对象、有步骤、要形象、要简单、符合实际。设计图要一致性,以保证制作的顺利进行。二、原型制作是根据设计图纸和制作材料,可以是手绘也可以是3d软件创建。在此步骤中,要注意的问题是色彩和平面布局。三、动漫制作制作完成后,加工成型。完成不同的表现形式后,就要对设计稿进行加工处理,使加工的难易度降低,并得到一些基本准确的概念,以便于后续的大样、准确的尺寸制定。四、

  3. python ffmpeg 使用 pyav 转换 一组图像 到 视频 - 2

    2022/8/4更新支持加入水印水印必须包含透明图像,并且水印图像大小要等于原图像的大小pythonconvert_image_to_video.py-f30-mwatermark.pngim_dirout.mkv2022/6/21更新让命令行参数更加易用新的命令行使用方法pythonconvert_image_to_video.py-f30im_dirout.mkvFFMPEG命令行转换一组JPG图像到视频时,是将这组图像视为MJPG流。我需要转换一组PNG图像到视频,FFMPEG就不认了。pyav内置了ffmpeg库,不需要系统带有ffmpeg工具因此我使用ffmpeg的python包装p

  4. TimeSformer:抛弃CNN的Transformer视频理解框架 - 2

    Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图

  5. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  6. ruby-on-rails - Rails 3 - 过滤器链暂停为 :authentication rendered or redirected - 2

    我仍然收到标题中的“错误”消息,但不知道如何解决。在ApplicationController中,classApplicationController在routes.rb#match'set_activity_account/:id/:value'=>'users#account_activity',:as=>:set_activity_account--thisdoesn'tworkaswell..resources:usersdomemberdoget:action_a,:action_bendcollectiondoget'account_activity'endend和User

  7. ruby - 如何更改此正则表达式以从未指定 v 参数的 Youtube URL 获取 Youtube 视频 ID? - 2

    目前我正在使用这个正则表达式从YoutubeURL中提取视频ID:url.match(/v=([^&]*)/)[1]我怎样才能改变它,以便它也可以从这个没有v参数的YoutubeURL获取视频ID:http://www.youtube.com/user/SHAYTARDS#p/u/9/Xc81AajGUMU感谢阅读。编辑:我正在使用ruby​​1.8.7 最佳答案 对于Ruby1.8.7,这就可以了。url_1='http://www.youtube.com/watch?v=8WVTOUh53QY&feature=feedf'url

  8. ruby - 如何以编程方式将 mp3 转换为 itunes 可播放的 aac/m4a 文件? - 2

    我一直在寻找一种以编程方式或通过命令行将mp3转换为aac的方法,但没有成功。理想情况下,我有一段代码可以从我的Rails应用程序中调用,将mp3转换为aac。我安装了ffmpeg和libfaac,并能够使用以下命令创建aac文件:ffmpeg-itest.mp3-acodeclibfaac-ab163840dest.aac当我将输出文件的名称更改为dest.m4a时,它无法在iTunes中播放。谢谢! 最佳答案 FFmpeg提供AAC编码功能(如果您已编译它们)。如果您使用的是Windows,则可以从here获取完整的二进制文件。

  9. ruby - 如何播放 mp3 文件? - 2

    我如何用ruby​​编写一个脚本,当从命令行执行时播放mp3文件(背景音乐)?我试过了run="mplayer#{"/Users/bhushan/resume/m.mp3"}-aosdl-vox11-framedrop-cache16384-cache-min20/100"system(run)但它也不起作用,以上是播放器特定的。如果用户没有安装mplayer怎么办。有没有更好的办法? 最佳答案 我一般都是这样pid=fork{exec'mpg123','-q',file} 关于ruby

  10. ruby-on-rails - 在服务器端检测屏幕尺寸和像素密度? - 2

    我一直在做一些研究,我想我已经知道答案了,但我想知道是否有任何方法可以在不使用javascript或依赖CSS3媒体的情况下获得设备的屏幕尺寸和像素密度查询。本质上,我正在研究如何获取屏幕分辨率和像素密度,以便服务器可以决定在URI请求中为服务器提供哪个图像。到目前为止,我还没有发现任何证据表明这是可能的,但我想嘿,为什么不问问呢? 最佳答案 我不完全同意上面的正确答案。实际上,这个答案在很多情况下都是正确的……但理论上并非如此。通常向Web服务器发出的请求包含一个User-Agent字段,从理论上讲,该字段可用于识别有关设备屏幕分

随机推荐