【问题标题】:Android VideoView black screenAndroid VideoView 黑屏
【发布时间】:2012-04-03 16:05:16
【问题描述】:

我一直在寻找在运行 start() 方法之前摆脱 VideoView 上令人讨厌的黑色初始屏幕的方法。

我已尝试在小部件上使用背景图像,但它根本无法按预期工作。 我还尝试将视频中第一帧的图像放在 VideoView 的顶部,并在 start() 方法之后将其隐藏。 添加一个 onPrepared 监听器来启动视频,然后隐藏图像。这行得通,但在过渡中有可怕的闪烁,我不知道如何摆脱它。


添加 MediaController 完全没有效果。问题仍然存在(我仍然看到黑色闪烁),我根本不想让视频控件可见。 我的代码如下所示:

    VideoView vSurface= (VideoView) findViewById(R.id.surfaceView1);
    vSurface.setVideoURI(Uri.parse("android.resource://com.mypackage/" + R.raw.video1));
    vSurface.setVisibility(View.VISIBLE);
    vSurface.setOnPreparedListener(this);
    vSurface.setDrawingCacheEnabled(true);
    vSurface.setOnErrorListener(this);

【问题讨论】:

  • 您找到解决问题的方法了吗?我也遇到了同样的情况
  • 我做到了,最好的方法是下面的方法。但是当您尝试删除视图时问题仍然存在(如果是这种情况)。它仍然会闪烁。希望不是你的情况。
  • 如果你检查一下,这个问题要老得多。谢谢
  • 谁能告诉我为什么会这样?

标签: android flicker android-videoview


【解决方案1】:

我遇到了同样的问题,并用上面接受的解决方案加上这个来解决它:

  @Override
  public void onPrepared(MediaPlayer mp) {
    mp.setOnInfoListener(new MediaPlayer.OnInfoListener() {
      @Override
      public boolean onInfo(MediaPlayer mp, int what, int extra) {
        Log.d(TAG, "onInfo, what = " + what);
        if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
          // video started; hide the placeholder.
          placeholder.setVisibility(View.GONE);
          return true;
        }
        return false;
      }
    });

我认为 onPrepared 只是意味着视频已准备好播放,但并不意味着视频开始播放。如果在onPrepared中隐藏占位符,屏幕仍然显示黑屏。

在我的 Note3 和 Nexus 上,这个解决方案效果很好。

【讨论】:

  • 我在 VideoView 上应用了 ImageView。当 MEDIA_INFO_VIDEO_RENDERING_START 被触发时,我隐藏了 ImageView。
  • 请注意 MEDIA_INFO_VIDEO_RENDERING_START 需要 api 17+
  • 肯定应该是正确答案! +1 我的朋友 ;)
  • 在 Android 5.1 上没有区别。
  • 我试过这个并没有在物理设备上看到任何闪烁,但在模拟器上仍然看到闪烁 (API 23)。因此,似乎等待 MEDIA_INFO_VIDEO_RENDERING_START 并不能保证任何事情。不过我不知道有更好的选择。
【解决方案2】:

我在 Galaxy tab 2、Android 4.1.1 上遇到了同样的问题。

做videoView.setZOrderOnTop(true); 和下一个videoView.start()

对我来说很好用。

【讨论】:

  • 仅当您没有在 videoview 上设置小部件时才有效
  • 在 Android 7.0 上为我工作,非常感谢!这让我发疯了
【解决方案3】:

我遇到了同样的问题,我找到了解决方案。它有点hacky,但它可以解决问题。 所以基本上你需要把你的 VideoView 放到 FrameLayout 中。 在 videoview 上,您需要添加另一个带有视频背景的 FrameLayout,当您的视频加载并准备好播放时,您隐藏占位符。

<FrameLayout
  android:id="@+id/frameLayout1"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:layout_gravity="center"
  android:layout_marginTop="50dip" >

  <VideoView
    android:id="@+id/geoloc_anim"
    android:layout_width="fill_parent"
    android:layout_height="172dip" android:layout_gravity="top|center" android:visibility="visible"/>

  <FrameLayout
      android:id="@+id/placeholder"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent" android:background="@drawable/fondvert_anim">
  </FrameLayout>

