首页 > 代码库 > 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