Android播放远程非流MP4文件


由于Android自带的Mediaplayer类,只能播放本地或者远程流形式的MP4文件,所以在播放远程非流的MP4,而且MP4的moov数据在文件的末尾时,在下载时,需要我们在写文件时做特殊处理,这样才能实现下载一部分,播放一部视频,下面来看实现代码:
下载代码部分
public class Mp4DownloadUtils {/** 播放MP4消息 */private static final int PLAYER_MP4_MSG = 0x1001;/** 下载MP4完成 */private static final int DOWNLOAD_MP4_COMPLETION = 0x1002;/** 下载MP4失败 */private static final int DOWNLOAD_MP4_FAIL = 0x1003;/** * 下载MP4文件 * @param url * @param fileName * @param handler * @return */public static File downloadMp4File(final String url, final String fileName,final Handler handler) {final File mp4File = new File(fileName);downloadVideoToFile(url, mp4File, handler);return mp4File;}/** * 下载视频数据到文件 * @param url * @param dstFile * @param moovSize */private static void downloadVideoToFile(final String url, final File dstFile, final Handler handler) {Thread thread = new Thread() {@Overridepublic void run() {super.run();try {URL request = new URL(url);HttpURLConnection httpConn = (HttpURLConnection) request.openConnection();httpConn.setConnectTimeout(3000);httpConn.setDoInput(true);httpConn.setDoOutput(true);httpConn.setDefaultUseCaches(false);httpConn.setRequestMethod("GET");httpConn.setRequestProperty("Charset", "UTF-8");httpConn.setRequestProperty("Accept-Encoding", "identity");int responseCode = httpConn.getResponseCode();if ((responseCode == HttpURLConnection.HTTP_OK)) {// 获取文件总长度int totalLength = httpConn.getContentLength();InputStream is = httpConn.getInputStream();if (dstFile.exists()) {dstFile.delete();}dstFile.createNewFile();RandomAccessFile raf = new RandomAccessFile(dstFile, "rw");BufferedInputStream bis = new BufferedInputStream(is);int readSize = 0;int mdatSize = 0;// mp4的mdat长度int headSize = 0;// mp4头长度byte[] boxSizeBuf = new byte[4];byte[] boxTypeBuf = new byte[4];// 由MP4的文件格式读取int boxSize = readBoxSize(bis, boxSizeBuf);String boxType = readBoxType(bis, boxTypeBuf);raf.write(boxSizeBuf);raf.write(boxTypeBuf);while (!boxType.equalsIgnoreCase("moov")) {int count = boxSize - 8;if (boxType.equalsIgnoreCase("ftyp")) {headSize += boxSize;byte[] ftyps = new byte[count];bis.read(ftyps, 0, count);raf.write(ftyps, 0, count);} else if (boxType.equalsIgnoreCase("mdat")) {// 标记mdat数据流位置,在后面reset时读取bis.mark(totalLength - headSize);// 跳过mdat数据skip(bis, count);mdatSize = count;byte[] mdatBuf = new byte[mdatSize];raf.write(mdatBuf);} else if (boxType.equalsIgnoreCase("free")) {headSize += boxSize;}boxSize = readBoxSize(bis, boxSizeBuf);boxType = readBoxType(bis, boxTypeBuf);raf.write(boxSizeBuf);raf.write(boxTypeBuf);}// 读取moov数据byte[] buffer = new byte[4096];int moovSize = 0;while ((readSize = bis.read(buffer)) != -1) {moovSize += readSize;raf.write(buffer, 0, readSize);}// 返回到mdat数据开始bis.reset();// 设置文件指针偏移到mdat位置long offset = raf.getFilePointer() - moovSize - mdatSize - 8;raf.seek(offset);// 读取mdat数据,设置mp4初始mdat的缓存大小int buf_size = 56 * 1024;// 56kbint downloadCount = 0;boolean viable = false;while (mdatSize > 0) {readSize = bis.read(buffer);raf.write(buffer, 0, readSize);mdatSize -= readSize;downloadCount += readSize;if (handler != null && !viable && downloadCount >= buf_size) {viable = true;// 发送开始播放视频消息sendMessage(handler, PLAYER_MP4_MSG, null);}}// 发送下载消息if (handler != null) {sendMessage(handler, DOWNLOAD_MP4_COMPLETION, null);}bis.close();is.close();raf.close();httpConn.disconnect();}} catch (Exception e) {e.printStackTrace();sendMessage(handler, DOWNLOAD_MP4_FAIL, null);}}};thread.start();thread = null;}/** * 发送下载消息 * @param handler * @param what * @param obj */private static void sendMessage(Handler handler, int what, Object obj) {if (handler != null) {Message msg = new Message();msg.what = what;msg.obj = obj;handler.sendMessage(msg);}}/** * 跳转 * @param is * @param count 跳转长度 * @throws IOException */private static void skip(BufferedInputStream is, long count) throws IOException {while (count > 0) {long amt = is.skip(count);if (amt == -1) {throw new RuntimeException("inputStream skip exception");}count -= amt;}}/** * 读取mp4文件box大小 * @param is * @param buffer * @return */private  static int readBoxSize(InputStream is, byte[] buffer) {int sz = fill(is, buffer);if (sz == -1) {return 0;}return bytesToInt(buffer, 0, 4);}/** * 读取MP4文件box类型 * @param is * @param buffer * @return */private static String readBoxType(InputStream is, byte[] buffer) {fill(is, buffer);return byteToString(buffer);}/** * byte转换int * @param buffer * @param pos * @param bytes * @return */private static int bytesToInt(byte[] buffer, int pos, int bytes) {/* * int intvalue = (buffer[pos + 0] & 0xFF) << 24 | (buffer[pos + 1] & * 0xFF) << 16 | (buffer[pos + 2] & 0xFF) << 8 | buffer[pos + 3] & 0xFF; */int retval = 0;for (int i = 0; i < bytes; ++i) {retval |= (buffer[pos + i] & 0xFF) << (8 * (bytes - i - 1));}return retval;}/** * byte数据转换String * @param buffer * @return */private static String byteToString(byte[] buffer) {assert buffer.length == 4;String retval = new String();try {retval = new String(buffer, 0, buffer.length, "ascii");} catch (UnsupportedEncodingException e) {e.printStackTrace();}return retval;}private static int fill(InputStream stream, byte[] buffer) {return fill(stream, 0, buffer.length, buffer);}/** * 读取流数据 * @param stream * @param pos * @param len * @param buffer * @return */private static int fill(InputStream stream, int pos, int len, byte[] buffer) {int readSize = 0;try {readSize = stream.read(buffer, pos, len);if (readSize == -1) {return -1;}assert readSize == len : String.format("len %d readSize %d", len,readSize);} catch (IOException e) {e.printStackTrace();}return readSize;}}

播放器代码
public class VideoPlayerActivity extends Activity implements OnClickListener,OnSeekBarChangeListener, OnPreparedListener, OnCompletionListener, OnTouchListener {private String url = null;// 播放地址private SurfaceView surfaceView = null;private SurfaceHolder surfaceHolder = null;private MediaPlayer mediaPlayer = null;private SeekBar seekBar = null;// 播放进度条private Button playBtn = null;// 播放private Button pauseBtn = null;// 暂停private TextView tv_current = null;private TextView tv_duration = null;private TextView divideTxt = null;private RelativeLayout controlLayout = null;// 操控界面布局private RelativeLayout mediaPlayerLayout = null;private LayoutParams mediaLayoutParams = null;private LinearLayout loadPrgLayout = null;private boolean isPlay = false;// 播放状态private boolean isPause = false;private boolean isShow = true;private boolean isEnd = false;private boolean isStartPlayer = false;private boolean isCustomStyle = false;// 开启自定义seekBar样式private int mDuration = 0;private int mSeekBarMax = 0;private int currentPosition = 0;// 当前播放位置private File mDownloadMP4File = null;private MediaPlayerCallback mCallback = null;private static final int playBtnID = 0x001;// 播放按钮idprivate static final int pauseBtnID = 0x002;// 暂停按钮idprivate static final int btnLayoutID = 0x003;// 按钮布局层idprivate static final int clockLayoutID = 0x004;// 计时布局层idprivate static final int surfaceViewID = 0x005;// surfaceView id/** 分秒 */private static final String DateFormatMS = "mm:ss";private static final int UPDATE_PROGRESS_MSG = 0x011;// 更新进度条和计时private static final int SHOW_CONTROL_MSG = 0x012;// 显示控制private static final int COMPLETION_PLAY_MSG = 0x013;// 播放完成@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); // 全屏getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);// 测试视频地址url = "http://minisite.adsame.com/nodie/v2.mp4";String videoFileName = getRootPath() + getVideo(url);mDownloadMP4File = Mp4DownloadUtils.downloadMp4File(url, videoFileName, videoHandler);initPlayer();}/** * 获取外部存储根路径 * @return */private String getRootPath() {String rootPath = Environment.getExternalStorageDirectory().getAbsolutePath();return rootPath;}/** * 获取视频文件名字 * @param videoUrl * @return */private String getVideo(String videoUrl) {int startIndex = videoUrl.lastIndexOf("/");return url.substring(startIndex, videoUrl.length());}/** * 视频下载时的handler */private Handler videoHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {// 有MP4的mdat数据时,创建播放器case Mp4DownloadUtils.PLAYER_MP4_MSG:isStartPlayer = true;createMediaPlayer(mDownloadMP4File);break;case Mp4DownloadUtils.DOWNLOAD_MP4_COMPLETION:break;case Mp4DownloadUtils.DOWNLOAD_MP4_FAIL:break;default:break;}}};@SuppressWarnings("deprecation")private void initPlayer() {if (surfaceView == null) {surfaceView = new SurfaceView(this);surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// 不缓冲surfaceView.getHolder().setKeepScreenOn(true);// 保持屏幕高亮surfaceView.getHolder().addCallback(new SurfaceViewCallback());surfaceView.setId(surfaceViewID);surfaceView.setOnClickListener(this);surfaceView.setEnabled(false);surfaceHolder = surfaceView.getHolder();}initPlayerButton();RelativeLayout btnLayout = new RelativeLayout(this);btnLayout.setId(btnLayoutID);btnLayout.setGravity(Gravity.CENTER);LayoutParams btnParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);btnParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);btnParams.addRule(RelativeLayout.CENTER_VERTICAL);btnLayout.setLayoutParams(btnParams);btnLayout.addView(playBtn);btnLayout.addView(pauseBtn);initClockTextView();LinearLayout clockLayout = new LinearLayout(this);clockLayout.setId(clockLayoutID);clockLayout.setOrientation(LinearLayout.HORIZONTAL);LayoutParams clockTVLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);clockTVLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);clockTVLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL);clockLayout.setLayoutParams(clockTVLayoutParams);clockLayout.addView(tv_duration);clockLayout.addView(divideTxt);clockLayout.addView(tv_current);// 进度条必须在btnLayout和prgLayout后面initProgressSeekBar();// 下载进度initProgressBar();controlLayout = new RelativeLayout(this);LayoutParams rlParams = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT);rlParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);int marginLeft = 5;int marginRight = 5;rlParams.setMargins(marginLeft, 0, marginRight, 0);controlLayout.setLayoutParams(rlParams);controlLayout.setVisibility(View.GONE);controlLayout.setBackgroundColor(Color.GRAY);controlLayout.addView(btnLayout);controlLayout.addView(seekBar);controlLayout.addView(clockLayout);setViewDrawableStyle();mediaPlayerLayout = new RelativeLayout(this);mediaLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);mediaLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);mediaPlayerLayout.setLayoutParams(mediaLayoutParams);mediaPlayerLayout.addView(surfaceView);mediaPlayerLayout.addView(controlLayout);mediaPlayerLayout.addView(loadPrgLayout);RelativeLayout layout = new RelativeLayout(this);layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));layout.addView(mediaPlayerLayout);setContentView(layout);}private void initPlayerButton() {int btnWidth = 60;int btnHeight = 60;// 开始按钮playBtn = new Button(this);playBtn.setId(playBtnID);playBtn.setOnClickListener(this);LayoutParams playParams = new LayoutParams(btnWidth, btnHeight);playBtn.setLayoutParams(playParams);playBtn.setEnabled(false);// 暂停按钮pauseBtn = new Button(this);pauseBtn.setId(pauseBtnID);pauseBtn.setOnClickListener(this);LayoutParams pauseParams = new LayoutParams(btnWidth, btnHeight);pauseBtn.setLayoutParams(pauseParams);pauseBtn.setVisibility(View.GONE);}private void initClockTextView() {// 播放进度tv_current = new TextView(this);tv_current.setTextColor(Color.WHITE);tv_current.setText(getStringByFormat(currentPosition, DateFormatMS));// 播放持续时间tv_duration = new TextView(this);tv_duration.setTextColor(Color.WHITE);tv_duration.setText(getStringByFormat(mDuration, DateFormatMS));// 分隔线divideTxt = new TextView(this);divideTxt.setText("/");divideTxt.setTextColor(Color.WHITE);}private void initProgressSeekBar() {// 播放进度条seekBar = new SeekBar(this);seekBar.setOnSeekBarChangeListener(this);LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT);params.addRule(RelativeLayout.RIGHT_OF, btnLayoutID);params.addRule(RelativeLayout.LEFT_OF, clockLayoutID);params.addRule(RelativeLayout.CENTER_VERTICAL);int leftpadding = 15;int rightpadding = 15;seekBar.setLayoutParams(params);seekBar.setPadding(leftpadding, 0, rightpadding, 0);seekBar.setOnTouchListener(this);}private void initProgressBar() {LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);loadPrgLayout = new LinearLayout(this);loadPrgLayout.setLayoutParams(layoutParams);loadPrgLayout.setOrientation(LinearLayout.VERTICAL);loadPrgLayout.setVisibility(View.VISIBLE);loadPrgLayout.setGravity(Gravity.CENTER);LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);ProgressBar loadPrgBar = new ProgressBar(this);loadPrgBar.setLayoutParams(params);loadPrgLayout.addView(loadPrgBar);}/** * 设置view的样式 */private void setViewDrawableStyle() {try {// setBackground报错需要Android版本号在16以上playBtn.setBackground(createSelectorDrawable(getAssetDrawable(this, "btn_play_normal.png"),getAssetDrawable(this, "btn_play_pressed.png")));pauseBtn.setBackground(createSelectorDrawable(getAssetDrawable(this, "btn_pause_normal.png"),getAssetDrawable(this, "btn_pause_pressed.png")));if (isCustomStyle) {seekBar.setThumb(createSeekbarThumbDrawable(getAssetDrawable(this, "progress_thumb_normal.png"),getAssetDrawable(this, "progress_thumb_pressed.png")));seekBar.setProgressDrawable(createSeekbarProgressDrawable(getAssetDrawable(this, "progress_bg.png"),getAssetDrawable(this, "progress_secondary.png"), getAssetDrawable(this, "progress.png")));controlLayout.setBackground(getAssetDrawable(this, "ctrl_layout_bg.png"));}} catch (Exception e) {e.printStackTrace();}}/** * 获取accets目录下的图片 * @param context * @param imageName * @return * @throws IOException */public Drawable getAssetDrawable(Context context, String imageName) throws IOException {return BitmapDrawable.createFromStream(context.getAssets().open(imageName), imageName);}/** * 创建图片选择器 * @param normal * @param pressed * @return */private Drawable createSelectorDrawable(Drawable normal, Drawable pressed) {StateListDrawable drawable = new StateListDrawable();drawable.addState(new int[] { android.R.attr.state_focused },normal);drawable.addState(new int[] { android.R.attr.state_pressed },pressed);drawable.addState(new int[] {}, normal);return drawable;}/** * 创建seekBar拖动点样式图 *  * @param normal *            正常 * @param pressed *            下压 * @return */private Drawable createSeekbarThumbDrawable(Drawable normal, Drawable pressed) {StateListDrawable drawable = new StateListDrawable();drawable.addState(new int[] { android.R.attr.state_pressed }, pressed);drawable.addState(new int[] { android.R.attr.state_focused }, normal);drawable.addState(new int[] {}, normal);return drawable;}/** * 创建seekBar进度样式图 *  * @param background *            背景图 * @param secondaryProgress *            第二进度能量图 * @param progress *            进度能量图 * @return */private Drawable createSeekbarProgressDrawable(Drawable background,Drawable secondaryProgress, Drawable progress) {LayerDrawable progressDrawable = (LayerDrawable) seekBar.getProgressDrawable();int itmeSize = progressDrawable.getNumberOfLayers();Drawable[] outDrawables = new Drawable[itmeSize];for (int i = 0; i < itmeSize; i++) {switch (progressDrawable.getId(i)) {case android.R.id.background:// 设置进度条背景outDrawables[i] = background;break;case android.R.id.secondaryProgress:// 设置二级进度条outDrawables[i] = secondaryProgress;break;case android.R.id.progress:// 设置进度条ClipDrawable oidDrawable = (ClipDrawable) progressDrawable.getDrawable(i);Drawable drawable = progress;ClipDrawable proDrawable = new ClipDrawable(drawable,Gravity.LEFT, ClipDrawable.HORIZONTAL);proDrawable.setLevel(oidDrawable.getLevel());outDrawables[i] = proDrawable;break;default:break;}}progressDrawable = new LayerDrawable(outDrawables);return progressDrawable;}private class SurfaceViewCallback implementsandroid.view.SurfaceHolder.Callback {@Overridepublic void surfaceCreated(SurfaceHolder holder) {createMediaPlayer();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {destroy();}}private void createMediaPlayer() {createMediaPlayer(null);}private void createMediaPlayer(File videoFile) {if (url == null && videoFile == null && !isStartPlayer) {return;}if (mediaPlayer == null) {mediaPlayer = new MediaPlayer();}mediaPlayer.reset();mediaPlayer.setOnCompletionListener(this);mediaPlayer.setOnPreparedListener(this);// 设置监听事件mediaPlayer.setDisplay(surfaceHolder);// 把视频显示到surfaceView上if (videoFile != null) {setDataSource(videoFile);} else {setDataSource(url);}mediaPlayer.prepareAsync();// 准备播放}private void setDataSource(String src) {try {if (src.startsWith("http://")) {mediaPlayer.setDataSource(this, Uri.parse(src));} else {setDataSource(new File(src));}} catch (IOException e) {e.printStackTrace();}}private void setDataSource(File file) {try {FileInputStream fis = new FileInputStream(file);mediaPlayer.setDataSource(fis.getFD());// 设置播放路径fis.close();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void onPrepared(MediaPlayer mp) {if (isPause) {} else {mediaPlayer.start();playBtn.setEnabled(true);playBtn.setVisibility(View.GONE);pauseBtn.setVisibility(View.VISIBLE);if (currentPosition > 0) {mediaPlayer.seekTo(currentPosition);}}loadPrgLayout.setVisibility(View.GONE);controlLayout.setVisibility(View.VISIBLE);surfaceView.setEnabled(true);mHandler.post(showControlRunnable);mHandler.post(updateProgressRunnable);if (mSeekBarMax == 0 || mDuration == 0) {mSeekBarMax = seekBar.getMax();mDuration = mediaPlayer.getDuration();mediaPlayerLayout.setMinimumHeight(520);mediaPlayerLayout.invalidate();}}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {removeHandlerTask();}@Overridepublic void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {if (fromUser) {int milliseconds = countPosition(progress);tv_current.setText(getStringByFormat(milliseconds, DateFormatMS));}}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {if (mediaPlayer != null) {currentPosition = countPosition(seekBar.getProgress());mediaPlayer.seekTo(currentPosition);restartHandlerTack();}}private void start() {if (mediaPlayer != null && isPause) {isPlay = true;isPause = false;if (currentPosition > 0) {mediaPlayer.seekTo(currentPosition);}mediaPlayer.start();restartHandlerTack();playBtn.setVisibility(View.GONE);pauseBtn.setVisibility(View.VISIBLE);}}private void pause() {if (mediaPlayer != null && mediaPlayer.isPlaying()) {isPlay = false;isPause = true;mediaPlayer.pause();playBtn.setVisibility(View.VISIBLE);pauseBtn.setVisibility(View.GONE);controlLayout.setVisibility(View.VISIBLE);currentPosition = mediaPlayer.getCurrentPosition();removeHandlerTask();}}private void destroy() {if (mediaPlayer != null && isPlay) {mediaPlayer.pause();controlLayout.setVisibility(View.VISIBLE);currentPosition = mediaPlayer.getCurrentPosition();removeHandlerTask();}}@Overridepublic void onClick(View v) {switch (v.getId()) {case playBtnID:// 播放if (mediaPlayer == null) {createMediaPlayer();} else {start();}break;case pauseBtnID:// 暂停pause();break;case surfaceViewID:// 先移除任务,如果显示,重新post一次任务mHandler.removeCallbacks(showControlRunnable);if (isShow) {controlLayout.setVisibility(View.GONE);isShow = false;} else {controlLayout.setVisibility(View.VISIBLE);isShow = true;mHandler.postDelayed(showControlRunnable, 5000);}break;default:break;}}@Overridepublic boolean onTouch(View v, MotionEvent event) {if (v == seekBar && isEnd) {return true;}return false;}@Overridepublic void onDetachedFromWindow() {super.onDetachedFromWindow();}@Overridepublic void onCompletion(MediaPlayer mp) {// 完成播放try {isEnd = true;isPlay = false;seekBar.setProgress(countProgress(mDuration));tv_current.setText(getStringByFormat(mDuration, DateFormatMS));playBtn.setVisibility(View.VISIBLE);pauseBtn.setVisibility(View.GONE);controlLayout.setVisibility(View.VISIBLE);playBtn.setEnabled(false);removeHandlerTask();mHandler.sendEmptyMessageDelayed(COMPLETION_PLAY_MSG, 500);} catch (Exception e) {e.printStackTrace();}}public interface MediaPlayerCallback {public void onCompletion();}public void setMediaPlayerCallback(MediaPlayerCallback callback) {mCallback = callback;}private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case UPDATE_PROGRESS_MSG:// 更新播放进度和计时器if (mediaPlayer != null && mediaPlayer.isPlaying()) {isPlay = true;currentPosition = mediaPlayer.getCurrentPosition();seekBar.setProgress(countProgress(currentPosition));tv_current.setText(getStringByFormat(currentPosition, DateFormatMS));tv_duration.setText(getStringByFormat(mDuration, DateFormatMS));}break;case SHOW_CONTROL_MSG:// 显示播放控制控件if (isPlay) {isShow = false;controlLayout.setVisibility(View.GONE);mHandler.removeCallbacks(showControlRunnable);} else {isShow = true;controlLayout.setVisibility(View.VISIBLE);}break;case COMPLETION_PLAY_MSG:// 完成播放finish();if (mCallback != null) {mCallback.onCompletion();}Settings.System.getInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0);break;default:break;}}};/** * 重新启动任务 */private void restartHandlerTack() {mHandler.post(updateProgressRunnable);mHandler.postDelayed(showControlRunnable, 5000);}/** * 移除任务 */private void removeHandlerTask() {mHandler.removeCallbacks(showControlRunnable);mHandler.removeCallbacks(updateProgressRunnable);}/** * 更新进度条线程 */private Runnable updateProgressRunnable = new Runnable() {@Overridepublic void run() {mHandler.sendEmptyMessage(UPDATE_PROGRESS_MSG);mHandler.postDelayed(updateProgressRunnable, 1000);}};/** * 显示控制线程 */private Runnable showControlRunnable = new Runnable() {@Overridepublic void run() {mHandler.sendEmptyMessage(SHOW_CONTROL_MSG);mHandler.postDelayed(showControlRunnable, 5000);}};/** * 计算播放进度 *  * @param position * @return */private int countProgress(int position) {if (mDuration == 0) {return 0;}return position * mSeekBarMax / mDuration;}/** * 计算播放位置 *  * @param progress * @return */private int countPosition(int progress) {if (mSeekBarMax == 0) {return 0;}return progress * mDuration / mSeekBarMax;}/** * 描述:获取milliseconds表示的日期时间的字符串. *  * @param milliseconds * @param format *            格式化字符串,如:"yyyy-MM-dd HH:mm:ss" * @return String 日期时间字符串 */private String getStringByFormat(long milliseconds, String format) {String thisDateTime = null;try {SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat(format);mSimpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT+0"));thisDateTime = mSimpleDateFormat.format(milliseconds);} catch (Exception e) {e.printStackTrace();}return thisDateTime;}@Overrideprotected void onDestroy() {super.onDestroy();if (mediaPlayer != null) {mediaPlayer.stop();mediaPlayer.release();mediaPlayer = null;currentPosition = 0;}System.gc();}}

需要加的权限
<uses-permission android:name="android.permission.INTERNET" />




更多相关文章

  1. android apk安装原理分析
  2. 深入理解:Android(安卓)编译系统
  3. Android(安卓)4.4.2插入exFAT格式U盘识别及加载的解决方案
  4. Android(安卓)设备root 原理及方法
  5. 日积月累--exception记录
  6. Android使用JNI实现Java与C之间传递数据
  7. mybatisplus的坑 insert标签insert into select无参数问题的解决
  8. python起点网月票榜字体反爬案例
  9. NPM 和webpack 的基础使用

随机推荐

  1. 安卓UI四种基本布局-线性布局
  2. 如何在项目中封装 Kotlin + Android(安卓
  3. Android多触点总结
  4. Android(安卓)Emulator UnknownHostExcep
  5. Android(安卓)碎碎念
  6. 盒模型居中及水平垂直
  7. Tinker热修复简单接入
  8. Android(安卓)属性动画 详解
  9. Android(安卓)WIFI状态监控
  10. Android(安卓)VideoView本地视频播放