VideoView 视频播放 示例
介绍
实现的功能:
- 可播放本地视频或网络视频,可控制播放或暂停
- 最小化时保存播放位置及播放状态,resume时恢复所有状态;
- 横竖屏切换时保持切换前的位置及状态
- 在屏幕上竖直滑动可调节屏幕亮度和音量
- 可改变视频显示样式(有bug)
- 可获取视频缩略图及视频大小
Activity
import android.app.Activity;import android.content.pm.ActivityInfo;import android.content.res.Configuration;import android.media.MediaPlayer;import android.media.MediaPlayer.OnCompletionListener;import android.media.MediaPlayer.OnErrorListener;import android.media.MediaPlayer.OnPreparedListener;import android.net.Uri;import android.os.Bundle;import android.os.Environment;import android.util.Log;import android.view.GestureDetector;import android.view.GestureDetector.OnGestureListener;import android.view.MotionEvent;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnTouchListener;import android.widget.Button;import android.widget.MediaController;import android.widget.ProgressBar;import android.widget.RelativeLayout;import android.widget.Toast;import android.widget.VideoView;public class MainActivity extends Activity implements OnCompletionListener, OnErrorListener, OnPreparedListener, OnTouchListener, OnClickListener,OnGestureListener {private Button btn_switch;private Button btn_start;private Button btn_fullscreen;private VideoView mVideoView;//在 VidioView 外层套一个容器,以在切换屏幕方向的时候对 rl_vv 进行拉伸,而内部的 mVideoView 会依据视频尺寸重新计算宽高。//若是直接具体指定了view的宽高,则视频会被拉伸。private RelativeLayout rl_vv;private ProgressBar progressBar; //加载进度条private int positionWhenPause = 0;//标记当视频暂停时的播放位置private boolean isPlayingWhenPause = false;//标记最小化或横竖屏时是否正在播放private GestureDetector mGestureDetector;//手势识别器,用户控制屏幕亮度和音量private Uri mVideoUri;public static final String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/b.rmvb";//本地路径public static final String url = "http://7xt0mj.com1.z0.glb.clouddn.com/lianaidaren.v.640.480.mp4";//网络路径public static final String url2 = "http://7xt0mj.com1.z0.glb.clouddn.com/xia.v.1280.720.f4v";public static final String url3 = "http://112.253.22.157/17/z/z/y/u/zzyuasjwufnqerzvyxgkuigrkcatxr/hc.yinyuetai.com /D046015255134077DDB3ACA0D7E68D45.flv";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);progressBar = (ProgressBar) findViewById(R.id.progressBar);rl_vv = (RelativeLayout) findViewById(R.id.rl_vv);mVideoView = (VideoView) findViewById(R.id.mVideoView);btn_switch = (Button) findViewById(R.id.btn_switch);btn_start = (Button) findViewById(R.id.btn_start);btn_fullscreen = (Button) findViewById(R.id.btn_fullscreen);//设置显示控制条mVideoView.setMediaController(new MediaController(this));mVideoUri = Uri.parse(filePath);mVideoView.setVideoURI(mVideoUri);//mVideoView.setVideoPath(url);//这两个方法都可以用来播放网络视频或本地视频btn_switch.setOnClickListener(this);btn_start.setOnClickListener(this);btn_fullscreen.setOnClickListener(this);mVideoView.setOnCompletionListener(this);mVideoView.setOnErrorListener(this);mVideoView.setOnPreparedListener(this);mVideoView.setOnTouchListener(this);mVideoView.setOnClickListener(this);mGestureDetector = new GestureDetector(this, this);}@Overrideprotected void onResume() {super.onResume();//如果有保存位置,则跳转到暂停时所保存的那个位置if (positionWhenPause > 0) {mVideoView.seekTo(positionWhenPause);//如果暂停前正在播放,则继续播放,并将播放位置置为0if (isPlayingWhenPause) {mVideoView.start();mVideoView.requestFocus();positionWhenPause = 0;}}}@Overrideprotected void onPause() {//如果当前页面暂定,则保存当前播放位置,并记录之前mVideoView是否正在播放isPlayingWhenPause = mVideoView.isPlaying();positionWhenPause = mVideoView.getCurrentPosition();//停止回放视频文件,先获取再stopPlayback()mVideoView.stopPlayback();super.onPause();}@Overrideprotected void onDestroy() {super.onDestroy();if (null != mVideoView) mVideoView = null;}@Override//横竖屏切换时更改mVideoView的大小public void onConfigurationChanged(Configuration newConfig) {super.onConfigurationChanged(newConfig);if (mVideoView == null) {return;}if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {//横屏VideoUtils.setActivityFullScreenMode(this);//设置为全屏模式getWindow().getDecorView().invalidate();//rl_vv.getLayoutParams().width = VideoUtils.getScreenWidth(this);rl_vv.getLayoutParams().height = VideoUtils.getScreenHeight(this);} else {//竖屏VideoUtils.setActivityWindowScreenMode(this);rl_vv.getLayoutParams().width = VideoUtils.getScreenWidth(this);//rl_vv.getLayoutParams().height = VideoUtils.dp2px(this, 400);}}//***************************************************************************************************************************@Overridepublic void onPrepared(MediaPlayer mp) {try {long timeLong = Long.valueOf(VideoUtils.getVideoLength(mVideoUri.toString()));Toast.makeText(this, "准备好了,时长为 " + VideoUtils.long2Time(timeLong), Toast.LENGTH_SHORT).show();} catch (Exception e) {}//如果文件加载成功,隐藏加载进度条progressBar.setVisibility(View.GONE);}@Overridepublic void onCompletion(MediaPlayer mp) {}@Override//视频播放发生错误时回调。如果未指定回调, 或回调函数返回false,mVideoView 会通知用户发生了错误。public boolean onError(MediaPlayer mp, int what, int extra) {switch (what) {case MediaPlayer.MEDIA_ERROR_UNKNOWN:Log.e("text", "发生未知错误");break;case MediaPlayer.MEDIA_ERROR_SERVER_DIED:Log.e("text", "媒体服务器死机");break;default:Log.e("text", "onError+" + what);break;}switch (extra) {case MediaPlayer.MEDIA_ERROR_IO:Log.e("text", "文件或网络相关的IO操作错误");break;case MediaPlayer.MEDIA_ERROR_MALFORMED:Log.e("text", "比特流编码标准或文件不符合相关规范");break;case MediaPlayer.MEDIA_ERROR_TIMED_OUT:Log.e("text", "操作超时");break;case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:Log.e("text", "比特流编码标准或文件符合相关规范,但媒体框架不支持该功能");break;default:Log.e("text", "onError+" + extra);break;}return true;//经常会碰到视频编码格式不支持的情况,若不想弹出提示框就返回true}//************************************************************************************************************************************@Overridepublic boolean onTouch(View v, MotionEvent event) {return mGestureDetector.onTouchEvent(event);//把Touch事件传递给手势识别器,这一步非常重要!}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_start:if (mVideoView.isPlaying()) {mVideoView.pause();} else {mVideoView.start();//启动视频播放mVideoView.requestFocus();//获取焦点}break;case R.id.btn_switch://横竖屏切换if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);} else {setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);}// btn_switch.setVisibility(View.INVISIBLE);break;case R.id.btn_fullscreen:VideoUtils.setVideoViewLayoutParams(this, mVideoView, VideoUtils.FULL_SCREEN);break;}}//************************************************************************************************************************************@Override//e1代表触摸时的事件,是不变的,e2代表滑动过程中的事件,是时刻变化的//distance是当前event2与上次回调时的event2之间的距离,代表上次回调之后到这次回调之前移动的距离public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {float FLING_MIN_BRIGHTNESS = 1.0f * VideoUtils.dp2px(MainActivity.this, 1f);//调节亮度时的敏感度,float FLING_MIN_VOICE = 1.0f * VideoUtils.dp2px(MainActivity.this, 5f);//调节声音时的敏感度float distance = Math.abs(distanceY);//竖直方向移动范围//在屏幕左侧滑动调节亮度,在屏幕右侧滑动调节声音if (e1.getX() < VideoUtils.getScreenWidth(this) / 2) {//左侧if (distance > FLING_MIN_BRIGHTNESS) {//移动范围满足if (e1.getY() - e2.getY() > 0) {//上滑VideoUtils.setScreenBrightness(this, 15);//亮度增加,第二参数的大小代表着敏感度} else {//下滑VideoUtils.setScreenBrightness(this, -15);}}} else {//右侧if (distance > FLING_MIN_VOICE) {//移动范围满足if (e1.getY() - e2.getY() > 0) {//上滑//VideoUtils.setVoiceVolume(this, 1);//音量增加VideoUtils.setVoiceVolumeAndShowNotification(this, true);//系统自动控制音量增加减小级别} else {//下滑// VideoUtils.setVoiceVolume(this, -1);VideoUtils.setVoiceVolumeAndShowNotification(this, false);}}}return true;}@Overridepublic boolean onDown(MotionEvent e) {return true;}@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {return true;}@Overridepublic void onLongPress(MotionEvent e) {}@Overridepublic void onShowPress(MotionEvent e) {}@Overridepublic boolean onSingleTapUp(MotionEvent e) {return false;}}
工具
import java.lang.reflect.Method;import java.text.SimpleDateFormat;import java.util.Date;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.PixelFormat;import android.graphics.drawable.Drawable;import android.media.AudioManager;import android.media.MediaMetadataRetriever;import android.media.ThumbnailUtils;import android.net.ConnectivityManager;import android.net.NetworkInfo;import android.os.Build;import android.provider.MediaStore.Video;import android.provider.Settings;import android.provider.Settings.SettingNotFoundException;import android.util.Log;import android.view.View;import android.view.Window;import android.view.WindowManager;import android.widget.RelativeLayout;import android.widget.RelativeLayout.LayoutParams;import android.widget.VideoView;public class VideoUtils {/*** 根据手机的分辨率从 dp或 sp 的单位 转成为 px*/public static int dp2px(Context context, float dpValue) {float scale = context.getResources().getDisplayMetrics().density;return (int) (dpValue * scale + 0.5f);}/*** 根据手机的分辨率从 px 的单位转成为 dp 或 sp*/public static int px2dp(Context context, float pxValue) {float scale = context.getResources().getDisplayMetrics().density;return (int) (pxValue / scale + 0.5f);}/*** 获取屏幕高度*/public static int getScreenHeight(Context context) {return context.getResources().getDisplayMetrics().heightPixels;}/*** 获取屏幕宽度*/public static int getScreenWidth(Context context) {return context.getResources().getDisplayMetrics().widthPixels;}/*** 设置Activity为全屏模式*/public static void setActivityFullScreenMode(Activity context) {context.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);}/*** 设置Activity为窗口模式???*/public static void setActivityWindowScreenMode(Activity context) {WindowManager.LayoutParams attrs = context.getWindow().getAttributes();attrs.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);context.getWindow().setAttributes(attrs);context.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);}//********************************************************************************************************************public static final int FULL_SCREEN = 1;//全屏拉伸模式public static final int SCREEN_WINDOW = 2;//指定大小模式public static final int SCREEN_WINDOW_ADAPT = 3;//自适应宽高模式/*** 设置VideoView的全屏和窗口模式。<br>* 全屏拉伸模式 : {@link #FULL_SCREEN} <br>* 指定大小模式: {@link #SCREEN_WINDOWE}<br>* 自适应宽高模式 : {@link #SCREEN_WINDOW_ADAPT}* 这里有很多bug*******************************************************************************************************************************************************/public static void setVideoViewLayoutParams(Activity context, VideoView mVideoView, int paramsType) {int width, height;switch (paramsType) {case FULL_SCREEN:setActivityFullScreenMode(context);RelativeLayout.LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);((View) mVideoView.getParent()).setLayoutParams(layoutParams);//布局里我们给VideoView设置了一个父布局mVideoView.setLayoutParams(layoutParams);break;case SCREEN_WINDOW:width = getScreenWidth(context) * 2 / 3;height = VideoUtils.getScreenHeight(context) * 2 / 3;RelativeLayout.LayoutParams LayoutParams = new LayoutParams(width, height);LayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);mVideoView.setLayoutParams(LayoutParams);break;default://先获取VideoView中资源的大小,然后分别和VideoView控件的大小作对比,当资源宽高大于控件时,缩小,否则放大。//和加载图片一个样,但是VideoView没有scaleType塑性int videoWidth = mVideoView.getWidth();int videoHeight = mVideoView.getHeight();break;}}//********************************************************************************************************************/*** 获取屏幕亮度模式,返回-1代表没有获取到* 自动调节:Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC=1* 手动调节:SCREEN_BRIGHTNESS_MODE_MANUAL=0*/public static int getScreenBrightnessMode(Context context) {int screenMode = -1;try {screenMode = Settings.System.getInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE);} catch (SettingNotFoundException e) {e.printStackTrace();}return screenMode;}/*** 设置屏幕亮度模式* 自动调节:Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC=1* 手动调节:SCREEN_BRIGHTNESS_MODE_MANUAL=0*/public static void setScreenBrightnessMode(Context context, int value) {Settings.System.putInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, value);}/*** 获取屏幕亮度,获取失败返回-1*/public static int getScreenBrightness(Context context) {int bright = -1;try {bright = Settings.System.getInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);} catch (SettingNotFoundException e) {e.printStackTrace();}return bright;}/*** 增加或减小当前屏幕亮度,并在整个系统上生效*/public static void setScreenBrightness(Activity context, float value) {//设置当前【activity】的屏幕亮度Window mWindow = context.getWindow();WindowManager.LayoutParams mParams = mWindow.getAttributes();//注意:它的值是从0到1,亮度从暗到全亮mParams.screenBrightness += value / 255.0F;if (mParams.screenBrightness > 1) {//设置大于1的值后,虽然获取到的此参数的值被改了,但系统并不使用此值而是使用某一指定值设置亮度mParams.screenBrightness = 1;} else if (mParams.screenBrightness < 0.01) {mParams.screenBrightness = 0.01f;}mWindow.setAttributes(mParams);// 保存设置为【系统】屏幕亮度值。注意它的值是0-255int newValue = (int) (mParams.screenBrightness * 255.0F + value);// 或者= (int) (getScreenBrightness(context) + value);if (newValue > 255) newValue = 255;else if (newValue < 0) newValue = 0;Log.i("bqt", "亮度=" + mParams.screenBrightness + ",亮度=" + newValue);Settings.System.putInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, newValue);}//********************************************************************************************************************/*** 设置铃声模式* @param mode 声音模式:AudioManager.RINGER_MODE_NORMAL;静音模式:_SILENT;震动模式:_VIBRATE*/public static void setRingerMode(Context context, int mode) {AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);mAudioManager.setRingerMode(mode);}/*** 增加或减小媒体音量*/public static void setVoiceVolume(Context context, int value) {AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);// 注意:分为静音(0),震动(0),1--7 共九个等级。从静音调为1时,需要调大两个等级;从1调为0时,手机将调整为“震动模式”int currentVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);//尼玛,我获得的最大值是15int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);int newVolume = currentVolume + value;if (newVolume > maxVolume) {newVolume = maxVolume;} else if (newVolume < 0) {newVolume = 0;}Log.i("bqt", "音量=" + newVolume);mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, newVolume, 0);}/*** 增加或减小媒体音量,并且显示系统音量控制提示条*/public static void setVoiceVolumeAndShowNotification(Context context, boolean isAddVolume) {AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);if (isAddVolume) {//参数:声音类型,调整音量的方向(只能是增加、减小、不变),可选的标志位(不知道有卵用)//音乐:AudioManager.STREAM_MUSIC;通话:_VOICE_CALL;系统:_SYSTEM;铃声:_RING;提示音:_NOTIFICATION;闹铃:_ALARMmAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, AudioManager.FX_FOCUS_NAVIGATION_UP);} else {mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, AudioManager.FX_FOCUS_NAVIGATION_UP);}Log.i("bqt", "音量=" + mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));}//********************************************************************************************************************/*** 获取视频长度,获取网络视频长度时异常!*/public static String getVideoLength(String filePath) {MediaMetadataRetriever retriever = new MediaMetadataRetriever();retriever.setDataSource(filePath);String length = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);return length;}/*** 毫秒值装换为时分秒形式*/@SuppressWarnings("deprecation")public static String long2Time(long timeLong) {Date date = new Date(timeLong);date.setHours(date.getHours() - 8); //沃日,我们这里比标准时长快了八个小时SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss ");return format.format(date);}/*** 获取视频缩略图* @param filePath 视频文件的路径*/public static Bitmap createVideoThumbnail(String filePath) {return ThumbnailUtils.createVideoThumbnail(filePath, Video.Thumbnails.MINI_KIND);}/*** 获取视频的缩略图* 先通过ThumbnailUtils来创建一个视频的缩略图,然后再利用ThumbnailUtils来生成指定大小的缩略图。* 如果想要的缩略图的宽和高都小于MICRO_KIND,则类型要使用MICRO_KIND作为kind的值,这样会节省内存。* @param videoPath 视频的路径* @param width 指定输出视频缩略图的宽度* @param height 指定输出视频缩略图的高度度* @param kind 参照Thumbnails类中的常量MINI_KIND(512 x 384) 和 MICRO_KIND(96 x 96)*/public static Bitmap getVideoThumbnail(String videoPath, int width, int height, int kind) {// 获取视频的缩略图Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(videoPath, kind);bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);return bitmap;}/*** 利用反射的方式获取视频缩略图,不建议使用* @param filePath 视频文件的路径*/public static Bitmap createVideoThumbnail2(String filePath) {Class<?> clazz = null;Object instance = null;try {clazz = Class.forName("android.media.MediaMetadataRetriever");instance = clazz.newInstance();Method method = clazz.getMethod("setDataSource", String.class);method.invoke(instance, filePath);if (Build.VERSION.SDK_INT <= 9) {return (Bitmap) clazz.getMethod("captureFrame").invoke(instance);} else {byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance);if (data != null) {Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);if (bitmap != null) return bitmap;}return (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance);}} catch (Exception ex) {} finally {try {if (instance != null) {clazz.getMethod("release").invoke(instance);}} catch (Exception ignored) {}}return null;}/*** 将Drawable转化为Bitmap*/public static Bitmap drawableToBitmap(Drawable drawable) {// 取 drawable 的长宽,颜色格式int w = drawable.getIntrinsicWidth();int h = drawable.getIntrinsicHeight();Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;// 创建对应 bitmapBitmap bitmap = Bitmap.createBitmap(w, h, config);Canvas canvas = new Canvas(bitmap);drawable.setBounds(0, 0, w, h);drawable.draw(canvas);return bitmap;}//********************************************************************************************************************public static final int NETWORK_TYPE_INVALID = 0;public static final int NETWORK_TYPE_MOBILE = 1;public static final int NETWORK_TYPE_WIFI = 2;/*** 获取当前网络连接状况* 网络不可用 : {@link #NETWORK_TYPE_INVALID} <br>* 蜂窝网络(手机流量) : {@link #NETWORK_TYPE_MOBILE}<br>* WIFI连接 : {@link #NETWORK_TYPE_WIFI}*/public static int getNetworkType(Context context) {ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);NetworkInfo networkInfo = manager.getActiveNetworkInfo();if (networkInfo != null && networkInfo.isConnected()) {String type = networkInfo.getTypeName();if (type.equalsIgnoreCase("WIFI")) {return NETWORK_TYPE_WIFI;} else if (type.equalsIgnoreCase("MOBILE")) {return NETWORK_TYPE_MOBILE;}}return NETWORK_TYPE_INVALID;}}
布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#300f"android:padding="5dp" ><RelativeLayoutandroid:id="@+id/rl_vv"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerInParent="true"android:layout_weight="2016"android:background="#30f0"android:minHeight="200dp"android:padding="5dp" ><VideoViewandroid:id="@+id/mVideoView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:padding="5dp" /></RelativeLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:orientation="horizontal" ><Buttonandroid:id="@+id/btn_start"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="播放/暂停" /><Buttonandroid:id="@+id/btn_switch"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="横竖屏切换" /><Buttonandroid:id="@+id/btn_fullscreen"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="全屏" /></LinearLayout><ProgressBarandroid:id="@+id/progressBar"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true" /></RelativeLayout>
清单文件
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.bqt.videoview"android:versionCode="1"android:versionName="1.0" ><uses-sdkandroid:minSdkVersion="17"android:targetSdkVersion="21" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><!-- 网络权限 --><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><!-- 滑动改变屏幕亮度/音量 --><uses-permission android:name="android.permission.WRITE_SETTINGS" /><uses-permission android:name="android.permission.VIBRATE" /><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid:name=".MainActivity"android:configChanges="keyboard|orientation|screenSize"android:label="@string/app_name"android:theme="@style/Theme.AppCompat.Light.NoActionBar" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>
VideoView 视频播放 示例的更多相关文章
- React Native实战系列教程之自定义原生UI组件和VideoView视频播放器开发
React Native实战系列教程之自定义原生UI组件和VideoView视频播放器开发 2016/09/23 | React Native技术文章 | Sky丶清| 4 条评论 | 1 ...
- MediaPlayer+SurfaceView 视频播放 示例
SurfaceView的原理 SurfaceView在视频播放中起到显示画面的作用,而视频的播放主要通过MediaPlayer来控制. SurfaceView 允许我们 ...
- Android开发 VideoView视频播放详解
前言 VideoView是Android主要的视频播放View,它其实是对MediaPlayer的再次封装.如果你已经了解过MediaPlayer在使用VideoView是十分简单的.如果你想先了解M ...
- Android 视频播放器 (一):使用VideoView播放视频
一.简介 作为Android开发,我们不可避免的会接触到视频播放,VideoView做为最简单的播放器,我们是不应该不会的. 下面简单介绍一下VideoView: VideoView是使用MediaP ...
- Android:视频(VideoView/MediaPlayer)
Android之视频播放 VideoView if(android.os.Environment.getExternalStorageState().equals(android.os.Environ ...
- Android音视频之MediaPlayer音视频播放
前言: 昨天总结了视频录制,今天来学习一下视频的播放,Android的视频播放主要采用MediaPlayer类. MediaPlayer介绍 MediaPlayer类可用于控制音频/视频文件或流的播放 ...
- 用法简单的图片和视频播放的框架Demo
最近在恶补自己不足的基础知识,偶然在一个QQ群里看到作为同行业的大神们在开源自己的代码.并且在炫耀说让我们找Bug,于是出于好奇就看了下,点开了一个关于图片和视频播放的Demo.也就是接下来我要说的这 ...
- Android高级控件(四)——VideoView 实现引导页播放视频欢迎效果,超级简单却十分的炫酷
Android高级控件(四)--VideoView 实现引导页播放视频欢迎效果,超级简单却十分的炫酷 是不是感觉QQ空间什么的每次新版本更新那炫炫的引导页就特别的激动,哈哈,其实他实现起来真的很简单很 ...
- Android学习笔记总结
第一步: Android(1) - 在 Windows 下搭建 Android 开发环境,以及 Hello World 程序 搭建 Android 的开发环境,以及写一个简单的示例程序 · 在 Win ...
随机推荐
- webAPP前端必备知识
了解各浏览器内核 Firefox:-moz-box-shadow Safari:-webkit-box-shadow Opera:-o-box-shadow IE:-ms-box-shadow Web ...
- grails通过findBy或findBy查找的结果集进行排序
原文:http://grails.org/doc/2.3.x/ref/Domain%20Classes/list.html list Purpose Lists instances of the do ...
- js变量声明与赋值以及函数声明
if (!("a" in window)) { var a = 1; } alert(a); 结果:undefined 分析: 首先,所有的全局变量都是window的属性,语句 v ...
- thinkphp 文件下载实例 实现以及注意事项
#下载 function download() { $id=$_GET['id']; $file_name ...
- [前端笔记]第一篇:html
什么是 HTML? HTML 是用来描述网页的一种语言.HTML 指的是超文本标记语言 (Hyper Text Markup Language)HTML 不是一种编程语言,而是一种标记语言 (mark ...
- Expires、Last-Modified、Etag缓存控制
当请求一个页面时,如果浏览器使用本地缓存,因此我们经常会看到一个HTTP请求为304状态.或者显示200状态,在chrome下标注是from cache,在火狐下会标注BFCache: 我们希望在服务 ...
- 水仙花 AC 杭电
水仙花数 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...
- 人见人爱a*b 杭电2035
求A^B的最后三位数表示的整数.说明:A^B的含义是“A的B次方” Input 输入数据包含多个测试实例,每个实例占一行,由两个正整数A和B组成(1<=A,B<=10000),如果A= ...
- 实验二:基于mykernel实现的时间片轮转调度
原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 如果我写的不好或者有误的地方请留言 ...
- 【Java】环境变量的配置
注意点 1.环境变量不能有空格,比如C:\Program Files 2.JAVA_HOME:D:\Java\jdk1.7.0_67------------->注意不能加;分号