首页 > 代码库 > Android视频播放1

Android视频播放1

为何那么决绝?不给我喘气的机会。

突然就想搞一下视频播放,就查了一下资料。网上大牛真多,都讲的很详细。我就纵览细品了一下大牛们的代码。然后就随心写了一个综合的小例子。

其中涉及到:视频播放,文件选择等。用的重点内容:MediaPlayer SurfaceView SurfaceHolder VideoView 除此之外还有最基本的:Activity/Intent/Toast/Dialog/Menu等等。比较适合有一定基础的菜鸟。大鸟可选择性飞过。代码比较多。亲测。


一、视频播放的三种方法

第一种:调用系统的视频播放器

            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(uri, "video/mp4");
            startActivity(intent);

第二种:使用VideoView控件

            videoView.setMediaController(new MediaController(MainActivity.this));
            videoView.setVideoURI(uri);
            videoView.start();
            videoView.requestFocus();

第三种:使用MediaPlayer和SurfaceView自定义播放

           MediaPlayer player = new MediaPlayer();


二、具体实现

这里我有两个Activity分别为:MainActivity和CustomActivity其中MainActivity用于控件的播放CustomActivity用于自定义的播放

还有一个CallbackBundle接口和自定义的OpenFileDialog类,这两个类用于弹出一个对话框让用户选择视频文件

注:CallbackBundle和OpenFileDialog是从RobinTang大牛(http://blog.csdn.net/trbbadboy/article/details/7899424)哪里拿来用的,写的真是太好了,所以一点没改直接用。太感谢大牛了。

上代码:

MainActivity.java

package com.study.myshipin;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.MediaController;
import android.widget.Toast;
import android.widget.VideoView;

public class MainActivity extends Activity {
	private VideoView videoView = null;
	private Uri uri = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		uri = Uri.parse(Environment.getExternalStorageDirectory().getPath()
				+ "/test.mp4");
		videoView = (VideoView) findViewById(R.id.videoView1);
		Toast.makeText(MainActivity.this, "请在菜单里操作", Toast.LENGTH_LONG).show();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// TODO Auto-generated method stub
		menu.add(0, 1, 1, "控件播放");
		menu.add(0, 2, 2, "调用系统");
		menu.add(0, 3, 3, "自己定义");
		menu.add(0, 4, 5, "退出系统");
		return super.onCreateOptionsMenu(menu);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// TODO Auto-generated method stub
		if (item.getItemId() == 1) {
			videoView
					.setMediaController(new MediaController(MainActivity.this));
			videoView.setVideoURI(uri);
			videoView.start();
			videoView.requestFocus();
		} else if (item.getItemId() == 2) {
			Intent intent = new Intent(Intent.ACTION_VIEW);
			intent.setDataAndType(uri, "video/mp4");
			startActivity(intent);
		} else if (item.getItemId() == 3) {
			Intent intent = new Intent();
			intent.setClass(MainActivity.this, CustomActivity.class);
			startActivity(intent);
		} else if (item.getItemId() == 4) {
			finish();
		}
		return super.onOptionsItemSelected(item);
	}

}
CustomActivity.java
package com.study.myshipin;

import java.util.HashMap;
import java.util.Map;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnErrorListener;
import android.os.Bundle;
import android.os.Environment;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.EditText;
import android.widget.Toast;

public class CustomActivity extends Activity implements SurfaceHolder.Callback {
	private SurfaceView surfaceView = null;
	private MediaPlayer player = null;
	private SurfaceHolder holder = null;
	private String path = null;
	private static final int OPEN_FILE_DIALOG_ID = 0;

	@Override
	@Deprecated
	protected Dialog onCreateDialog(int id) {
		// TODO Auto-generated method stub
		if (id == OPEN_FILE_DIALOG_ID) {
			Map<String, Integer> images = new HashMap<String, Integer>();
			// 下面几句设置各文件类型的图标, 需要你先把图标添加到资源文件夹
			images.put(OpenFileDialog.sRoot, R.drawable.filedialog_root); // 根目录图标
			images.put(OpenFileDialog.sParent, R.drawable.filedialog_folder_up); // 返回上一层的图标
			images.put(OpenFileDialog.sFolder, R.drawable.filedialog_folder); // 文件夹图标
			images.put("mp4", R.drawable.filedialog_videofile); // video文件图标
			images.put("mp3", R.drawable.filedialog_wavfile); // wav文件图标
			images.put(OpenFileDialog.sEmpty, R.drawable.filedialog_root);
			Dialog dialog = OpenFileDialog.createDialog(id, this, "打开文件",
					new CallbackBundle() {
						@Override
						public void callback(Bundle bundle) {
							String filepath = bundle.getString("path");
							path = filepath;
						}
					}, ".mp4;", images);
			return dialog;
		}
		return null;
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		Toast.makeText(CustomActivity.this, "影布已就绪", Toast.LENGTH_SHORT).show();
		Toast.makeText(CustomActivity.this, "请在菜单里操作", Toast.LENGTH_LONG)
				.show();
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub

	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		Toast.makeText(CustomActivity.this, "影布已销毁", Toast.LENGTH_SHORT).show();
	}

