在RecyclerView中使用TextureViews播放视频,就像Vine一样

时间:2015-10-29 22:38:50

标签: android-mediaplayer android-recyclerview android-textureview

我有一个RecyclerViewViewHolder的每个RecyclerView都有MediaPlayer个对象。我使用TextureView来保存MediaPlayer个对象,问题是当我向下滚动时它非常迟缓。为什么会这样?我相信当表面被破坏时,我正在正确地释放MediaPlayer个物体。

作为参考,我使用了以下TextureView从此回购中获取的public class TextureVideoView extends TextureView implements TextureView.SurfaceTextureListener { // Indicate if logging is on public static final boolean LOG_ON = true; // Log tag private static final String TAG = TextureVideoView.class.getName(); private MediaPlayer mMediaPlayer; private float mVideoHeight; private float mVideoWidth; private boolean mIsDataSourceSet; private boolean mIsViewAvailable; private boolean mIsVideoPrepared; private boolean mIsPlayCalled; private ScaleType mScaleType; private State mState; public enum ScaleType { CENTER_CROP, TOP, BOTTOM } public enum State { UNINITIALIZED, PLAY, STOP, PAUSE, END } public TextureVideoView(Context context) { super(context); initView(); } public TextureVideoView(Context context, AttributeSet attrs) { super(context, attrs); initView(); } public TextureVideoView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(); } private void initView() { if (!isInEditMode()) { initPlayer(); setScaleType(ScaleType.CENTER_CROP); setSurfaceTextureListener(this); } } public void setScaleType(ScaleType scaleType) { mScaleType = scaleType; } private void updateTextureViewSize() { float viewWidth = getWidth(); float viewHeight = getHeight(); float scaleX = 1.0f; float scaleY = 1.0f; if (mVideoWidth > viewWidth && mVideoHeight > viewHeight) { scaleX = mVideoWidth / viewWidth; scaleY = mVideoHeight / viewHeight; } else if (mVideoWidth < viewWidth && mVideoHeight < viewHeight) { scaleY = viewWidth / mVideoWidth; scaleX = viewHeight / mVideoHeight; } else if (viewWidth > mVideoWidth) { scaleY = (viewWidth / mVideoWidth) / (viewHeight / mVideoHeight); } else if (viewHeight > mVideoHeight) { scaleX = (viewHeight / mVideoHeight) / (viewWidth / mVideoWidth); } // Calculate pivot points, in our case crop from center int pivotPointX; int pivotPointY; switch (mScaleType) { case TOP: pivotPointX = 0; pivotPointY = 0; break; case BOTTOM: pivotPointX = (int) (viewWidth); pivotPointY = (int) (viewHeight); break; case CENTER_CROP: pivotPointX = (int) (viewWidth / 2); pivotPointY = (int) (viewHeight / 2); break; default: pivotPointX = (int) (viewWidth / 2); pivotPointY = (int) (viewHeight / 2); break; } Matrix matrix = new Matrix(); matrix.setScale(scaleX, scaleY, pivotPointX, pivotPointY); setTransform(matrix); } private void initPlayer() { if (mMediaPlayer == null) { mMediaPlayer = new MediaPlayer(); } else { mMediaPlayer.reset(); } mIsVideoPrepared = false; mIsPlayCalled = false; mState = State.UNINITIALIZED; } /** * @see android.media.MediaPlayer#setDataSource(String) */ public void setDataSource(final String path) { initPlayer(); ((Activity) getContext()).runOnUiThread(new Runnable() { @Override public void run() { try { mMediaPlayer.setDataSource(path); } catch (IOException e) { e.printStackTrace(); } } }); mIsDataSourceSet = true; prepare(); } /** * @see android.media.MediaPlayer#setDataSource(android.content.Context, android.net.Uri) */ public void setDataSource(Context context, Uri uri) { initPlayer(); try { mMediaPlayer.setDataSource(context, uri); mIsDataSourceSet = true; //prepare(); mMediaPlayer.setWakeMode(context.getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK); } catch (IOException e) { Log.d(TAG, e.getMessage()); } } /** * @see android.media.MediaPlayer#setDataSource(java.io.FileDescriptor) */ public void setDataSource(AssetFileDescriptor afd) { initPlayer(); try { long startOffset = afd.getStartOffset(); long length = afd.getLength(); mMediaPlayer.setDataSource(afd.getFileDescriptor(), startOffset, length); mIsDataSourceSet = true; prepare(); } catch (IOException e) { Log.d(TAG, e.getMessage()); } } private void prepare() { try { // Adjust the size of the MediaPlayer based on the Screen Resolution mMediaPlayer.setOnVideoSizeChangedListener( new MediaPlayer.OnVideoSizeChangedListener() { @Override public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); mVideoWidth = width * metrics.density; mVideoHeight = height * metrics.density; updateTextureViewSize(); } } ); // Add a completion listener for when video ends and pass it to the listener mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { mState = State.END; if (mListener != null) { mListener.onVideoEnd(); } } }); // don't forget to call MediaPlayer.prepareAsync() method when you use constructor for // creating MediaPlayer mMediaPlayer.prepareAsync(); // Play video when the media source is ready for playback. mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mediaPlayer) { mIsVideoPrepared = true; if (mIsPlayCalled && mIsViewAvailable) { log("Player is prepared and play() was called."); play(); } if (mListener != null) { mListener.onVideoPrepared(); } } }); } catch (IllegalArgumentException e) { Log.d(TAG, "IllegalArgumentException"); Log.d(TAG, e.getMessage()); } catch (SecurityException e) { Log.d(TAG, "SecurityException"); Log.d(TAG, e.getMessage()); } catch (IllegalStateException e) { Log.d(TAG, "IllegalStateException"); Log.d(TAG, e.toString()); } } /** * Play or resume video. Video will be played as soon as view is available and media player is * prepared. * <p/> * If video is stopped or ended and play() method was called, video will start over. */ public void play() { if (!mIsDataSourceSet) { log("play() was called but data source was not set."); return; } mIsPlayCalled = true; if (!mIsVideoPrepared) { log("play() was called but video is not prepared yet, waiting."); return; } if (!mIsViewAvailable) { log("play() was called but view is not available yet, waiting."); return; } if (mState == State.PLAY) { log("play() was called but video is already playing."); return; } if (mState == State.PAUSE) { log("play() was called but video is paused, resuming."); mState = State.PLAY; mMediaPlayer.start(); return; } if (mState == State.END || mState == State.STOP) { log("play() was called but video already ended, starting over."); mState = State.PLAY; mMediaPlayer.seekTo(0); mMediaPlayer.start(); return; } mState = State.PLAY; mMediaPlayer.start(); } /** * Pause video. If video is already paused, stopped or ended nothing will happen. */ public void pause() { if (mState == State.PAUSE) { log("pause() was called but video already paused."); return; } if (mState == State.STOP) { log("pause() was called but video already stopped."); return; } if (mState == State.END) { log("pause() was called but video already ended."); return; } mState = State.PAUSE; if (mMediaPlayer.isPlaying()) { mMediaPlayer.pause(); } } /** * Stop video (pause and seek to beginning). If video is already stopped or ended nothing will * happen. */ public void stop() { if (mState == State.UNINITIALIZED) { log("stop() was called but video already released."); } if (mState == State.STOP) { log("stop() was called but video already stopped."); return; } if (mState == State.END) { log("stop() was called but video already ended."); return; } mState = State.STOP; if (mMediaPlayer.isPlaying()) { Log.d(TAG, "MediaPlayer is playing"); mMediaPlayer.pause(); mMediaPlayer.seekTo(0); mMediaPlayer.stop(); } } /** * Reset the video (only if the video has been stopped). This will reset the mediaplayer, else * nothing happens */ public void reset() { if (mState == State.PLAY) { log("reset() was called but video is currently playing."); return; } if (mState == State.PAUSE) { log("reset() was called but video is currently paused."); return; } if (mState == State.STOP) { mMediaPlayer.reset(); } } public void release() { if (mState == State.PLAY) { log("release() was called but video is currently playing."); return; } if (mState == State.PAUSE) { log("release() was called but video is currently paused."); return; } if (mState == State.STOP) { log("release() was called but video is currently stopped."); return; } mMediaPlayer.release(); mMediaPlayer = null; mState = State.UNINITIALIZED; } /** * @see android.media.MediaPlayer#setLooping(boolean) */ public void setLooping(boolean looping) { Log.d(TAG, "Looping"); mMediaPlayer.setLooping(looping); } /** * @see android.media.MediaPlayer#seekTo(int) */ public void seekTo(int milliseconds) { mMediaPlayer.seekTo(milliseconds); } /** * @see android.media.MediaPlayer#getDuration() */ public int getDuration() { return mMediaPlayer.getDuration(); } static void log(String message) { if (LOG_ON) { Log.d(TAG, message); } } private MediaPlayerListener mListener; /** * Listener trigger 'onVideoPrepared' and `onVideoEnd` events */ public void setListener(MediaPlayerListener listener) { mListener = listener; } public interface MediaPlayerListener { void onVideoPrepared(); void onVideoEnd(); } @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { Surface surface = new Surface(surfaceTexture); mMediaPlayer.setSurface(surface); mIsViewAvailable = true; if (mIsDataSourceSet && mIsPlayCalled && mIsVideoPrepared) { play(); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { // Deallocate MediaPlayer if (mMediaPlayer != null) { mMediaPlayer.pause(); mMediaPlayer.stop(); mMediaPlayer.reset(); mMediaPlayer.release(); mMediaPlayer = null; } return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } } 实现:TextureVideoView

TextureVideoView.java

final TextureVideoView videoView = holder.videoview;
videoView.setDataSource(path);
videoView.setLooping(true);
videoView.setScaleType(TextureVideoView.ScaleType.CENTER_CROP);
videoView.play();

当我下载资产时,我会在我的适配器中提供它,如下所示:

RecyclerView

问题在于,当我滚动时,它确实很迟钝,我该如何解决这个问题?除非视图大部分可见,否则我如何制作TextureView public class ActivityTwo extends AppCompatActivity { int sizeOfArray; String[][] qAndA;//Stores Questions and Answers String[] temp; ArrayList<String>arrayListTerms; ArrayList<String>arrayListDef; HashMap<String, String> qMatch = new HashMap<>();//Matches correct answer with current question public static final String TAG =" "; public ActivityTwo() { arrayListDef = new ArrayList<>(); arrayListTerms = new ArrayList<>(); } @Override protected void onCreate(Bundle savedInstanceState) { try { InputStream myInputStream = this.getResources().openRawResource(R.raw.textfile); BufferedReader myBufferedReader = new BufferedReader(new InputStreamReader(myInputStream)); String str = myBufferedReader.readLine(); while((str != null)) { temp = str.split(","); arrayListTerms.add(temp[0]); arrayListDef.add(temp[1]); //qMatch.put(temp[1], temp[0]); } Log.i(TAG, "Textfile Loaded."); myBufferedReader.close(); } catch (FileNotFoundException ex) { Log.e(TAG, "Unable to open text file."); } catch (IOException ex){ Log.e(TAG, "Error reading text file."); } Collections.shuffle(arrayListDef); sizeOfArray = arrayListDef.size(); 暂停$scope.fileContents.push({ dCol: dRow }); 暂停。

寻找这个问题的非常彻底的答案和良好的优化实施。

0 个答案:

没有答案