在您的活动中,您需要实现 OnPreparedListener 并添加此

//Called when the video is ready to play
public void onPrepared(MediaPlayer mp) {

    View placeholder = (View) findViewById(R.id.placeholder);

    placeholder.setVisibility(View.GONE);
}

因此,当视频准备好时,我们隐藏占位符并避免黑屏闪烁。

希望这对某人有所帮助。

【讨论】:

  • 这是一个非常糟糕的解决方法,因为它意味着不透明的可绘制对象与布局匹配。此外,我发现闪烁的持续时间因设备而异,并且在调用onPrepared() 时不一定显示第一帧。令人失望。
  • 如果它有效,那么谁在乎它是否是“黑客”——生活中的一切都不完美!您总是可以使用占位符在框架布局上设置一个简短的 alpha 动画,以便减少“轻弹”效果 - 或者玩这样的东西..
  • 但我的黑屏在 onPrepared 被调用后仍然出现,该怎么办?
  • 我在 Android 5.1 上使用此解决方案仍然有黑色闪烁。
  • 视图仍然会导致闪烁。 @wizardlee 有正确答案
【解决方案4】:

我有同样的问题,这对我有用..

当你想显示视频时,使 videoView.setZOrderOnTop(false);当你想隐藏视频时,只需制作 videoView.setZOrderOnTop(true);

【讨论】:

  • 出于某种原因,这提高了性能,但并不能完全防止黑闪。不过谢谢
  • 这个答案帮助了我,就像@Moak所说的那样,它并不能完全防止黑色闪光。我为防止它所做的是if(videoView.isPlaying()) 然后设置videoView.setZOrderOnTop(false)
  • 它应该适用于所有人。首先设置 videoView.setZOrderOnTop(true);然后设置 videoView.setZOrderOnTop(true);在 OnPreparedListener 回调内部。
【解决方案5】:

我遇到了同样的问题,我刚刚使用了 videov.setBackgroundColor(Color.WHITE),然后在 onprepare 我使用了 Color.TRANSPARENT) 白色对我来说仍然比黑色好

【讨论】:

  • 简单的解决方案。如果您有可能设置一种与您的视图风格不冲突的颜色,那是最好的。
  • 我一直黑屏,只有声音没有视频。 Color.TRANSPARENT 在 onPreparedListener 中为我工作...非常感谢
【解决方案6】:

通过扩展 TextureView,我在开始或结束时都不会出现黑屏。这是如果您想避免使用ZOrderOnTop(true)。

public class MyVideoView extends TextureView implements TextureView.SurfaceTextureListener {
  private MediaPlayer mMediaPlayer;
  private Uri mSource;
  private MediaPlayer.OnCompletionListener mCompletionListener;
  private boolean isLooping = false;


  public MyVideoView(Context context) {
      this(context, null, 0);
  }

  public MyVideoView(Context context, AttributeSet attrs) {
      this(context, attrs, 0);
  }

  public MyVideoView(Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);
      setSurfaceTextureListener(this);
  }

  public void setSource(Uri source) {
      mSource = source;
  }

  public void setOnCompletionListener(MediaPlayer.OnCompletionListener listener) {
      mCompletionListener = listener;
  }

  public void setLooping(boolean looping) {
     isLooping = looping;
  }

  @Override
  protected void onDetachedFromWindow() {
     // release resources on detach
     if (mMediaPlayer != null) {
         mMediaPlayer.release();
         mMediaPlayer = null;
     }
     super.onDetachedFromWindow();
   }

   /*
    * TextureView.SurfaceTextureListener
    */
    @Override
   public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
     Surface surface = new Surface(surfaceTexture);
     try {
         mMediaPlayer = new MediaPlayer();
         mMediaPlayer.setOnCompletionListener(mCompletionListener);
         mMediaPlayer.setOnBufferingUpdateListener(this);
         mMediaPlayer.setOnErrorListener(this);
         mMediaPlayer.setLooping(isLooping);
         mMediaPlayer.setDataSource(getContext(), mSource);
         mMediaPlayer.setSurface(surface);
         mMediaPlayer.prepare();
         mMediaPlayer.start();
     } catch (IllegalArgumentException e) {
         e.printStackTrace();
     } catch (SecurityException e) {
         e.printStackTrace();
     } catch (IllegalStateException e) {
         e.printStackTrace();
         mMediaPlayer.reset();
     } catch (IOException e) {
         e.printStackTrace();
     }
   }

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

  @Override
  public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
     surface.release();
     return true;
  }

  @Override
  public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
}