	@SuppressWarnings("deprecation")
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.custom);
		path = Environment.getExternalStorageDirectory().getPath()
				+ "/test.mp4";
		player = new MediaPlayer();
		surfaceView = (SurfaceView) findViewById(R.id.surfaceView1);
		holder = surfaceView.getHolder();
		holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		holder.addCallback(this);

		player.setOnBufferingUpdateListener(new OnBufferingUpdateListener() {

			@Override
			public void onBufferingUpdate(MediaPlayer mp, int percent) {
				// TODO Auto-generated method stub
				Toast.makeText(CustomActivity.this, "缓冲中,请等候",
						Toast.LENGTH_SHORT).show();
			}
		});
		player.setOnErrorListener(new one rrorListener() {

			@Override
			public boolean one rror(MediaPlayer mp, int what, int extra) {
				// TODO Auto-generated method stub
				Toast.makeText(CustomActivity.this, "出错啦", Toast.LENGTH_SHORT)
						.show();
				return false;
			}
		});
	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		if (player.isPlaying()) {
			player.stop();
		}
		player.release();
		super.onDestroy();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// TODO Auto-generated method stub
		menu.add(1, 1, 1, "播放");
		menu.add(1, 2, 2, "暂停");
		menu.add(1, 3, 3, "停止");
		menu.add(1, 4, 4, "本地");
		menu.add(1, 5, 5, "网络");
		return super.onCreateOptionsMenu(menu);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// TODO Auto-generated method stub
		if (item.getItemId() == 1) {
			try {
				player.reset();
				player.setAudioStreamType(AudioManager.STREAM_MUSIC);
				player.setDataSource(path);
				player.setDisplay(holder);
				player.prepare();
				player.start();
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else if (item.getItemId() == 2) {
			if (player.isPlaying()) {
				player.pause();
			} else {
				player.start();
			}
		} else if (item.getItemId() == 3) {
			if (player.isPlaying()) {
				player.stop();
			}
		} else if (item.getItemId() == 4) {
			showDialog(OPEN_FILE_DIALOG_ID);
		} else if (item.getItemId() == 5) {
			final EditText editText = new EditText(CustomActivity.this);
			new AlertDialog.Builder(CustomActivity.this).setTitle("请输入视频地址")
					.setIcon(android.R.drawable.ic_dialog_info)
					.setView(editText)
					.setPositiveButton("确定", new OnClickListener() {

						@Override
						public void onClick(DialogInterface dialog, int which) {
							// TODO Auto-generated method stub
							path = editText.getText().toString().trim();
							Toast.makeText(CustomActivity.this, path,
									Toast.LENGTH_SHORT).show();
						}
					}).setNegativeButton("取消", null).show();
		}
		return super.onOptionsItemSelected(item);
	}

}
CallbackBundle.java
package com.study.myshipin;

import android.os.Bundle;

public interface CallbackBundle {
	void callback(Bundle bundle);
} 
OpenFileDialog.java

package com.study.myshipin;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;

public class OpenFileDialog {
	public static String tag = "OpenFileDialog";
	static final public String sRoot = "/";
	static final public String sParent = "..";
	static final public String sFolder = ".";
	static final public String sEmpty = "";
	static final private String sOnErrorMsg = "No rights to access!";

	// 参数说明
	// context:上下文
	// dialogid:对话框ID
	// title:对话框标题
	// callback:一个传递Bundle参数的回调接口
	// suffix:需要选择的文件后缀,比如需要选择wav、mp3文件的时候设置为".wav;.mp3;",注意最后需要一个分号(;)
	// images:用来根据后缀显示的图标资源ID。
	// 根目录图标的索引为sRoot;
	// 父目录的索引为sParent;
	// 文件夹的索引为sFolder;
	// 默认图标的索引为sEmpty;
	// 其他的直接根据后缀进行索引,比如.wav文件图标的索引为"wav"
	public static Dialog createDialog(int id, Context context, String title,
			CallbackBundle callback, String suffix, Map<String, Integer> images) {
		AlertDialog.Builder builder = new AlertDialog.Builder(context);
		builder.setView(new FileSelectView(context, id, callback, suffix,
				images));
		Dialog dialog = builder.create();
		// dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
		dialog.setTitle(title);
		return dialog;
	}

	static class FileSelectView extends ListView implements OnItemClickListener {

		private CallbackBundle callback = null;
		private String path = sRoot;
		private List<Map<String, Object>> list = null;
		private int dialogid = 0;

		private String suffix = null;

		private Map<String, Integer> imagemap = null;

		public FileSelectView(Context context, int dialogid,
				CallbackBundle callback, String suffix,
				Map<String, Integer> images) {
			super(context);
			this.imagemap = images;
			this.suffix = suffix == null ? "" : suffix.toLowerCase();
			this.callback = callback;
			this.dialogid = dialogid;
			this.setOnItemClickListener(this);
			refreshFileList();
		}

		private String getSuffix(String filename) {
			int dix = filename.lastIndexOf('.');
			if (dix < 0) {
				return "";
			} else {
				return filename.substring(dix + 1);
			}
		}

