用SurfaceView+MediaPlayer做的简单本地视频播放器
首先是VideoUtil 类
package com.example.myvideo;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.database.Cursor;
import android.provider.MediaStore;
public class VideoUtil {
//通过遍历数据库来获取视频的路径,时间,大小,
public static List<VideoInfo> getVideoInfos(Context context){
Cursor cursor = context.getContentResolver().
query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Video.Media._ID);//MediaStore.Video.Media._ID 通过ID来排序 当然也可以使用默认排序MediaStore.Video.Media.DEFAULT_SORT_ORDER
List<VideoInfo> videoinfos = new ArrayList<VideoInfo>();
for(int i = 0; i<cursor.getCount(); i++){
VideoInfo videoInfo = new VideoInfo();
cursor.moveToNext();
int id = i;
String title = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.TITLE));
String url = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA));
long time = cursor.getLong(cursor.getColumnIndex(MediaStore.Video.Media.DURATION));
videoInfo.setId(id);
videoInfo.setTitle(title);
videoInfo.setTime(time);
videoInfo.setUrl(url);
videoinfos.add(videoInfo);
}
cursor.close();//关闭数据库
return videoinfos;
}
/**
*把long格式的时间转化成00:00:00
*/
public static String millions2hour(int million) {
int hour = million / (60 * 60 * 1000);
int minute = (million - hour * 60 * 60 * 1000) / (60 * 1000);
int seconds = (million - hour * 60 * 60 * 1000 - minute * 60 * 1000) / 1000;
if (seconds >= 60) {
seconds = seconds % 60;
minute += seconds / 60;
}
if (minute >= 60) {
minute = minute % 60;
hour += minute / 60;
}
String sh = "";
String sm = "";
String ss = "";
if (hour < 10) {
sh = "0" + String.valueOf(hour);
} else {
sh = String.valueOf(hour);
}
if (minute < 10) {
sm = "0" + String.valueOf(minute);
} else {
sm = String.valueOf(minute);
}
if (seconds < 10) {
ss = "0" + String.valueOf(seconds);
} else {
ss = String.valueOf(seconds);
}
return sh + ":" + sm + ":" + ss;
}
}
VideoInfo类
这个类没什么好说的
package com.example.myvideo;
public class VideoInfo {
private int id;
private String title;
private long time;
private String url;
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
public String getTitle(){
return title;
}
public void setTitle(String title){
this.title = title;
}
public long getTime(){
return time;
}
public void setTime(long time){
this.time = time;
}
public String getUrl(){
return url;
}
public void setUrl(String url){
this.url = url;
}
}
MainActivity
关于快进快退我就没具体写了,使用mediaplay的getCurrentPosition()方法获得当前时间,然后在对当前时间进行加减计算,然后在通过mediaplay的seekTo()方法来设置
package com.example.myvideo;
import java.lang.ref.WeakReference;
import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener {
private SurfaceView video;
private VideoInfo videoInfo;
private MediaPlayer player;
private Button mPre, mPlayPause, mNext;
private SurfaceHolder holder;
private TextView mCurTime, mTime;
private SeekBar mSeekBar;
private LinearLayout mLayout;
MyHandler mHandler = new MyHandler(MainActivity.this);
CountTimeThread countTimeThread;
private int id = 0;
private int mCount;
String url;
int position;
Handler handler = new Handler() {
};
Runnable runnable = new Runnable() {
@Override
public void run() {
if (player.isPlaying()) {//当处于播放状态时
if (mSeekBar.isEnabled() == false) {//当seekbar不可用时
mSeekBar.setEnabled(true);//seekbar可用
}
position = player.getCurrentPosition();
String curtime = VideoUtil.millions2hour(position);
int alltime = (int) videoInfo.getTime();
String time = VideoUtil.millions2hour(alltime);
mTime.setText(time);
mCurTime.setText(curtime);
mSeekBar.setProgress(position);
mSeekBar.setMax(alltime);
}
handler.postDelayed(this, 1000);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);//隐藏标题栏
setContentView(R.layout.activity_main);
initView();
}
void initView() {
mCurTime = (TextView) findViewById(R.id.tv_curtime);
mTime = (TextView) findViewById(R.id.tv_time);
mCurTime.setText("00:00:00");
mTime.setText("00:00:00");
player = new MediaPlayer();
videoInfo = new VideoInfo();
mCount = VideoUtil.getVideoInfos(this).size();
video = (SurfaceView) findViewById(R.id.video);
mPre = (Button) findViewById(R.id.btn_pre);
mPlayPause = (Button) findViewById(R.id.btn_playpause);
mNext = (Button) findViewById(R.id.btn_next);
mLayout = (LinearLayout) findViewById(R.id.btn_bar);
mPre.setOnClickListener(this);
mNext.setOnClickListener(this);
mPlayPause.setOnClickListener(this);
video.setOnClickListener(this);
mSeekBar = (SeekBar) findViewById(R.id.progress);
SeekBarListener mListener = new SeekBarListener();
mSeekBar.setOnSeekBarChangeListener(mListener);
mSeekBar.setEnabled(false);//seekbar初始化时时不可拖动的
AutoPlay();
handler.postDelayed(runnable, 1000);
startCountTimeThread();//这是自动隐藏控件的线程
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_playpause:
if (!player.isPlaying()) {
if (position != 0) {//当播放时间不为0
videoPlay(id);
player.seekTo(position);//跳转到之前的播放时间
} else {
videoPlay(id);
}
} else if (player.isPlaying()) {
player.pause();
mSeekBar.setEnabled(false);
}
break;
case R.id.btn_pre:
if (id == 0) {
id = mCount - 1;
videoPlay(id);
} else {
id = id - 1;
videoPlay(id);
}
break;
case R.id.btn_next:
if (id == mCount - 1) {
id = 0;
videoPlay(0);
} else {
id = id + 1;
videoPlay(id);
}
break;
case R.id.video:
if (mLayout.isShown()) {
mLayout.setVisibility(View.GONE);
} else {
mLayout.setVisibility(View.VISIBLE);
}
break;
default:
break;
}
}
private void videoPlay(int id) {
try {
player.reset();
videoInfo = VideoUtil.getVideoInfos(this).get(id);
url = videoInfo.getUrl();
player.setDataSource(url);
holder = video.getHolder();
player.setDisplay(holder);
player.prepare();
player.start();
} catch (Exception e) {
e.printStackTrace();
}
}
//自动播放下一首
private void AutoPlay() {
player.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
if (id < mCount - 1) {
id = id + 1;
videoPlay(id);
player.start();
} else {
id = 0;
videoPlay(0);
player.start();
}
}
});
}
public class SeekBarListener implements OnSeekBarChangeListener {
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
if (fromUser == true && player.isPlaying()) {
//fromUser判断是否为用户自己操作
player.seekTo(progress);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
countTimeThread.reset();// 重置时间
if (event.getAction() == MotionEvent.ACTION_DOWN) {
boolean isVisible = mLayout.isShown();
if (!isVisible) {
mLayout.setVisibility(View.VISIBLE);
return true;
}
}
return super.onTouchEvent(event);
}
private void startCountTimeThread() {
countTimeThread = new CountTimeThread(5);
countTimeThread.start();
}
/**
* 隐藏需要隐藏的布局
*/
private void hide() {
if (mLayout.isShown()) {
//mLayout.isShown()判断控件是否在VISIBIL状态
mLayout.setVisibility(View.GONE);
}
}
/**
* Handler消息传递机制
*/
class MyHandler extends Handler {
// 发送消息的id
private final int MSG_HIDE = 0x001;
// WeakReference垃圾回收机制
private WeakReference<MainActivity> weakRef;
public MyHandler(MainActivity mMainActivity) {
weakRef = new WeakReference<MainActivity>(mMainActivity);
}
@Override
public void handleMessage(Message msg) {
final MainActivity mainActivity = weakRef.get();
if (mainActivity != null) {
switch (msg.what) {
case MSG_HIDE:
hide();
break;
}
}
super.handleMessage(msg);
}
/**
* 发送消息
*/
public void sendHideControllMessage() {
obtainMessage(MSG_HIDE).sendToTarget();
}
}
private class CountTimeThread extends Thread {
private final long maxVisibleTime;
private long startVisibleTime;
/**
* 设置控件显示时间 second单位是秒
* @param second
*/
public CountTimeThread(int second) {
maxVisibleTime = second * 1000;// 换算为毫秒
setDaemon(true);// 设置为后台进程
}
/**
* 如果用户有操作,则重新开始计时隐藏时间
*/
private synchronized void reset() {
startVisibleTime = System.currentTimeMillis();
}
@Override
public void run() {
startVisibleTime = System.currentTimeMillis();// 初始化开始时间
while (true) {
// 如果时间达到最大时间,则发送隐藏消息
if (startVisibleTime + maxVisibleTime < System.currentTimeMillis()) {
mHandler.sendHideControllMessage();
startVisibleTime = System.currentTimeMillis();
}
try {
Thread.sleep(1000);
} catch (Exception e) {
}
}
}
}
}
这是布局activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<SurfaceView
android:id="@+id/video"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:id="@+id/btn_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/tv_curtime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:textColor="@android:color/white"
android:textSize="24sp" />
<SeekBar
android:id="@+id/progress"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:maxHeight="10dp"
android:minHeight="10dp" />
<TextView
android:id="@+id/tv_time"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:textColor="@android:color/white"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center" >
<Button
android:id="@+id/btn_pre"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pre"
android:textColor="@android:color/white"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center" >
<Button
android:id="@+id/btn_playpause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/play"
android:textColor="@android:color/white"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center" >
<Button
android:id="@+id/btn_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/next"
android:textColor="@android:color/white"
android:textSize="24sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</FrameLayout>
记得加权限
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myvideo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="17"
android:targetSdkVersion="22" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>