标签:
最近项目中要用到视频播放器,就先写了个Demo,在写的过程中遇到些问题,来和大家分享一下:
1.Demo是基于Android电视的,因此与Android手机有点区别,但问题不大
2.MediaPlayer有个Bug,当视频播放完后getDuration(获取视频总时间)和getCurrentPosition(获取视频当前播放时间)方法获取到的数字不一样,相差300ms左右,如果单纯的播放不受影响,但是如果需要显示播放进度或播放时间就会有点小麻烦,暂时还没找到好的方法,只能在视频播放结束时处理时间,如果你们有好的方法也可以交流一下。
3.项目要实现显示当前时间的TextView与进度条同步移动,界面添加一个ViewGroup,然后在ViewGroup中放置TextView,通过TextView的Layout方法就能实现TextView的同步移动。
代码的解析挺详细,下面我就直接粘代码:
主Activity:
import java.io.IOException; import java.text.SimpleDateFormat; import java.util.TimeZone; import java.util.Timer; import java.util.TimerTask; import com.example.play.R; import com.luluvideo.view.TextMoveLayout; import android.app.Activity; import android.content.Intent; import android.content.res.AssetManager; import android.graphics.Color; import android.graphics.Typeface; import android.media.AudioManager; import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; import android.view.Window; import android.view.WindowManager; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; public class MainActivity extends Activity implements OnClickListener { private SurfaceView videoSurfaceView;// 视频播放器 private MediaPlayer mediaPlayer;// 视频播放控制器 private ImageView videoStart;// 播放 private ImageView videoForward;// 快进 private ImageView videoBack;// 快退 private ImageView videoReport;// 举报视频 private LinearLayout seekLayout; private LinearLayout videoProgress; private ProgressBar progressBar;// 视频进度条 private TextView totalTime;// 播放总时间 private View view;// 记忆获取焦点控件 private TextView movieName;// 电影名字 private TextView currentTime;// 当前播放时间 private ViewGroup.LayoutParams layoutParams; private TextMoveLayout textMoveLayout;// 放置当前时间控件的ViewGroup private int screenWidth;// 屏幕宽度 private Typeface roboto;// 自定义Roboto字体 private float moveStep = 0;// 当前时间控件移动步长 private SimpleDateFormat formatter;// 转换时间格式的类 private SimpleDateFormat hourFormatter; private boolean isPlaying = true;// 视频播放状态标识 private boolean isVisible = false;// 视频进度条隐藏或显示标识 private boolean hourOrMin = false; private boolean threadRunning = true; private int postion = 0; private String uri = null; private AlphaAnimation animation_appear;// 进度条显现动画 private AlphaAnimation animation_daiappear;// 进度条消失动画 private float progressLength = 0;// 进度条相对长度 private Thread thread = null; private MyTimerTask task; public static int PROGRESS_VISUBLE = 0; public static int PROGRESS_RATE = 1; public int i = 0; private Timer timer; /** * 刷新进度条和当前时间 */ private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == PROGRESS_RATE) { // 显示进度条 progressBar.setProgress((Integer) msg.obj); // 设置当前时间 currentTime.layout((int) ((Integer) msg.obj * moveStep), 0, (int) (screenWidth), 80); if (hourOrMin) { currentTime .setText(hourFormatter.format((Integer) msg.obj)); } else { currentTime.setText(formatter.format((Integer) msg.obj)); } } else if (msg.what == PROGRESS_VISUBLE) { Log.e("timer", msg.obj + ""); if ((Integer) msg.obj == 4) { view = getCurrentFocus(); // videoProgress // .setAnimation(animationAppear(animation_appear)); // videoProgress.setVisibility(View.GONE); seekLayout.setAnimation(animationAppear(animation_appear)); seekLayout.setVisibility(View.GONE); isVisible = false; timer.cancel(); } } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // 全屏 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // 应用运行时,保持屏幕高亮,不锁屏 initData(); initView(); getparams(); movieName.setText("大圣归来"); } private void getparams() { // TODO Auto-generated method stub Intent intent = getIntent(); } private void initData() { // TODO Auto-generated method stub screenWidth = getWindowManager().getDefaultDisplay().getWidth(); progressLength = (float) (screenWidth * 0.625); formatter = new SimpleDateFormat("mm:ss");// 初始化Formatter的转换格式。 formatter.setTimeZone(TimeZone.getTimeZone("GMT+00:00")); hourFormatter = new SimpleDateFormat("HH:mm:ss");// 初始化Formatter的转换格式。 hourFormatter.setTimeZone(TimeZone.getTimeZone("GMT+00:00")); mediaPlayer = new MediaPlayer(); layoutParams = new ViewGroup.LayoutParams((int) (screenWidth), 20); uri = "android.resource://" + getPackageName() + "/" + R.raw.test; AssetManager mgr = getAssets();// 得到AssetManager roboto = Typeface.createFromAsset(mgr, "fonts/roboto.ttf");// 根据路径得到Typeface isPlaying = true; isVisible = false; hourOrMin = false; threadRunning = true; } private void initView() { videoSurfaceView = (SurfaceView) findViewById(R.id.videoSurfaceView); videoSurfaceView.getHolder().setKeepScreenOn(true); videoSurfaceView.getHolder().addCallback(new SurfaceViewVideo()); currentTime = new TextView(this); currentTime.setTextColor(Color.rgb(255, 255, 255)); currentTime.setTextSize(12); currentTime.setTypeface(roboto); videoProgress = (LinearLayout) findViewById(R.id.vedioProgress); videoStart = (ImageView) videoProgress.findViewById(R.id.videoStart); videoForward = (ImageView) videoProgress .findViewById(R.id.videoForward); videoBack = (ImageView) videoProgress.findViewById(R.id.videoBack); videoReport = (ImageView) videoProgress.findViewById(R.id.videoReqort); progressBar = (ProgressBar) videoProgress .findViewById(R.id.videoProgress); totalTime = (TextView) videoProgress.findViewById(R.id.videoTotal); movieName = (TextView) findViewById(R.id.movieName); seekLayout = (LinearLayout) findViewById(R.id.seekLayout); movieName.setTypeface(roboto); totalTime.setTypeface(roboto); videoStart.setFocusable(true); videoStart.requestFocus(); videoStart.setOnClickListener(this); videoForward.setFocusable(true); videoForward.setOnClickListener(this); videoBack.setFocusable(true); videoBack.setOnClickListener(this); videoReport.setFocusable(true); videoReport.setOnClickListener(this); videoProgress.findViewById(R.id.videoForward).setOnClickListener(this); videoProgress.findViewById(R.id.videoBack).setOnClickListener(this); videoProgress.findViewById(R.id.videoReqort).setOnClickListener(this); textMoveLayout = (TextMoveLayout) videoProgress .findViewById(R.id.videoCurrent); textMoveLayout.addView(currentTime, layoutParams); currentTime.layout(0, 0, (int) (screenWidth), 80); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } /** * 设置播放文件 */ public void play() throws IllegalArgumentException, SecurityException, IllegalStateException, IOException { mediaPlayer.reset(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setDataSource(MainActivity.this, Uri.parse(uri)); // 把视频输出到SurfaceView上 mediaPlayer.setDisplay(videoSurfaceView.getHolder()); mediaPlayer.prepare(); mediaPlayer.start(); progressBar.setMax(mediaPlayer.getDuration()); moveStep = (float) ((progressLength / (float) mediaPlayer.getDuration())); // 开启进度刷新线程 thread = new Thread(runnable); thread.start(); } private Animation animationAppear(Animation animation) { animation = new AlphaAnimation(1.0f, 0.0f); animation.setDuration(1000); animation.setFillAfter(true); return animation; } private Animation animationDiaappear(Animation animation) { animation = new AlphaAnimation(0.0f, 1.0f); animation.setDuration(1000); animation.setFillAfter(true); return animation; } /* * SurfaceHolder可以调用 SurfaceView播放视频 */ private class SurfaceViewVideo implements SurfaceHolder.Callback { @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { if (postion == 0) { try { play(); mediaPlayer.seekTo(postion); if (mediaPlayer.getDuration() >= 3600000) { totalTime.setText(hourFormatter.format(mediaPlayer .getDuration())); hourOrMin = true; } else { totalTime.setText(formatter.format(mediaPlayer .getDuration())); hourOrMin = false; } // totalTime.setText(formatter.format(3600000)); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } @Override public void surfaceDestroyed(SurfaceHolder holder) { } } @Override protected void onPause() { if (mediaPlayer.isPlaying()) { // 保存当前播放的位置 postion = mediaPlayer.getCurrentPosition(); mediaPlayer.stop(); } super.onPause(); } @Override protected void onDestroy() { if (thread != null) { threadRunning = false; thread = null; } if (mediaPlayer.isPlaying()) { mediaPlayer.stop(); } mediaPlayer.release(); super.onDestroy(); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.videoForward: mediaGo(); break; case R.id.videoBack: mediaBack(); break; case R.id.videoStart: mediaPlay(); break; case R.id.videoReqort: mediaReport(); break; default: break; } } // 视频快进 private void mediaGo() { } // 视频快退 private void mediaBack() { } // 视频举报 private void mediaReport() { } private void startTimer() { i = 0; if (timer != null) { if (task != null) { task.cancel(); // 将原任务从队列中移除 timer.cancel(); } } task = new MyTimerTask(); // 新建一个任务 timer = new Timer(true); timer.schedule(task, 1000, 1000); // 延时1000ms后执行,1000ms执行一次 } // 视频播放 private void mediaPlay() { if (isPlaying) { mediaPlayer.pause(); videoStart.setImageResource(R.drawable.video_pause_style); isPlaying = false; } else { mediaPlayer.start(); videoStart.setImageResource(R.drawable.video_start_style); isPlaying = true; } } // 定义遥控按键 @Override public boolean dispatchKeyEvent(KeyEvent event) { // TODO Auto-generated method stub if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN && isVisible) { view = getCurrentFocus(); seekLayout.setAnimation(animationAppear(animation_appear)); isVisible = false; seekLayout.setVisibility(View.GONE); if (timer != null) { if (task != null) { task.cancel(); // 将原任务从队列中移除 timer.cancel(); } } return true; } else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN && event.getAction() == KeyEvent.ACTION_DOWN && !isVisible) { if (view != null) { view.setFocusable(true); view.requestFocus(); } seekLayout.setAnimation(animationDiaappear(animation_daiappear)); isVisible = true; seekLayout.setVisibility(View.VISIBLE); startTimer(); return true; } else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT && event.getAction() == KeyEvent.ACTION_DOWN && isVisible) { startTimer(); } else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT && event.getAction() == KeyEvent.ACTION_DOWN && isVisible) { startTimer(); } return super.dispatchKeyEvent(event); } /** * */ private Runnable runnable = new Runnable() { @Override public void run() { while (threadRunning && mediaPlayer.getCurrentPosition() < mediaPlayer .getDuration()) { Message msg = handler.obtainMessage(); msg.what = PROGRESS_RATE; msg.obj = mediaPlayer.getCurrentPosition(); Log.e("currentPosition", mediaPlayer.getCurrentPosition() + ""); handler.sendMessage(msg); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; class MyTimerTask extends TimerTask { @Override public void run() { Message message = new Message(); message.what = PROGRESS_VISUBLE; message.obj = ++i; handler.sendMessage(message); } } }自定义的ViewGroup:
import android.content.Context; import android.util.AttributeSet; import android.view.ViewGroup; /** * * @author YiWei * TextMoveLayout用来放置显示时间的TextView,从而实现时间随进度条移动 * */ public class TextMoveLayout extends ViewGroup { public TextMoveLayout(Context context) { super(context); } public TextMoveLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public TextMoveLayout(Context context, AttributeSet attrs) { super(context, attrs); } /** * onLayout用来布局子控件,实时调用onLayout就可以改变子布局位置 */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { } }
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <SurfaceView android:id="@+id/videoSurfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:id="@+id/seekLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom|center_horizontal" android:orientation="vertical" android:visibility="visible"> <TextView android:id="@+id/movieName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/movie_name_bottom" android:layout_marginLeft="@dimen/movie_name_left" android:textColor="@color/movie_name_color" android:textSize="@dimen/movie_name_size" android:shadowColor="@color/movie_name_back" android:shadowDx="4" android:shadowDy="4" android:shadowRadius="2"/> <include android:id="@+id/vedioProgress" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/progress_bottom" android:layout_marginLeft="@dimen/movie_name_left" android:layout_marginRight="@dimen/progress_right" layout="@layout/video_progress_layout" android:background="@color/progress_back" /> </LinearLayout> </FrameLayout>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:background="@color/progress_back" android:orientation="horizontal" android:weightSum="1668" > <ImageView android:id="@+id/videoBack" android:layout_width="@dimen/video_start_width" android:layout_height="wrap_content" android:layout_marginTop="@dimen/video_start_top" android:layout_weight="60" android:src="@drawable/video_back_style" /> <ImageView android:id="@+id/videoStart" android:layout_width="@dimen/video_start_width" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/video_start_left" android:layout_marginTop="@dimen/video_start_top" android:layout_weight="60" android:src="@drawable/video_start_style" /> <ImageView android:id="@+id/videoForward" android:layout_width="@dimen/video_start_width" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/video_start_left" android:layout_marginTop="@dimen/video_start_top" android:layout_weight="60" android:src="@drawable/video_forward_style" /> <ImageView android:id="@+id/videoReqort" android:layout_width="@dimen/video_start_width" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/video_start_left" android:layout_marginTop="@dimen/video_start_top" android:layout_weight="60" android:src="@drawable/video_report_style" /> <LinearLayout android:layout_width="@dimen/video_start_width" android:layout_height="wrap_content" android:layout_weight="1268" android:orientation="vertical" > <com.luluvideo.view.TextMoveLayout android:id="@+id/videoCurrent" android:layout_width="match_parent" android:layout_height="@dimen/text_move_height" /> <ProgressBar android:id="@+id/videoProgress" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="@dimen/progressbar_height" android:layout_marginLeft="@dimen/progressbar_left" android:layout_marginRight="@dimen/progressbar_right" android:layout_marginTop="@dimen/progressbar_top" android:max="100" android:progressDrawable="@drawable/video_progress_style" /> </LinearLayout> <TextView android:id="@+id/videoTotal" android:layout_width="@dimen/video_start_width" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="@dimen/video_total_time_left" android:layout_marginTop="@dimen/video_total_time_top" android:layout_weight="100" android:textColor="#ffffff" android:textSize="@dimen/video_total_time_size"/> </LinearLayout>
版权声明:本文为博主原创文章,未经博主允许不得转载。
MediaPlayer+surfaceView实现视频播放器
标签:
原文地址:http://blog.csdn.net/beefandpotatoes/article/details/47614239