		private int getImageId(String s) {
			if (imagemap == null) {
				return 0;
			} else if (imagemap.containsKey(s)) {
				return imagemap.get(s);
			} else if (imagemap.containsKey(sEmpty)) {
				return imagemap.get(sEmpty);
			} else {
				return 0;
			}
		}

		private int refreshFileList() {
			// 刷新文件列表
			File[] files = null;
			try {
				files = new File(path).listFiles();
			} catch (Exception e) {
				files = null;
			}
			if (files == null) {
				// 访问出错
				Toast.makeText(getContext(), sOnErrorMsg, Toast.LENGTH_SHORT)
						.show();
				return -1;
			}
			if (list != null) {
				list.clear();
			} else {
				list = new ArrayList<Map<String, Object>>(files.length);
			}

			// 用来先保存文件夹和文件夹的两个列表
			ArrayList<Map<String, Object>> lfolders = new ArrayList<Map<String, Object>>();
			ArrayList<Map<String, Object>> lfiles = new ArrayList<Map<String, Object>>();

			if (!this.path.equals(sRoot)) {
				// 添加根目录 和 上一层目录
				Map<String, Object> map = new HashMap<String, Object>();
				map.put("name", sRoot);
				map.put("path", sRoot);
				map.put("img", getImageId(sRoot));
				list.add(map);

				map = new HashMap<String, Object>();
				map.put("name", sParent);
				map.put("path", path);
				map.put("img", getImageId(sParent));
				list.add(map);
			}

			for (File file : files) {
				if (file.isDirectory() && file.listFiles() != null) {
					// 添加文件夹
					Map<String, Object> map = new HashMap<String, Object>();
					map.put("name", file.getName());
					map.put("path", file.getPath());
					map.put("img", getImageId(sFolder));
					lfolders.add(map);
				} else if (file.isFile()) {
					// 添加文件
					String sf = getSuffix(file.getName()).toLowerCase();
					if (suffix == null
							|| suffix.length() == 0
							|| (sf.length() > 0 && suffix.indexOf("." + sf
									+ ";") >= 0)) {
						Map<String, Object> map = new HashMap<String, Object>();
						map.put("name", file.getName());
						map.put("path", file.getPath());
						map.put("img", getImageId(sf));
						lfiles.add(map);
					}
				}
			}

			list.addAll(lfolders); // 先添加文件夹,确保文件夹显示在上面
			list.addAll(lfiles); // 再添加文件

			SimpleAdapter adapter = new SimpleAdapter(
					getContext(),
					list,
					R.layout.filedialogitem,
					new String[] { "img", "name", "path" },
					new int[] { R.id.filedialogitem_img,
							R.id.filedialogitem_name, R.id.filedialogitem_path });
			this.setAdapter(adapter);
			return files.length;
		}

		@Override
		public void onItemClick(AdapterView<?> parent, View v, int position,
				long id) {
			// 条目选择
			String pt = (String) list.get(position).get("path");
			String fn = (String) list.get(position).get("name");
			if (fn.equals(sRoot) || fn.equals(sParent)) {
				// 如果是更目录或者上一层
				File fl = new File(pt);
				String ppt = fl.getParent();
				if (ppt != null) {
					// 返回上一层
					path = ppt;
				} else {
					// 返回更目录
					path = sRoot;
				}
			} else {
				File fl = new File(pt);
				if (fl.isFile()) {
					// 如果是文件
					((Activity) getContext()).dismissDialog(this.dialogid); // 让文件夹对话框消失

					// 设置回调的返回值
					Bundle bundle = new Bundle();
					bundle.putString("path", pt);
					bundle.putString("name", fn);
					// 调用事先设置的回调函数
					this.callback.callback(bundle);
					return;
				} else if (fl.isDirectory()) {
					// 如果是文件夹
					// 那么进入选中的文件夹
					path = pt;
				}
			}
			this.refreshFileList();
		}
	}
}
布局文件:

activity_main.xml

<RelativeLayout 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"
    android:background="#FFFFFF"
    tools:context="${relativePackage}.${activityClass}" >

    <VideoView
        android:id="@+id/videoView1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" />

</RelativeLayout>
custom.xml

<RelativeLayout 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"
    android:background="#888888"
    tools:context="${relativePackage}.${activityClass}" >

    <SurfaceView
        android:id="@+id/surfaceView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true" />

</RelativeLayout>
filedialogitem.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/vw1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="#000000"
    android:orientation="horizontal"
    android:padding="4dp" >

    <ImageView
        android:id="@+id/filedialogitem_img"
        android:layout_width="32dp"
        android:layout_height="32dp"
        android:layout_margin="4dp" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/filedialogitem_name"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textColor="#FFFFFF"
            android:textSize="18sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/filedialogitem_path"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="10dp"
            android:textColor="#FFFFFF"
            android:textSize="14sp" />
    </LinearLayout>

</LinearLayout>

AndroidManifest.xml部分代码

<uses-permission android:name="android.permission.INTERNET" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.Black.NoTitleBar" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:screenOrientation="landscape" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".CustomActivity"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:screenOrientation="landscape" />
    </application>









Android视频播放1