【讨论】:

  • 一个精度,TextureView 来自 api 14
  • @Carl B 如何从一个视频切换到另一个视频。你能帮忙吗,我必须调用哪种方法
  • 视频课要做什么?
  • 有人能更好地解释一下吗?如果我使用上面的代码,它不包含常见的VIdeoView方法如start()等。
  • 好的,我用上面的逻辑成功实现了一个自定义的VideoView,但是还是黑屏。所以,在 Android 5.1 上对我没有好处。
【解决方案7】:

这对我有用:

videoView.setBackgroundColor(Color.WHITE); // Your color.
videoView.start();
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    @Override
    public void onPrepared(MediaPlayer mp) {
        videoView.setBackgroundColor(Color.TRANSPARENT);
    }
});

至少两年后,但我希望这会有所帮助。

【讨论】:

    【解决方案8】:

    以上都不适合我。 在我的情况下,onPrepared 在黑框消失之前被调用,所以我仍然会看到黑框。

    我需要一个解决方案,让视频在第一帧后不久出现。

    所以我所做的是在 xml 中将 VideoView alpha 设置为 0:

    android:alpha="0"
    

    然后在开始播放视频之前,我将 alpha 设置为 1:

    videoView.animate().alpha(1);
    videoView.seekTo(0);
    videoView.start();
    

    或者,您可以只发布延迟的 Runnable 以将 alpha 设置为 1,而不是对其进行动画处理。

    【讨论】:

      【解决方案9】:

      这绝对是 hacky,但比覆盖图像 (IMO) 要好。

      boolean mRestored = false;
      
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
      
          mRestored = savedInstanceState != null;
      }
      
      @Override
      public void onPrepared(MediaPlayer mp) {
      
          if (!mRestored) vSurface.seekTo(1);
      }
      

      假设您将东西放入savedInstanceState 中的onSaveInstanceState。

      【讨论】:

      • 对 Android 5.1 没有影响。
      【解决方案10】:

      只显示视频中的一帧作为预览。

      vSurface.SeekTo(100);
      

      【讨论】:

        【解决方案11】:

        我认为只需使用 VideoView#setBackgroundDrawable()。

        1. 初始设置。

          VideoView.setBackgroundDrawable(yourdrawableid);
          
        2. 开始视频

          VideoView.start();
          VideoView.setBackgroundDrawable(0);
          

        【讨论】:

          【解决方案12】:

          对于仍在寻找答案的人,在onPrepared 内连续调用VideoView.start() 和VideoView.pause() 对我有用。我知道这可能不是实现这一目标的理想方式,但它可能是代码中所需解决方法最少的方式。希望这对你也有用。

          @Override
          public void onPrepared(MediaPlayer mp) {
              mVideoView.start();
              mVideoView.pause();
          }
          

          【讨论】:

          • 在 Android 5.1 上没有区别。
          【解决方案13】:

          这个对我有用:

          在 XML 中:VideoView 隐藏在具有白色背景的相对布局后面

              <VideoView
                android:id="@+id/myVideo"
                android:layout_below="@+id/logo_top"
                android:layout_width="200dp"
                android:layout_height="200dp"
                android:layout_centerHorizontal="true" 
              />
              <RelativeLayout
                android:id="@+id/mask"
                android:background="#FFFFFF"
                android:layout_below="@+id/logo_top"
                android:layout_centerHorizontal="true"
                android:layout_width="200dp"  android:layout_height="200dp"
              >
              </RelativeLayout>
          

          在活动中:onCreate

          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.acceuil);
              myVideo = (VideoView)  findViewById(R.id.myVideo);
              mask = (RelativeLayout)  findViewById(R.id.mask);
              String path = "android.resource://" 
                + getPackageName() + "/" + R.raw.anim_normal;
              myVideo.setVideoURI(Uri.parse(path));
              myVideo.start();
          }
          

          开始:

           public void onStart() { 
              final long time = System.currentTimeMillis();
              super.onStart();
              new CountDownTimer(5000, 100) { 
              @Override
                  public void onTick(long l) {
          
                      long time2 = System.currentTimeMillis();
                      if((time2 - time) > 500) {
                          mask.setVisibility(View.GONE);
                      }
                  }
          
          }.start();
          

          希望这会有所帮助。

          【讨论】:

            【解决方案14】:

            使用 svVideoView.seekTo(position)。

            在 5 (ms) 内给出位置。

            onPause():
            position=svVideoView.getCurrentPosition()
            
            onResume():
            svVideoView.seekTo(position);
            

            【讨论】:

              【解决方案15】:

              它在 Activity 和 Fragment 上都适用于我。

              VideoView mVideo = (VideoView) findViewById(R.id.yourViewViewId);
                        mVideo.setVideoURI(mUri);
                        mVideo.setZOrderOnTop(false);
              
              SurfaceHolder surfaceholder = mVideo.getHolder();
              surfaceholder.setFormat(PixelFormat.TRANSPARENT);
              

              【讨论】:

                【解决方案16】:

                对我来说,设置setZOrderOnTop 并没有完全消除播放 mp4 视频时的初始黑框。但是,它确实减少了黑框出现的时间。我想完全删除最初的黑框,所以我玩了一下,发现将视频向前搜索 100 毫秒对我来说很有效。

                请注意,我正在循环使用视频,所以如果您不想循环播放视频,只需删除
                mp.isLooping = true

                以下是我用来解决问题的 sn-p:

                val path = "android.resource://" + packageName + "/" + R.raw.my_video
                videoView.setVideoURI(Uri.parse(path))
                videoView.setZOrderOnTop(true)
                videoView.seekTo(100)
                videoView.start()
                
                videoView.setOnPreparedListener { mp ->
                   videoView.setZOrderOnTop(false)
                   mp.isLooping = true // Loops the video 
                }
                

                如果有人认为它有帮助,如果我能准确解释为什么上述方法有效,那就太好了。

                【讨论】:

                  【解决方案17】:

                  这个答案有点晚了,但也许其他用户有同样的问题并找到这个问题..

                  我已经解决了这个问题,最初设置了一个 BackgroundResource,然后在开始播放视频时,我将背景设置为不可见的颜色..

                  VideoView myView = findViewById(R.id.my_view);
                  myView.setBackgroundResource(R.drawable.some_resource);
                  // some stuff
                  
                  // this is when starting the video
                  myView.setVideoUri(someUri);
                  // also set MediaController somewhere...
                  //...
                  // now set the backgroundcolor to be not visible (first val of Color.argb(..) is the alpha)
                  myView.setBackGroundColor(Color.argb(0, 0, 0, 0));
                  //...
                  myView.start();
                  

                  【讨论】:

                  • 在开始视频之前只需video.setBackgroundColor(Color.WHITE);。然后video.setBackgroundColor(Color.TRANSPARENT);准备好了。
                  【解决方案18】:

                  这是一个不错的解决方案:

                  package com.example.videoviewpractice;
                  
                  import android.app.Activity;
                  import android.net.Uri;
                  import android.os.Bundle;
                  import android.view.View;
                  import android.widget.MediaController;
                  import android.widget.VideoView;
                  
                  public class MainActivity extends Activity {
                  
                      VideoView myVideoView;
                  
                  @Override
                  protected void onCreate(Bundle savedInstanceState) {
                      super.onCreate(savedInstanceState);
                      setContentView(R.layout.activity_main);
                      initVideo();
                  }
                  
                  private void initVideo() {
                      myVideoView = (VideoView) findViewById(R.id.videoView1);
                      String url = "http://mtc.cdn.vine.co/r/videos/3DF00EB7001110633055418310656_1e50d6d9a65.3.2.mp4?" + 
                              "versionId=KVMUFFGqe6rYRrGKgl8hxL6eakVAErPy";
                      myVideoView.setVideoURI(Uri.parse(url));
                      myVideoView.setMediaController(new MediaController(this));
                      myVideoView.requestFocus();
                  }
                  
                  public void gone(View v){
                      myVideoView.setZOrderOnTop(true);
                      View placeholder = (View) findViewById(R.id.placeholder);
                  
                      placeholder.setVisibility(View.GONE);
                      myVideoView.start();
                  }
                  
                  }
                  

                  activity_main.xml:

                  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  xmlns:tools="http://schemas.android.com/tools"
                  android:id="@+id/LinearLayout1"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:orientation="vertical"
                  tools:context="${relativePackage}.${activityClass}" >
                  
                  <FrameLayout
                      android:id="@+id/frameLayout1"
                      android:layout_width="fill_parent"
                      android:layout_height="fill_parent"
                      android:layout_gravity="center"
                      android:layout_marginTop="50dip" >
                  
                      <VideoView
                          android:id="@+id/videoView1"
                          android:layout_width="300dp"
                          android:layout_height="300dp"
                          android:layout_gravity="top|center"
                          android:visibility="visible" />
                  
                      <FrameLayout
                          android:id="@+id/placeholder"
                          android:layout_width="300dp"
                          android:layout_height="300dp"
                          android:layout_gravity="top|center"
                          android:background="@drawable/ic_launcher"
                          android:onClick="gone" >
                      </FrameLayout>
                  
                  </FrameLayout>
                  
                  </LinearLayout>
                  

                  【讨论】:

                    【解决方案19】:

                    为了避免烦人的闪烁和黑屏问题,我写了FrameVideoView。

                    它受益于“占位符解决方案”和(如果您的设备运行 API 级别 14 或更高)来自TextureView,这比VideoView 更有效。

                    我在我们的博客上写了article 来介绍它的实际作用。

                    使用简单:

                    在布局中添加FrameVideoView:

                    <mateuszklimek.framevideoview.FrameVideoView
                        android:id="@+id/frame_video_view"
                        android:layout_width="@dimen/video_width"
                        android:layout_height="@dimen/video_height"
                      />
                    

                    在Activity中找到它的实例,并在onResume和onPause中调用相应的方法:

                    public class SampleActivity extends Activity {
                    
                      private FrameVideoView videoView;
                    
                      @Override
                      protected void onCreate(Bundle savedInstanceState) {
                        super.onCreate(savedInstanceState);
                        setContentView(R.layout.simple);
                    
                        String uriString = "android.resource://" + getPackageName() + "/" + R.raw.movie;
                        videoView = (FrameVideoView) findViewById(R.id.frame_video_view);
                        videoView.setup(Uri.parse(uriString), Color.GREEN);
                      }
                    
                        @Override
                        protected void onResume() {
                          super.onResume();
                          videoView.onResume();
                        }
                    
                        @Override
                        protected void onPause() {
                          videoView.onPause();
                          super.onPause();
                        }
                      }
                    

                    【讨论】:

                    • 这是一个不错的解决方案,但是视频处于无限循环中,并且在某些视频上,右边缘有绿线,底部有黑线(它在项目中的原始视频没有, h.264,mp4)。有这个问题的人吗?解决方案?
                    【解决方案20】:

                    我遇到了同样的问题。我发现主要原因是使用FrameLayout 作为父布局。使用RelativeLayout 作为VideoView 的父布局

                    【讨论】:

                      【解决方案21】:

                      修改@emmgfx 的答案对我有用:

                      videoView.setBackgroundColor(Color.WHITE)
                      videoView.start()
                      Timer().schedule(100){
                        videoView?.setBackgroundColor(Color.TRANSPARENT)
                      }
                      

                      技巧是延迟视频观看,直到视频加载。 PS : 是 kotlin。

                      【讨论】:

                        【解决方案22】:

                        我找到了解决这个问题的好方法。 (在 Kotlin 中)

                        在您的视频视图之上创建一个图像视图。 使用处理程序创建一个函数,并检查是否 ( videoview.duration > 0 )

                        如果持续时间大于零,则将 imageview.visibility 设置为 INVISABLE,并紧跟 handler.removeCallbacks(this)

                        调用videoview.start后调用上述函数

                        代码如下:

                        fun showVideoView() {

                            val handler = Handler()
                        
                            handler.postDelayed(object : Runnable {
                                override fun run() {
                                    try {
                                        if (videoplayer_topthree.currentPosition > 0) {
                                            videoview_topthreeloadingimage.visibility = View.INVISIBLE
                                            videoview_topthreeprogressbar.visibility = View.VISIBLE
                                            videoview_topthreefullname.visibility = View.VISIBLE
                                            videoview_topthreeviews.visibility = View.VISIBLE
                                            videoview_topthreedate.visibility = View.VISIBLE
                                            videoview_topthreedescription.visibility = View.VISIBLE
                                            videoview_topthreedimview.visibility = View.VISIBLE
                                            handler.removeCallbacks(this)
                                        }
                                        handler.postDelayed(this, 250)
                                    } catch (e: Exception) {
                                        println("SHOW VIDEOVIEW CATCH WAS CAUGHT")
                                    }
                                }
                        
                            }, 0)
                        
                        }
                        

                        这就是我调用这个函数的地方..

                        videoplayer_topthree.setOnPreparedListener {

                                prepareSizing(it)
                                initializeProgressBar()
                                showVideoView()
                                
                            }
                        

                        【讨论】:

                          【解决方案23】:

                          尝试在大部分为白色的布局上播放大部分为白色的视频会以一种非常明显且令人讨厌的方式显示这些故障,尤其是在 Activity 转换期间。我设法完全摆脱故障的唯一方法是将这个线程的几个不同答案和 elprl 在https://stackoverflow.com/a/9089245/3997253 的答案混合在一起。

                          创建一个覆盖 VideoView 的纯色 View

                          <View
                          android:id="@+id/coverView"
                          android:background="@color/white"
                          android:layout_width="match_parent"
                          android:layout_height="match_parent" />
                          

                          在 onCreate 中

                          ...
                          coverView = findViewById(R.id.coverView)
                          videoView = findViewById(R.id.videoView)
                          
                          videoView.setZOrderOnTop(false)
                          val surfaceHolder = videoView.holder
                          surfaceHolder.setFormat(PixelFormat.TRANSPARENT)
                          

                          在 onStart 中

                          ...
                          videoView.setOnPreparedListener { mp ->
                              // Fade out cover View to show VideoView once rendering has started
                              mp.setOnInfoListener { _, what, _ ->
                                  if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
                                      coverView.animate().alpha(0F)
                                      return@setOnInfoListener true
                                  }
                                  return@setOnInfoListener false
                              }
                              mp.isLooping = true
                              videoView.start()
                              videoView.requestFocus()
                          }
                          

                          使用 VideoView 完成后

                          // Fade in cover View to hide the VideoView
                          coverView.animate().alpha(1F)
                          

                          【讨论】:

                            【解决方案24】:

                            看到这个

                            VideoView videoView = (VideoView) findViewById(R.id.VideoView);
                                    MediaController mediaController = new MediaController(this);
                                    mediaController.setAnchorView(videoView);
                                    Uri video = Uri.parse("android.resource://your_package_name/"+R.raw.monkeysonthebed_video);
                            
                                    videoView.setMediaController(mediaController);
                                    videoView.setVideoURI(video);
                                    videoView.start();
                            

                            【讨论】:

                            • 谢谢,但我不想使用/显示媒体控制器。
                            猜你喜欢
                            • 1970-01-01
                            • 2012-07-16
                            • 2023-03-20
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2013-07-17
                            • 1970-01-01
                            相关资源
                            最近更新 更多