不拘小节的太阳 · Python求解拉普拉斯矩阵及其特征值_51 ...· 1 年前 · |
怕老婆的西装 · 吃掉宿主舌头自己当舌头,科学家发现世界上最恶 ...· 1 年前 · |
好帅的小刀 · sql server like 优化-掘金· 1 年前 · |
博学的苦瓜 · AndroidStudio配置Termina ...· 1 年前 · |
调皮的小蝌蚪 · java - Getting : ...· 1 年前 · |
1、使用其自带的播放器。指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型。
2、使用VideoView来播放。在布局文件中使用VideoView结合MediaController来实现对其控制。
3、使用MediaPlayer类和SurfaceView来实现,这种方式很灵活。
这里主要使用了vitamio万能播放器,官网:https://www.vitamio.org/,
vitamio支持格式:mp3/mp4/mkv/avi/3gp/rmvb/mov/flv
简介:1、当然最重要的是播放功能,含播放控制(播放、暂停,声音、亮度调整等)
2、可以扫描SDcard,用列表展现出来,可以搜索
3、可以播放网络视音频(http、rtsp、mms)
网络协议:mms,RTSP(RTP/SDP), HTTP流式传输(progressive streaming),
HTTPLive Streaming (M3U8), Android 2.1+
其他:1、FFmpeg提供软件解码器和多路输出(demuxers)
2、Universalchardet (是Mozilla的一个自动检测页面文字编码的程序) Universalchardet是Mozilla的编码检测库。Vitamio使用MPL许可下
Universalchardet的代码来检测字母文本编码。
2、自带播放器实现
Intent intent = new Intent();
intent.setDataAndType(Uri.parse("http://data.vod.itc.cn/?rb=1&prot=1&key=jbZhEJhlqlUN-Wj_HEI8BjaVqKNFvDrn&prod=flash&pt=1&new=/86/168/RUXzy059JIvGRrrXQvOkNE.mp4"), "video/*");
startActivity(intent);
3、videoView播放器实现
Uri uri = Uri.parse(Environment.getExternalStorageDirectory().getPath()+"/Test_Movie.m4v");
VideoView videoView = (VideoView)this.findViewById(R.id.video_view);
videoView.setMediaController(new MediaController(this));
videoView.setVideoURI(uri);
videoView.start();
videoView.requestFocus();
4、
vitamio播放器是继承surfaceView实现的,在实现之前先添加vitamio的库,可到官网下载,build.gradle配置
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.example.apple.vitamiodemo"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
compile 'com.android.support:appcompat-v7:25.1.1'
testCompile 'junit:junit:4.12'
compile project(':vitamio')
compile 'com.jakewharton:butterknife:8.4.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
}
5、权限文件实现代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.apple.vitamiodemo">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE"/>
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".activity.VideoList"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="io.vov.vitamio.activity.InitActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:launchMode="singleTop"
android:theme="@android:style/Theme.NoTitleBar"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".MainActivity"
android:configChanges="keyboardHidden|screenSize|orientation"
android:screenOrientation="landscape"
android:theme="@style/noAnimation_Theme"/>
</application>
</manifest>
6、都准备好后,首先先实现获取本地视频,通过列表显示。
/**
* 从本地的sdcard得到数据
* 1、遍历sdcard ,后缀名
* 2、去数据库中获取,内容提供者
* 3、如果是6.0系统需要动态读取sdcand权限
public void getDataFromLocal() {
new Thread() {
@Override
public void run() {
super.run();
mediaItems = new ArrayList<>();
ContentResolver resolver = getContentResolver();
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] objs = {
MediaStore.Video.Media.DISPLAY_NAME,//视屏文件在sdcard的名称
MediaStore.Video.Media.DURATION,//视屏总时长
MediaStore.Video.Media.SIZE,//视屏的文件大小
MediaStore.Video.Media.DATA,//视屏的绝对地址
MediaStore.Video.Media.ARTIST,//歌曲的演唱者
Cursor cursor = resolver.query(uri, objs, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
MediaItem mediaItem = new MediaItem();
String name = cursor.getString(0);//视频名称
mediaItem.setName(name);
long duration = cursor.getLong(1);//视频的时长
mediaItem.setDuration(duration);
long size = cursor.getLong(2);//视频大小
mediaItem.setSize(size);
String data = cursor.getString(3);//视频播放地址
mediaItem.setData(data);
String artist = cursor.getString(4);//艺术家
mediaItem.setArtist(artist);
mediaItems.add(mediaItem);//可以写在上面
cursor.close();
//Handler发消息
handler.sendEmptyMessage(10);
}.start();
}
adapter布局代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:padding="3dp"
android:layout_height="100dp">
<ImageView
android:layout_marginLeft="8dp"
android:id="@+id/iv_icon"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/btn_video_play" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="3dp"
android:layout_toRightOf="@+id/iv_icon"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="视频名称"
android:textColor="#77000000"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="20:00"
android:textColor="@android:color/black"
android:textSize="16sp" />
</LinearLayout>
<TextView
android:id="@+id/tv_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="3dp"
android:layout_marginTop="5dp"
android:text="20MB"
android:textColor="@android:color/black"
android:textSize="16sp" />
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:background="#44000000" />
</RelativeLayout>
adapter代码实现
package com.example.apple.vitamiodemo.adapter;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.apple.vitamiodemo.R;
import com.example.apple.vitamiodemo.data.MediaItem;
import com.example.apple.vitamiodemo.utils.Utils;
import java.text.DecimalFormat;
import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;
* Created by apple on 2017/2/7.
* VideoPager Adapter
public class VideoListAdapter extends BaseAdapter{
private boolean isVideo = false;
private final Context context;
private ArrayList<MediaItem> mediaItems = new ArrayList<>();
private Utils utils;
public VideoListAdapter(Context context,ArrayList<MediaItem> mediaItem,boolean isVideo) {
this.context = context;
this.mediaItems = mediaItem;
this.isVideo = isVideo;
@Override
public int getCount() {
return mediaItems.size();
@Override
public Object getItem(int position) {
return null;
@Override
public long getItemId(int position) {
return 0;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
utils = new Utils();
if (convertView == null) {
convertView = View.inflate(context, R.layout.item_video_pager, null);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder)convertView.getTag();
//根据position得到列表中对应位置的数据
MediaItem mediaItem = mediaItems.get(position);
viewHolder.tvName.setText(mediaItem.getName());
viewHolder.tvSize.setText(FormetFileSize(mediaItem.getSize()));
viewHolder.tvTime.setText(utils.stringForTime((int) mediaItem.getDuration()));
if (!isVideo){
viewHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);
return convertView;
static class ViewHolder {
@BindView(R.id.iv_icon)
ImageView ivIcon;
@BindView(R.id.tv_name)
TextView tvName;
@BindView(R.id.tv_time)
TextView tvTime;
@BindView(R.id.tv_size)
TextView tvSize;
ViewHolder(View view) {
ButterKnife.bind(this, view);
* 转换文件大小
* @param fileS
* @return fileSizeString
public String FormetFileSize(long fileS) {
DecimalFormat df = new DecimalFormat("#.00");
String fileSizeString = "";
if (fileS < 1024) {
fileSizeString = df.format((double) fileS) + "B";
} else if (fileS < 1048576) {
fileSizeString = df.format((double) fileS / 1024) + "K";
} else if (fileS < 1073741824) {
fileSizeString = df.format((double) fileS / 1048576) + "M";
} else {
fileSizeString = df.format((double) fileS / 1073741824) + "G";
return fileSizeString;
}
完整显示视频数据代码videoList.java
package com.example.apple.vitamiodemo.activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.example.apple.vitamiodemo.MainActivity;
import com.example.apple.vitamiodemo.R;
import com.example.apple.vitamiodemo.adapter.VideoListAdapter;
import com.example.apple.vitamiodemo.data.MediaItem;
import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;
public class VideoList extends AppCompatActivity {
@BindView(R.id.listView)
ListView listView;
@BindView(R.id.tv_nomedia)
TextView tvNomedia;
@BindView(R.id.pb_loading)
ProgressBar pbLoading;
private VideoListAdapter videoPagerAdapter;
* 装数据集合
private ArrayList<MediaItem> mediaItems;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (mediaItems != null && mediaItems.size() > 0) {
//有数据
//设置适配器
videoPagerAdapter = new VideoListAdapter(getApplication(),mediaItems,true);
listView.setAdapter(videoPagerAdapter);
//文本隐藏
tvNomedia.setVisibility(View.GONE);
} else {
//没有数据
//文本显示
tvNomedia.setVisibility(View.VISIBLE);
//隐藏progress
pbLoading.setVisibility(View.GONE);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_list);
ButterKnife.bind(this);
initData();
listView.setOnItemClickListener(new MyOnItemClickListener());
private void initData() {
getDataFromLocal();
class MyOnItemClickListener implements AdapterView.OnItemClickListener{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
MediaItem mediaItem = mediaItems.get(position);
//调起系统所有播放器--隐式意图
// Intent intent = new Intent();
// intent.setDataAndType(Uri.parse(mediaItem.getData()),"video/*");
// startActivity(intent);
//调用自己写的播放器,显示意图
// Intent intent = new Intent(getActivity(),SystemVideoPlayer.class);
// intent.setDataAndType(Uri.parse(mediaItem.getData()),"video/*");
// startActivity(intent);
//3、传递列表数据-对象-序列化
Intent intent = new Intent(getApplicationContext(),MainActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("videolist",mediaItems);
intent.putExtra("position",position);
intent.putExtras(bundle);
startActivity(intent);
* 从本地的sdcard得到数据
* 1、遍历sdcard ,后缀名
* 2、去数据库中获取,内容提供者
* 3、如果是6.0系统需要动态读取sdcand权限
public void getDataFromLocal() {
new Thread() {
@Override
public void run() {
super.run();
mediaItems = new ArrayList<>();
ContentResolver resolver = getContentResolver();
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] objs = {
MediaStore.Video.Media.DISPLAY_NAME,//视屏文件在sdcard的名称
MediaStore.Video.Media.DURATION,//视屏总时长
MediaStore.Video.Media.SIZE,//视屏的文件大小
MediaStore.Video.Media.DATA,//视屏的绝对地址
MediaStore.Video.Media.ARTIST,//歌曲的演唱者
Cursor cursor = resolver.query(uri, objs, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
MediaItem mediaItem = new MediaItem();
String name = cursor.getString(0);//视频名称
mediaItem.setName(name);
long duration = cursor.getLong(1);//视频的时长
mediaItem.setDuration(duration);
long size = cursor.getLong(2);//视频大小
mediaItem.setSize(size);
String data = cursor.getString(3);//视频播放地址
mediaItem.setData(data);
String artist = cursor.getString(4);//艺术家
mediaItem.setArtist(artist);
mediaItems.add(mediaItem);//可以写在上面
cursor.close();
//Handler发消息
handler.sendEmptyMessage(10);
}.start();
}
7、因为需要设置播放器大小,一次自定义一个view,然后继承vitamio的videoView
package com.example.apple.vitamiodemo.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
import io.vov.vitamio.widget.VideoView;
* Created by apple on 17/3/6.
public class MyVideoView extends VideoView{
* 在代码中创建的时候一般用这个方法
* @param context
public MyVideoView(Context context) {
super(context,null);
* 当这个类在布局文件的时候,系统通过该构造方法实例化该类
* @param context
* @param attrs
public MyVideoView(Context context, AttributeSet attrs) {
super(context, attrs,0);
* 当需要设置样式的时候调用该方法
* @param context
* @param attrs
* @param defStyleAttr
public MyVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
* 设置视频宽高
* @param videoWidth
* @param videoHeight
public void setVideoSize(int videoWidth,int videoHeight){
ViewGroup.LayoutParams params = getLayoutParams();
params.width = videoWidth;
params.height = videoHeight;
setLayoutParams(params);
//requestLayout();
}
8、实现布局代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:gravity="center">
<com.example.apple.vitamiodemo.view.MyVideoView
android:id="@+id/mVideoView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
<include
android:id="@+id/media_controller"
layout="@layout/activity_media_controller" />
<include
android:id="@+id/ll_buffer"
layout="@layout/ll_buffer" />
<include
android:id="@+id/ll_loading"
layout="@layout/ll_loading" />
</RelativeLayout>
用动态广播更新电量显示,注册广播
//注册电量广播
myReceiver = new MyReceiver();
IntentFilter intentFiler = new IntentFilter();
//当电量变化的时候发送广播
intentFiler.addAction(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(myReceiver, intentFiler);
/**
* 电量变化广播
class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int level = intent.getIntExtra("level", 0);//电量 0~100
setBattery(level);
}
/**
* 电量图标显示
* @param level 电量
public void setBattery(int level) {
if (level <= 0) {//电量为0
ivBattery.setImageResource(R.drawable.ic_battery_0);
} else if (level <= 10) {
ivBattery.setImageResource(R.drawable.ic_battery_10);
} else if (level <= 20) {
ivBattery.setImageResource(R.drawable.ic_battery_20);
} else if (level <= 40) {
ivBattery.setImageResource(R.drawable.ic_battery_40);
} else if (level <= 60) {
ivBattery.setImageResource(R.drawable.ic_battery_60);
} else if (level <= 80) {
ivBattery.setImageResource(R.drawable.ic_battery_80);
} else if (level <= 100) {
ivBattery.setImageResource(R.drawable.ic_battery_100);
} else {
ivBattery.setImageResource(R.drawable.ic_battery_100);
}
左边上下滑动改变亮度,右边上下滑动改变音量
@Override
public boolean onTouchEvent(MotionEvent event) {
//3、把事件传递给手势识别器
detector.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://手指按下
//1、按下去
startY = event.getY();
startX = event.getX();
mVol = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);//按下获取音量
touchRang = Math.min(screenHeight, screenWidth);//获取屏幕最小值即高度
handler.removeMessages(HIDE_MEDIA_CONTROLLER);
break;
case MotionEvent.ACTION_MOVE:
//移动的纪录相关值
float endY = event.getY();
float endX = event.getX();
float distanceY = endY - startY;
if (endX<screenWidth/2){
//左边屏幕--调节亮度
final double FLING_MIN_DISTANCE = 0.5;
final double FLING_MIN_VELOCITY = 0.5;
if (startY - endY > FLING_MIN_DISTANCE
&& Math.abs(distanceY) > FLING_MIN_VELOCITY) {
Log.e(TAG, "up");
setBrightness(20);
if (startY - endY < FLING_MIN_DISTANCE
&& Math.abs(distanceY) > FLING_MIN_VELOCITY) {
Log.e(TAG, "down");
setBrightness(-20);
}else {
//右边--调节声音
Log.e(TAG, "MotionEvent ACTION_MOVE distanceY=" + distanceY);
//改变的音量 = (滑动屏幕的距离:总距离)* 音量最大值
float delta = (distanceY / touchRang) * maxVoice;
//最终的音量 = 原来的 + 改变的
int voice = (int) Math.min(Math.max((mVol + delta), 0), maxVoice);
//加个距离判断防止误触
if ((delta != 0 && distanceY > 5) || (delta != 0 && distanceY < -5)) {
isMute = false;//设置非静音
updateVoice(voice, false);
//Log.e(TAG,"MotionEvent voice"+voice);
break;
case MotionEvent.ACTION_UP:
handler.sendEmptyMessageDelayed(HIDE_MEDIA_CONTROLLER, 4000);
break;
return super.onTouchEvent(event);
* 设置屏幕亮度 lp = 0 全暗 ,lp= -1,根据系统设置, lp = 1; 最亮
private Vibrator vibrator;
public void setBrightness(float brightness) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
// if (lp.screenBrightness <= 0.1) {
// return;
lp.screenBrightness = lp.screenBrightness + brightness / 255.0f;
if (lp.screenBrightness > 1) {
lp.screenBrightness = 1;
vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
long[] pattern = { 10, 200 }; // OFF/ON/OFF/ON...
vibrator.vibrate(pattern, -1);
} else if (lp.screenBrightness < 0.2) {
lp.screenBrightness = (float) 0.2;
vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
long[] pattern = { 10, 200 }; // OFF/ON/OFF/ON...
vibrator.vibrate(pattern, -1);
Log.e(TAG, "lp.screenBrightness= " + lp.screenBrightness);
getWindow().setAttributes(lp);
}
完整实现代码
package com.example.apple.vitamiodemo;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import com.example.apple.vitamiodemo.data.MediaItem;
import com.example.apple.vitamiodemo.utils.Utils;
import com.example.apple.vitamiodemo.view.MyVideoView;
import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import io.vov.vitamio.LibsChecker;
import io.vov.vitamio.MediaPlayer;
import io.vov.vitamio.Vitamio;
public class MainActivity extends Activity {
private final String TAG = "MainActivity";
//视频进度的更新
private static final int PROGRESS = 1;
* 控制面板显隐
private static final int HIDE_MEDIA_CONTROLLER = 2;
private static final int FULL_SCREEN = 3;
* 默认屏幕
private static final int DEFAULT_FULL_SCREEN = 5;
* 网络速度
private static final int SHOW_SPEED = 4;
@BindView(R.id.mVideoView)
MyVideoView mVideoView;
@BindView(R.id.tv_name)
TextView tvName;
@BindView(R.id.iv_battery)
ImageView ivBattery;
@BindView(R.id.tv_system_time)
TextView tvSystemTime;
@BindView(R.id.btn_voice)
Button btnVoice;
@BindView(R.id.seekbar_voice)
SeekBar seekbarVoice;
@BindView(R.id.btn_switch_player)
Button btnSwitchPlayer;
@BindView(R.id.ll_top)
LinearLayout llTop;
@BindView(R.id.tv_current_time)
TextView tvCurrentTime;
@BindView(R.id.seekbar_video)
SeekBar seekbarVideo;
@BindView(R.id.tv_duration)
TextView tvDuration;
@BindView(R.id.btn_exit)
Button btnExit;
@BindView(R.id.btn_video_pre)
Button btnVideoPre;
@BindView(R.id.btn_video_start_pause)
Button btnVideoStartPause;
@BindView(R.id.btn_video_next)
Button btnVideoNext;
@BindView(R.id.btn_video_siwch_screen)
Button btnVideoSiwchScreen;
@BindView(R.id.ll_bottom)
LinearLayout llBottom;
@BindView(R.id.tv_buffer_netSpeed)
TextView tvBufferNetSpeed;
@BindView(R.id.tv_loading_netSpeed)
TextView tvLoadingNetSpeed;
private LinearLayout ll_loading;
private RelativeLayout media_controller;
private LinearLayout ll_buffer;
* 视频真实宽高
private int mVideoWidth = 0;
private int mVideoHeight = 0;
* 屏幕宽高
private int screenWidth = 0;
private int screenHeight = 0;
* 是否全屏
private boolean isFullScreen = false;
* 调节声音
private AudioManager am;
* 当前声音
private int currentVolue;
* 最大音量 0~15
private int maxVoice;
* 是否是静音
private boolean isMute = false;
private float startY;
private float startX;
//屏幕的高
private float touchRang;
private int mVol;
* 定义手势识别器
private GestureDetector detector;
* 是否显示控制面板
private boolean isShowMediaController = false;
* 传进来的视频列表
private ArrayList<MediaItem> mediaItems;
private String path = "http://data.vod.itc.cn/?rb=1&prot=1&key=jbZhEJhlqlUN-Wj_HEI8BjaVqKNFvDrn&prod=flash&pt=1&new=/86/168/RUXzy059JIvGRrrXQvOkNE.mp4";
private Uri uri;
* 是否是网络uri
private boolean isNetUri;
* 列表中播放的位置
private int position;
private Utils utils;
//是否系统
private boolean isUseSystem = true;
* 上一次播放进度
private int preCurrentPosition;
* 监听电量变化广播
private MyReceiver myReceiver;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case PROGRESS:
//得到当前的视频的播放进程
int currentPosition = (int) mVideoView.getCurrentPosition();
//seekbar.setProgress(当前进度)
seekbarVideo.setProgress(currentPosition);
//更新播放进度
tvCurrentTime.setText(utils.stringForTime(currentPosition));
//设置系统时间
tvSystemTime.setText(utils.getSystemTime());
seekbarVideo.setSecondaryProgress(0);
//缓存进度的更新
if (isNetUri) {
//网络地址
int buffer = mVideoView.getBufferPercentage();//0~100
int totalBuffer = buffer * seekbarVideo.getMax();
int secondaryProgress = totalBuffer / 100;
seekbarVideo.setSecondaryProgress(secondaryProgress);
} else {
//本地地址
seekbarVideo.setSecondaryProgress(0);
//监听卡
if (!isUseSystem && mVideoView.isPlaying()) {
if (mVideoView.isPlaying()) {
int buffer = currentPosition - preCurrentPosition;
if (buffer < 500) {
//视频卡了
ll_buffer.setVisibility(View.VISIBLE);
} else {
//视频不卡了
ll_buffer.setVisibility(View.GONE);
} else {
ll_buffer.setVisibility(View.GONE);
preCurrentPosition = currentPosition;
//每秒更新一次
handler.removeMessages(PROGRESS);
handler.sendEmptyMessageDelayed(PROGRESS, 1000);
break;
case SHOW_SPEED://显示网速
//得到网速
String netSpeed = utils.showNetSpeed(getApplication());
tvLoadingNetSpeed.setText("加载中" + netSpeed);
tvLoadingNetSpeed.setText("缓存中" + netSpeed);
//两秒一次
handler.removeMessages(SHOW_SPEED);
handler.sendEmptyMessageDelayed(SHOW_SPEED, 2000);
break;
case HIDE_MEDIA_CONTROLLER://隐藏控制面板
hideMediaController();
break;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Vitamio.isInitialized(this);//vitamio播放器初始化
// if (!LibsChecker.checkVitamioLibs(this))
// return;
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
initView();
initData();
getData();
setData();
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
//加载页面消掉
ll_loading.setVisibility(View.GONE);
// optional need Vitamio 4.0
// mediaPlayer.setPlaybackSpeed(1.0f);
mVideoWidth = mediaPlayer.getVideoWidth();
mVideoHeight = mediaPlayer.getVideoHeight();
mVideoView.start();//开始播放
long duration = mVideoView.getDuration();//得到总时长
seekbarVideo.setMax((int) duration);//设置最大值
tvDuration.setText(utils.stringForTime((int) duration));
//设置视频宽高
setVideoType(DEFAULT_FULL_SCREEN);
//发消息
handler.sendEmptyMessage(PROGRESS);
mVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
showErrorDialog();
Toast.makeText(getApplication(), "播放出错!!!", Toast.LENGTH_SHORT).show();
return true;
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
playNextVideo();
//视频拖动监听
seekbarVideo.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
* 当手指滑动的时候,引起seekBar进度变化
* @param seekBar
* @param progress
* @param fromUser 如果是用户引起的是true 不是用户引起的是false
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
mVideoView.seekTo(progress);
* 当手指触碰的时候回调这个方法
* @param seekBar
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
handler.removeMessages(HIDE_MEDIA_CONTROLLER);
* 当手指离开的时候
* @param seekBar
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
handler.sendEmptyMessageDelayed(HIDE_MEDIA_CONTROLLER, 4000);
* 声音进度条
seekbarVoice.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
Log.e(TAG, "setOnSeekBarChangeListener progress=" + progress + "fromUser=" + fromUser);
if (fromUser) {
//更新音量
if (progress > 0) {
isMute = false;
} else {
isMute = true;
Log.e(TAG, "updateVoice(progress, isMute);");
updateVoice(progress, isMute);
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (isUseSystem) {
//监听视频播放卡,系统api
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
mVideoView.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
switch (what) {
case MediaPlayer.MEDIA_INFO_BUFFERING_START://视频卡顿了,拖动卡
//Toast.makeText(getApplication(),"卡了",Toast.LENGTH_SHORT).show();
ll_buffer.setVisibility(View.VISIBLE);
break;
case MediaPlayer.MEDIA_INFO_BUFFERING_END://视频卡结束了,拖动卡结束
ll_buffer.setVisibility(View.GONE);
// Toast.makeText(getApplication(),"卡结束了",Toast.LENGTH_SHORT).show();
break;
return false;
@OnClick({R.id.btn_voice, R.id.btn_switch_player, R.id.btn_exit, R.id.btn_video_pre, R.id.btn_video_start_pause, R.id.btn_video_next, R.id.btn_video_siwch_screen})
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_voice:
isMute = !isMute;
updateVoice(currentVolue, isMute);
break;
case R.id.btn_switch_player:
break;
case R.id.btn_exit:
finish();
break;
case R.id.btn_video_pre:
playPreVideo();
break;
case R.id.btn_video_start_pause:
startAndPause();
break;
case R.id.btn_video_next:
playNextVideo();
break;
case R.id.btn_video_siwch_screen:
setFullScreenAndDefault();//设置全屏与默认
break;
* 初始化view
private void initView() {
utils = new Utils();
ll_loading = (LinearLayout) findViewById(R.id.ll_loading);
ll_loading.setVisibility(View.GONE);
media_controller = (RelativeLayout) findViewById(R.id.media_controller);
ll_buffer = (LinearLayout) findViewById(R.id.ll_buffer);
ll_buffer.setVisibility(View.GONE);
//开始更新网络速度
handler.sendEmptyMessage(SHOW_SPEED);
* 初始化数据
private void initData() {
//注册电量广播
myReceiver = new MyReceiver();
IntentFilter intentFiler = new IntentFilter();
//当电量变化的时候发送广播
intentFiler.addAction(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(myReceiver, intentFiler);
* 2、实例化手势识别器,并且重写双击,点击和长按
detector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
* @param e
@Override
public void onLongPress(MotionEvent e) {
Log.e(TAG, "onLongPress");
// Toast.makeText(getApplication(),"onLongPress",Toast.LENGTH_SHORT).show();
startAndPause();
super.onLongPress(e);
* @param e
* @return
@Override
public boolean onDoubleTap(MotionEvent e) {
Log.e(TAG, "onDoubleTap");
setFullScreenAndDefault();
// videoView.setVideoSize(500, 500);
return super.onDoubleTap(e);
* @param e
* @return
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
Log.e(TAG, "onSingleTapConfirmed");
if (isShowMediaController) {
hideMediaController();//隐藏控制面板
//把隐藏消息移除
handler.removeMessages(HIDE_MEDIA_CONTROLLER);
} else {
showMediaController();//显示控制面板
//发消息隐藏
handler.sendEmptyMessageDelayed(HIDE_MEDIA_CONTROLLER, 4000);
//Toast.makeText(getApplication(),"onSingleTapConfirmed",Toast.LENGTH_SHORT).show();
return super.onSingleTapConfirmed(e);
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
//得到屏幕宽高像素
screenWidth = displayMetrics.widthPixels;
screenHeight = displayMetrics.heightPixels;
//得到音量,设置音量
am = (AudioManager) getSystemService(AUDIO_SERVICE);
currentVolue = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
maxVoice = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
//最大音量
seekbarVoice.setMax(maxVoice);
Log.e(TAG, "maxVoice===" + maxVoice + " initData currentVolue=" + currentVolue);
//设置音量
seekbarVoice.setProgress(currentVolue);
* 获取数据
private void getData() {
//得到播放地址,视频播放器会被调起并且播放
uri = getIntent().getData();//文件夹,图片浏览器,qq空间
mediaItems = (ArrayList<MediaItem>) getIntent().getSerializableExtra("videolist");
position = getIntent().getIntExtra("position", 0);
if (uri != null) {
mVideoView.setVideoURI(uri);//设置播放地址,开始播放
* 设置数据
private void setData() {
if (mediaItems != null && mediaItems.size() > 0) {
MediaItem mediaItem = mediaItems.get(position);
tvName.setText(mediaItem.getName());//显示视频的名字
mVideoView.setVideoPath(mediaItem.getData());//设置地址
isNetUri = utils.isNetUri(mediaItem.getData());
} else if (uri != null) {
tvName.setText(uri.toString());//设置视频的名称
isNetUri = utils.isNetUri(uri.toString());
mVideoView.setVideoURI(uri);//设置播放地址,以Uri的方式设置VideoView播放的视频源,可以是网络Uri或本地Uri。
} else {
Toast.makeText(this, "没有数据传递过来", Toast.LENGTH_SHORT).show();
setButtonState();
* 播放出错弹的提示dialog
private void showErrorDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示");
builder.setMessage("抱歉,无法播放该视频");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
builder.show();
* 播放上一个视频
private void playPreVideo() {
if (mediaItems != null && mediaItems.size() > 0) {
//播放下一个
position--;
if (position >= 0) {
ll_loading.setVisibility(View.VISIBLE);
MediaItem mediaItem = mediaItems.get(position);
tvName.setText(mediaItem.getName());
isNetUri = utils.isNetUri(mediaItem.getData());
mVideoView.setVideoPath(mediaItem.getData());
//设置按钮状态
setButtonState();
} else if (uri != null) {
//上一个和下一个按钮设置不可操作 //设置按钮状态
setButtonState();
* 开始播放和暂停播放
private void startAndPause() {
if (mVideoView.isPlaying()) {
//视频播放-设置暂停
mVideoView.pause();
//按钮状态设置播放
btnVideoStartPause.setBackgroundResource(R.drawable.btn_video_pause_selector2);
Log.e(TAG,"pause");
} else {
//视频播放
mVideoView.start();
//按钮暂停
btnVideoStartPause.setBackgroundResource(R.drawable.btn_video_pause_selector);
Log.e(TAG,"start");
* 播放下一个
private void playNextVideo() {
if (mediaItems != null && mediaItems.size() > 0) {
//播放下一个
position++;
if (position < mediaItems.size()) {
ll_loading.setVisibility(View.VISIBLE);
MediaItem mediaItem = mediaItems.get(position);
tvName.setText(mediaItem.getName());//设置视频名称
isNetUri = utils.isNetUri(mediaItem.getData());//判断是否是网络视频
mVideoView.setVideoPath(mediaItem.getData());
//设置按钮状态
setButtonState();
} else if (uri != null) {
//上一个和下一个按钮设置不可操作
//设置按钮状态
setButtonState();
* 全屏与默认切换
private void setFullScreenAndDefault() {
if (isFullScreen) {
setVideoType(DEFAULT_FULL_SCREEN);
} else {
setVideoType(FULL_SCREEN);
private void setVideoType(int defaultFullScreen) {
switch (defaultFullScreen) {
case FULL_SCREEN://全屏
//1、设置视频画面大小 屏幕大小
mVideoView.setVideoSize(screenWidth, screenHeight);
//2、设置按钮状态
btnVideoSiwchScreen.setBackgroundResource(R.drawable.btn_video_siwch_screen_default_selector);
//3、全屏
isFullScreen = true;
break;
case DEFAULT_FULL_SCREEN://默认
//1、设置视频画面大小
//屏幕宽高
int height = screenHeight;
int width = screenWidth;
// for compatibility, we adjust size based on aspect ratio
if (mVideoWidth * height < width * mVideoHeight) {
//Log.i("@@@", "image too wide, correcting");
width = height * mVideoWidth / mVideoHeight;
} else if (mVideoWidth * height > width * mVideoHeight) {
//Log.i("@@@", "image too tall, correcting");
height = width * mVideoHeight / mVideoWidth;
mVideoView.setVideoSize(width, height);
//2、设置按钮状态
btnVideoSiwchScreen.setBackgroundResource(R.drawable.btn_video_siwch_screen_selector);
isFullScreen = false;
break;
* 设置按钮状态
private void setButtonState() {
if (mediaItems != null && mediaItems.size() > 0) {
if (mediaItems.size() == 1) {
//两个按钮设置灰色
setEnableFalse();
} else if (mediaItems.size() == 2) {
if (position == 0) {
//两个按钮设置灰色
btnVideoPre.setBackgroundResource(R.drawable.video_pre_gray);
btnVideoPre.setEnabled(false);
btnVideoNext.setBackgroundResource(R.drawable.btn_video_next_selector);
btnVideoNext.setEnabled(true);
} else if (position == 1) {
//下一个按钮不可操作
btnVideoNext.setBackgroundResource(R.drawable.video_next_btn_bg);
btnVideoNext.setEnabled(false);
btnVideoPre.setBackgroundResource(R.drawable.btn_video_pre_selector);
btnVideoPre.setEnabled(true);
} else {
if (position == 0) {
//两个按钮设置灰色
btnVideoPre.setBackgroundResource(R.drawable.video_pre_gray);
btnVideoPre.setEnabled(false);
} else if (position == mediaItems.size() - 1) {
//下一个按钮不可操作
btnVideoNext.setBackgroundResource(R.drawable.video_next_btn_bg);
btnVideoNext.setEnabled(false);
} else {
btnVideoPre.setBackgroundResource(R.drawable.btn_video_pre_selector);
btnVideoPre.setEnabled(true);
btnVideoNext.setBackgroundResource(R.drawable.btn_video_next_selector);
btnVideoNext.setEnabled(true);
} else if (uri != null) {
//两个按钮设置灰色
setEnableFalse();
* //两个按钮设置灰色
private void setEnableFalse() {
btnVideoPre.setBackgroundResource(R.drawable.video_pre_gray);
btnVideoPre.setEnabled(false);
btnVideoNext.setBackgroundResource(R.drawable.video_next_btn_bg);
btnVideoNext.setEnabled(false);
* 显示控制面板
private void showMediaController() {
media_controller.setVisibility(View.VISIBLE);
isShowMediaController = true;
* 隐藏控制面板
private void hideMediaController() {
media_controller.setVisibility(View.GONE);
isShowMediaController = false;
@Override
protected void onDestroy() {
super.onDestroy();
//移除所有消息
handler.removeCallbacksAndMessages(null);
if (myReceiver != null) {
unregisterReceiver(myReceiver);
myReceiver = null;
@Override
public boolean onTouchEvent(MotionEvent event) {
//3、把事件传递给手势识别器
detector.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://手指按下
//1、按下去
startY = event.getY();
startX = event.getX();
mVol = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);//按下获取音量
touchRang = Math.min(screenHeight, screenWidth);//获取屏幕最小值即高度
handler.removeMessages(HIDE_MEDIA_CONTROLLER);
break;
case MotionEvent.ACTION_MOVE:
//移动的纪录相关值
float endY = event.getY();
float endX = event.getX();
float distanceY = endY - startY;
if (endX<screenWidth/2){
//左边屏幕--调节亮度
final double FLING_MIN_DISTANCE = 0.5;
final double FLING_MIN_VELOCITY = 0.5;
if (startY - endY > FLING_MIN_DISTANCE
&& Math.abs(distanceY) > FLING_MIN_VELOCITY) {
Log.e(TAG, "up");
setBrightness(20);
if (startY - endY < FLING_MIN_DISTANCE
&& Math.abs(distanceY) > FLING_MIN_VELOCITY) {
Log.e(TAG, "down");
setBrightness(-20);
}else {
//右边--调节声音
Log.e(TAG, "MotionEvent ACTION_MOVE distanceY=" + distanceY);
//改变的音量 = (滑动屏幕的距离:总距离)* 音量最大值
float delta = (distanceY / touchRang) * maxVoice;
//最终的音量 = 原来的 + 改变的
int voice = (int) Math.min(Math.max((mVol + delta), 0), maxVoice);
//加个距离判断防止误触
if ((delta != 0 && distanceY > 5) || (delta != 0 && distanceY < -5)) {
isMute = false;//设置非静音
updateVoice(voice, false);
//Log.e(TAG,"MotionEvent voice"+voice);
break;
case MotionEvent.ACTION_UP:
handler.sendEmptyMessageDelayed(HIDE_MEDIA_CONTROLLER, 4000);
break;
return super.onTouchEvent(event);
* 设置屏幕亮度 lp = 0 全暗 ,lp= -1,根据系统设置, lp = 1; 最亮
private Vibrator vibrator;
public void setBrightness(float brightness) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
// if (lp.screenBrightness <= 0.1) {
// return;
lp.screenBrightness = lp.screenBrightness + brightness / 255.0f;
if (lp.screenBrightness > 1) {
lp.screenBrightness = 1;
vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
long[] pattern = { 10, 200 }; // OFF/ON/OFF/ON...
vibrator.vibrate(pattern, -1);
} else if (lp.screenBrightness < 0.2) {
lp.screenBrightness = (float) 0.2;
vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
long[] pattern = { 10, 200 }; // OFF/ON/OFF/ON...
vibrator.vibrate(pattern, -1);
Log.e(TAG, "lp.screenBrightness= " + lp.screenBrightness);
getWindow().setAttributes(lp);
* 物理按键控制
* @param keyCode
* @param event
* @return
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.e(TAG, "onKeyDown currentVolue = " + currentVolue);
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
currentVolue--;
updateVoice(currentVolue, false);
handler.removeMessages(HIDE_MEDIA_CONTROLLER);
handler.sendEmptyMessageDelayed(HIDE_MEDIA_CONTROLLER, 4000);
return true;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
currentVolue++;
updateVoice(currentVolue, false);
handler.removeMessages(HIDE_MEDIA_CONTROLLER);
handler.sendEmptyMessageDelayed(HIDE_MEDIA_CONTROLLER, 4000);
return true;
return super.onKeyDown(keyCode, event);
* 设置音量大小
* @param progress 进度条值
* @param isMute 是否静音
private void updateVoice(int progress, boolean isMute) {
if (isMute) {
am.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0);//1调系统
seekbarVoice.setProgress(0);
} else {
am.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0);//1调系统
seekbarVoice.setProgress(progress);
currentVolue = progress;
Log.e(TAG, "updateVoice currentVolue=" + currentVolue);
* 电量图标显示
* @param level 电量
public void setBattery(int level) {
if (level <= 0) {//电量为0
ivBattery.setImageResource(R.drawable.ic_battery_0);
} else if (level <= 10) {
ivBattery.setImageResource(R.drawable.ic_battery_10);
} else if (level <= 20) {
ivBattery.setImageResource(R.drawable.ic_battery_20);
} else if (level <= 40) {
ivBattery.setImageResource(R.drawable.ic_battery_40);
} else if (level <= 60) {
ivBattery.setImageResource(R.drawable.ic_battery_60);
} else if (level <= 80) {
ivBattery.setImageResource(R.drawable.ic_battery_80);
} else if (level <= 100) {
ivBattery.setImageResource(R.drawable.ic_battery_100);
} else {
ivBattery.setImageResource(R.drawable.ic_battery_100);
* 电量变化广播
class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int level = intent.getIntExtra("level", 0);//电量 0~100
setBattery(level);
}
实现效果图:
最后代码下载地址:https://github.com/ningxingxing/vitamio
注意:在小米手机上测试出现了bug,无法播放,需要在加载布局之前添加下面代码
// ~~~ 检测Vitamio是否解压解码包
if (!LibsChecker.checkVitamioLibs(this))
return;
好帅的小刀 · sql server like 优化-掘金 1 年前 |