多媒体播放
来源:互联网 发布:怎么切换网络节点 编辑:程序博客网 时间:2024/04/30 18:06
一、VideoView播放视频
1.1 简介:
VideoView,用于播放一段视频媒体,它继承了SurfaceView,位于"android.widget.VideoView",是一个视频控件。
1.2 使用
- 权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
- 布局:
<?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="#88000000"
>
<VideoView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/vvtest"
android:layout_centerInParent="true"
/>
</RelativeLayout>
- 播放手机中的本地视频:
private final String strVideoPath = "/sdcard/Download/splash.mp4";
vvTest.setVideoPath(strVideoPath);
vvTest.start();
- 播放网络视频:
加入网络权限
<uses-permission android:name="android.permission.INTERNET"/>
设定网络视频地址并播放:
private final String strVideoUrl = "http://qv1.fit-time.cn/rockfit-vicky-plt-medium-6.mp4";
vvTest.setVideoPath(strVideoPath);
vvTest.start();
- 播放视频资源(res/raw下面的视频):
String struri = "android.resource://"+ getPackageName() +"/" + R.raw.splash;
Uri uri = Uri.parse(struri);
vvTest.setVideoURI(uri);//vvTest.setVideoPath(struri);也可以
vvTest.start();
- 获取视频总时长--getDuration:
vvTest.setOnPreparedListener(newMediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
int iDuration =vvTest.getDuration();
Log.d("qf","视频总时长:"+iDuration);
}
});
要在视频装载完成的监听事件中,才能获得视频的准确时长,否则的话,比如在start之前或之后获取时长可能是-1
- 跳到视频设定的位置(seekTo):
mac下模拟器中很多视频不能播放,能播放的拖动可能也有问题(用系统播放器播放也有同样的问题),所以此处使用真机测试
如果seekto方法不能正确执行,可以看下视频源在自带播放器中是否可以正常拖拉
seekto是异步执行的,不需要在视频装载完成后调用,在setVideoPath后调用就可以了(start前后调用都可以)
String struri = "android.resource://"+ getPackageName() +"/" + R.raw.db;
vvTest.setVideoPath(struri);
vvTest.seekTo(60*1000);
vvTest.start();
- 获取当前播放到的时长(getCurrentPosition)
String struri = "android.resource://"+ getPackageName() +"/" + R.raw.db;
vvTest.setVideoPath(struri);
vvTest.start();
new Handler().postDelayed(newRunnable() {
@Override
public void run() {
int iCurPos =vvTest.getCurrentPosition();
Log.e("qf","当前播放时长:"+iCurPos);
}
}, 6000);
6s后获取当前播放的时长(单位ms),打印出来可能是5点几秒,因为start后不一定马上播放,要准备一点时间,帧的时隙也会有影响
- 判断当前是否播放状态:isPlaying
- 暂停:pause
- 停止:stopPlayback
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (vvTest.isPlaying()){
vvTest.pause();
}
}
}, 6000);
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (!vvTest.isPlaying()){
vvTest.start();
}
}
}, 10000);
handler.postDelayed(new Runnable() {
@Override
public void run() {
vvTest.stopPlayback();
}
}, 15000);
播放视频中间按home键,再调出视频播放界面时接着播放:
@Override
protected void onPause() {
super.onPause();
iStopPos =vvTest.getCurrentPosition();//保存切换时的进度
vvTest.pause();
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onStart() {
super.onStart();
vvTest.seekTo(iStopPos);//调到保存的进度中
vvTest.start();
}
不能在onStop中写onPause的那两句代码,onStop时,videoview当前进度已经被重置为0了
- 播放完毕的监听:setOnCompletionListener
vvTest.setOnCompletionListener(newMediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
Log.e("qf","播放结束");
}
});
如果调用stopPlayback结束,不会调用这个监听方法,也不会调用error监听
- 播放错误时的监听:setOnErrorListener
vvTest.setOnErrorListener(newMediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, intwhat, intextra) {
Log.e("qf","发生错误");
return false;
}
});
发生错误,比如播放一个不能播放的视频时,调用此监听
- 全屏播放:
第一种方法,在布局中定义:
<?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="#88000000"
>
<VideoView
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/vvtest"
android:layout_centerInParent="true"
/>
</RelativeLayout>
第二种方法,代码里实现对布局的控制:
RelativeLayout.LayoutParams layoutParams=
new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.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);
vvTest.setLayoutParams(layoutParams);
第三种方法,重写onMeasure方法:
public class MyVideoViewextendsVideoView {
private int mVideoWidth;
private int mVideoHeight;
public MyVideoView(Context context) {
super(context);
}
public MyVideoView(Context context,AttributeSet attrs) {
this(context,attrs,0);
}
public MyVideoView(Context context,AttributeSet attrs, intdefStyle) {
super(context,attrs,defStyle);
}
public void setDimensions(intw, inth) {
this.mVideoWidth= h;
this.mVideoHeight= w;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getDefaultSize(mVideoWidth,widthMeasureSpec);
int height = getDefaultSize(mVideoHeight,heightMeasureSpec);
setMeasuredDimension(width,height);
}
}
getDefaultSize:得到设置的宽或高,第一个参数是默认size,第二个参数是父控件约束的值,只有第二个参数不约束的时候,才会采用第一个值
setMeasuredDimension:真正把宽高应用到控件的方法,父控件的onMeasure最终也是调用这个方法
使用这个自定义的VideoView后,宽高就可以由布局文件的设置决定了,比如设置为match_parent就可以使视频全屏播放了
<?xml version="1.0"encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.zhouyi.videoviewtest.MyVideoView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/myvv"/>
</LinearLayout>
可以看下VideView的源码中onMeasure方法,里面通过计算,对videoview的宽高做了约束,使之匹配所播放视频的真实宽高比
- 横竖屏切换
点击按钮横竖屏切换:
public void onChange(View view) {
int iOrientation = getRequestedOrientation();
if (iOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else{
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
如果之前没有调用setRequestedOrientation或在xml设置activity的方向,getRequestedOrientation会返回-1,所以先在xml中配置好方向或在oncreate中setRequestedOrientation为固定方向
默认情况下,横竖屏切换会销毁原来的activity,重新建立一个activity,这样视频就会重头开始播放,如果要在切换视频时,不重头播放,需要在清单文件的activity中加入如下配置(android3.2以后):
android:configChanges="keyboardHidden|orientation|screenSize"
Andorid 3.2以前的SDK可以使用如下配置
android:configChanges="orientation|keyboardHidden”
configChanges配置表示在发生配置所指定的变化时会通知系统调用onConfigurationChanged方法(比如orientation表示发生屏幕方向变化时调用onConfigurationChanged方法)
配置了这个属性,不会销毁原来的activity再重新创建,这样就不会走一遍生命周期,只会调用onConfigurationChanged方法
在onConfigurationChanged方法中重新设置videoview大小:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation== Configuration.ORIENTATION_LANDSCAPE) {
vvTest.setDimensions(displayHeight,displayWidth);
vvTest.getHolder().setFixedSize(displayHeight,displayWidth);//使videoview重绘,触发onmeasure
} else if(newConfig.orientation== Configuration.ORIENTATION_PORTRAIT){
vvTest.setDimensions(displayWidth,displayHeight);
vvTest.getHolder().setFixedSize(displayWidth,displayHeight);
}
}
setFixedSize让设定的宽高起作用,固定为设置的宽高,否则重写的onmeasrue方法里面不会采用设定的size值,而是用系统测量的widthMeasureSpec/heightMeasureSpec
获取屏幕宽高:
WindowManager wm = this.getWindowManager();
displayWidth = wm.getDefaultDisplay().getWidth();
displayHeight = wm.getDefaultDisplay().getHeight();
- 使用MediaController做播放控制:
vvmc = (VideoView) findViewById(R.id.vvmc);
vvmc.setVideoPath(strVideoPath);
MediaController controller = newMediaController(this);
vvmc.setMediaController(controller);
二、MediaPlayer播放音视频:
2.1 简介:
VideoView其实是对MediaPlayer的封装,里面很多方法都是调用MediaPlayer对象实现的,MediaPlayer才是真正播放和控制音视频的类,VideoView使用起来更简单,但是MediaPlayer的定制性更好(品牌机和组装机的区别)
2.2 播放音频
- 播放本地音频
private MediaPlayer mp = new MediaPlayer();
String strSound = "/sdcard/Download/yy.mp3";
try {
mp.setDataSource(strSound);
mp.prepare();
mp.start();
} catch (IOException e) {
e.printStackTrace();
}
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
mp.pause();
}
}, 5000);
handler.postDelayed(new Runnable() {
@Override
public void run() {
mp.start();
}
}, 10000);
handler.postDelayed(new Runnable() {
@Override
public void run() {
mp.stop();
}
}, 15000);
prepare用于播放前的准备,必须调用,是同步执行的
- 播放网络音频:
把地址变成网络地址,加上网络权限即可:
String strSound = "http://ok.96x.cn/2015/6yue_2651.cn/%E6%BC%94%E5%91%98%20-%20%E8%96%9B%E4%B9%8B%E8%B0%A6.mp3";
prepare是同步执行的,所以最好放到子线程中,准备完毕后通知主线程播放,否则会阻塞主线程
也可以调用异步prepare,prepareAsync():
String strSound = "http://ok.96x.cn/2015/6yue_2651.cn/%E6%BC%94%E5%91%98%20-%20%E8%96%9B%E4%B9%8B%E8%B0%A6.mp3";
try {
mp.setDataSource(strSound);
mp.prepareAsync();
mp.setOnPreparedListener(newMediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
} catch (IOException e) {
e.printStackTrace();
}
- 播放资源里的音频
mp = MediaPlayer.create(this,R.raw.yy);
mp.start();
create里面调用了prepare,不需要在外面调用了
- 释放资源
@Override
protected void onDestroy() {
super.onDestroy();
mp.release();
}
在程序销毁或之前,一定要调用
- 其他功能方法参照VideoView
- 2.3 播放视频:
- SurfaceView
surfaceView和View最本质的区别在于:
surfaceView是在一个新起的单独线程中可以重新绘制画面,而View必须在UI的主线程中更新画面。那么在UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。
SurfaceHolder.Callback会在SurfaceView创建,改变,销毁等事件发生时回调
- MediaPlayer+SurfaceView播放视频
MedeaPlayer本身没有画面输出机制,必须关联一个surfaceview,在surfaceview里面进行画面绘制
布局:
<?xml version="1.0"encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<SurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/sftest"/>
</LinearLayout>
不会保持宽高比,完全由布局的宽高决定视频大小
代码:
final String strVideoPath ="/sdcard/Download/splash.mp4";
SurfaceView sftest = (SurfaceView) findViewById(R.id.sftest);
mp = newMediaPlayer();
sftest.getHolder().addCallback(newSurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mp.setDisplay(holder);
mp.setDataSource(strVideoPath);
mp.prepare();
mp.start();
} catch(IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, intformat, intwidth, intheight) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
通过setdisplay方法把mediaplayer关联到一个surfaceview,视频是在surfaceview上绘制的
- MediaPlayer生命周期:
通过setLooping方法可以控制视频是否循环播放
通过reset方法可以重置视频,比如播放多个视频,第一个视频还没有播放完毕,用户触发播放第二个视频,就要先调用reset方法
里面的其他方法参考VideoPlayer部分,VideoPlayer其实是调用MediaPlayer相关生命周期方法
Idle 状态:当使用new()方法创建一个MediaPlayer对象或者调用了其reset()方法时,该MediaPlayer对象处于idle状态。
End 状态:通过release()方法可以进入End状态,只要MediaPlayer对象不再被使用,就应当尽快将其通过release()方法释放掉,以释放相关的软硬件组件资源。如果MediaPlayer对象进入了End状态,则不会在进入任何其他状态了
Initialized 状态:这个状态比较简单,MediaPlayer调用setDataSource()方法就进入Initialized状态,表示此时要播放的文件已经设置好了。
Prepared 状态:初始化完成之后还需要通过调用prepare()或prepareAsync()方法,这两个方法一个是同步的一个是异步的,只有进入Prepared状态,才表明MediaPlayer到目前为止都没有错误,可以进行文件播放。
Started 状态:显然,MediaPlayer一旦准备好,就可以调用start()方法,这样MediaPlayer就处于Started状态,这表明MediaPlayer正在播放文件过程中。可以使用isPlaying()测试MediaPlayer是否处于了Started状态。如果播放完毕,而又设置了循环播放,则MediaPlayer仍然会处于Started状态,类似的,如果在该状态下MediaPlayer调用了seekTo()或者start()方法均可以让MediaPlayer停留在Started状态。
Paused 状态:Started状态下MediaPlayer调用pause()方法可以暂停MediaPlayer,从而进入Paused状态,MediaPlayer暂停后再次调用start()则可以继续MediaPlayer的播放,转到Started状态,暂停状态时可以调用seekTo()方法,这是不会改变状态的。
Stop 状态:Started或者Paused状态下均可调用stop()停止MediaPlayer,而处于Stop状态的MediaPlayer要想重新播放,需要通过prepareAsync()和prepare()回到先前的Prepared状态重新开始才可以。
PlaybackCompleted状态:文件正常播放完毕,而又没有设置循环播放的话就进入该状态,并会触发OnCompletionListener的onCompletion()方法。此时可以调用start()方法重新从头播放文件,也可以stop()停止MediaPlayer,或者也可以seekTo()来重新定位播放位置。
Error状态:如果由于某种原因MediaPlayer出现了错误,会触发OnErrorListener.onError()事件,此时MediaPlayer即进入Error状态,及时捕捉并妥善处理这些错误是很重要的,可以帮助我们及时释放相关的软硬件资源,也可以改善用户体验。通过setOnErrorListener(android.media.MediaPlayer.OnErrorListener)可以设置该监听器。如果MediaPlayer进入了Error状态,可以通过调用reset()来恢复,使得MediaPlayer重新返回到Idle状态。
三、listview中播放视频(一般只同时播放一条,滑出屏幕外的暂停播放):
item布局:
<?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="300dp">
<VideoView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:id="@+id/vv_item"/>
<ImageView
android:id="@+id/video_image"
android:layout_width="fill_parent"
android:layout_height="300dp"
android:scaleType="fitXY"
android:background="@drawable/video2"
/>
<ImageButton
android:id="@+id/video_play_btn"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_centerInParent="true"
android:background="@drawable/ic_play_video"
/>
</RelativeLayout>
adapter:
package com.example.zhouyi.listitemvideo;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.VideoView;
import java.util.List;
public class MyAdapter extends BaseAdapter {
List<String> mListVideos;
Context mContext;
public MyAdapter(List<String> lstVides,Context context){
mListVideos = lstVides;
mContext = context;
}
@Override
public int getCount() {
return mListVideos.size();
}
@Override
public ObjectgetItem(intposition) {
return mListVideos.get(position);
}
@Override
public long getItemId(intposition) {
return position;
}
@Override
public ViewgetView(final intposition,View convertView,ViewGroup parent) {
final MyHolder holder;
if (convertView ==null){
convertView = LayoutInflater.from(mContext).inflate(R.layout.layout_item,parent,false);
VideoView vvtest = (VideoView) convertView.findViewById(R.id.vv_item);
ImageButton ivbtest = (ImageButton) convertView.findViewById(R.id.video_play_btn);
ImageView ivtest = (ImageView) convertView.findViewById(R.id.video_image);
holder = new MyHolder();
holder.vvtest= vvtest;
holder.ivbtest= ivbtest;
holder.ivtest= ivtest;
convertView.setTag(holder);
}else{
holder = (MyHolder) convertView.getTag();
}
holder.ivbtest.setOnClickListener(newView.OnClickListener() {
@Override
public void onClick(View v) {
holder.ivtest.setVisibility(View.GONE);
holder.ivbtest.setVisibility(View.GONE);
holder.vvtest.setVideoPath(mListVideos.get(position));
holder.vvtest.start();
}
});
return convertView;
}
class MyHolder{
public VideoViewvvtest;
public ImageViewivtest;
public ImageButtonivbtest;
}
}
初始化控件,解决复用时错位问题:
adapter中用一个成员变量mCurrentPos保存正在播放的item的position:
int mCurrentPos = -1;
如果不是正在播放的item,隐藏videoview
如果是正在播放的item,显示videoview,隐藏按钮和图片,开始播放
@Override
public ViewgetView(final intposition,View convertView,ViewGroup parent) {
final MyHolder holder;
if (convertView ==null){
convertView = LayoutInflater.from(mContext).inflate(R.layout.layout_item,parent,false);
VideoView vvtest = (VideoView) convertView.findViewById(R.id.vv_item);
ImageButton ivbtest = (ImageButton) convertView.findViewById(R.id.video_play_btn);
ImageView ivtest = (ImageView) convertView.findViewById(R.id.video_image);
holder = new MyHolder();
holder.vvtest= vvtest;
holder.ivbtest= ivbtest;
holder.ivtest= ivtest;
convertView.setTag(holder);
}else{
holder = (MyHolder) convertView.getTag();
}
if (position != mCurrentPos){
holder.ivbtest.setVisibility(View.VISIBLE);
holder.ivtest.setVisibility(View.VISIBLE);
}else {
holder.ivbtest.setVisibility(View.GONE);
holder.ivtest.setVisibility(View.GONE);
}
holder.ivbtest.setOnClickListener(newView.OnClickListener() {
@Override
public void onClick(View v) {
holder.ivtest.setVisibility(View.GONE);
holder.ivbtest.setVisibility(View.GONE);
mCurrentPos = position;
holder.vvtest.setVideoPath(mListVideos.get(position));
holder.vvtest.start();
}
});
return convertView;
}
当前item开始播放时,停止前面正在播放的视频:
首先在adpter中定义一个成员变量,存放目前正在播放视频的item对应的viewholder
MyHolder playingHolder=null;
用户点击下一个将要播放的视频时,在点击事件中,先停止当前播放的视频,并把按钮和图片设置为可见
@Override
public View getView(final intposition,View convertView,ViewGroup parent) {
final MyHolder holder;
if (convertView == null){
convertView = LayoutInflater.from(mContext).inflate(R.layout.layout_item,parent,false);
VideoView vvtest = (VideoView) convertView.findViewById(R.id.vv_item);
ImageButton ivbtest = (ImageButton) convertView.findViewById(R.id.video_play_btn);
ImageView ivtest = (ImageView) convertView.findViewById(R.id.video_image);
holder = new MyHolder();
holder.vvtest= vvtest;
holder.ivbtest= ivbtest;
holder.ivtest= ivtest;
convertView.setTag(holder);
}else{
holder = (MyHolder) convertView.getTag();
}
if (position !=mCurrentPos){
holder.ivbtest.setVisibility(View.VISIBLE);
holder.ivtest.setVisibility(View.VISIBLE);
}else{
holder.ivbtest.setVisibility(View.GONE);
holder.ivtest.setVisibility(View.GONE);
}
holder.ivbtest.setOnClickListener(newView.OnClickListener() {
@Override
public void onClick(View v) {
if (playingHolder != null){
if(playingHolder.vvtest.isPlaying()){
playingHolder.vvtest.stopPlayback();
playingHolder.ivbtest.setVisibility(View.VISIBLE);
playingHolder.ivtest.setVisibility(View.VISIBLE);
}
}
holder.ivtest.setVisibility(View.GONE);
holder.ivbtest.setVisibility(View.GONE);
mCurrentPos = position;
holder.vvtest.setVideoPath(mListVideos.get(position));
holder.vvtest.start();
playingHolder = holder;
}
});
return convertView;
}
item滑出屏幕时暂停播放:
在activity中回调listview的滑动事件,判断当前播放视频的item是否滑出屏幕之外,如果滑出了,暂停播放
lvtest.setOnScrollListener(newAbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, intscrollState) {
// TODO Auto-generated method stub
}
@Override
public void onScroll(AbsListView view, intfirstVisibleItem,
int visibleItemCount, inttotalItemCount) {
if (adapter.mCurrentPos< firstVisibleItem
|| adapter.mCurrentPos>lvtest.getLastVisiblePosition()) {
if ((adapter.playingHolder!=null)
&& adapter.playingHolder.vvtest.isPlaying()) {
adapter.playingHolder.vvtest.pause();
}
}
}
});
滑出屏幕再滑入,则重新播放;播放完毕后,重置界面和状态标志
@Override
public View getView(final intposition,View convertView,ViewGroup parent) {
final MyHolder holder;
if (convertView == null){
convertView = LayoutInflater.from(mContext).inflate(R.layout.layout_item,parent,false);
VideoView vvtest = (VideoView) convertView.findViewById(R.id.vv_item);
ImageButton ivbtest = (ImageButton) convertView.findViewById(R.id.video_play_btn);
ImageView ivtest = (ImageView) convertView.findViewById(R.id.video_image);
holder = new MyHolder();
holder.vvtest= vvtest;
holder.ivbtest= ivbtest;
holder.ivtest= ivtest;
convertView.setTag(holder);
}else{
holder = (MyHolder) convertView.getTag();
}
if (position !=mCurrentPos){
holder.ivbtest.setVisibility(View.VISIBLE);
holder.ivtest.setVisibility(View.VISIBLE);
}else{
holder.ivbtest.setVisibility(View.GONE);
holder.ivtest.setVisibility(View.GONE);
if (!holder.vvtest.isPlaying()){
holder.vvtest.start();
}
}
holder.vvtest.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
playingHolder.ivbtest.setVisibility(View.VISIBLE);
playingHolder.ivtest.setVisibility(View.VISIBLE);
playingHolder = null;
mCurrentPos = -1;
}
});
holder.ivbtest.setOnClickListener(newView.OnClickListener() {
@Override
public void onClick(View v) {
holder.ivtest.setVisibility(View.GONE);
holder.ivbtest.setVisibility(View.GONE);
mCurrentPos = position;
holder.vvtest.setVideoPath(mListVideos.get(position));
if (playingHolder!=null){
if(playingHolder.vvtest.isPlaying()){
playingHolder.vvtest.stopPlayback();
playingHolder.ivbtest.setVisibility(View.VISIBLE);
playingHolder.ivtest.setVisibility(View.VISIBLE);
}
}
playingHolder=holder;
holder.vvtest.start();
}
});
return convertView;
}
练习:
videoview和seekbar互动,seekbar能实时显示进度,能拖拉进度
- 播放多媒体
- 多媒体播放
- 多媒体播放
- linux多媒体播放
- 多媒体播放程序
- 使用mci播放多媒体
- BlackBerry 多媒体播放编程
- BlackBerry 多媒体播放编程
- C# DirectShow 播放多媒体
- c# 多媒体播放器
- 多媒体播放器 Amarok
- AVPlayer 多媒体播放器
- 音频视频多媒体播放
- 多媒体播放器
- Qt多媒体播放phonon
- 使用mci播放多媒体
- AVPlayer 多媒体播放器
- android 多媒体 视频播放
- ASCII码对照表
- 关于ngrok的端口转发功能
- NYOJ - 106 - 背包问题(物品可分割问题)
- 【vijos1677】【KMP】陶陶的名字
- 解决新版Jenkins首次安装一直停在向导界面问题
- 多媒体播放
- 【bzoj 1968】 [Ahoi2005]COMMON 约数研究
- [LeetCode392]Is Subsequence
- 【Boost】boost::timer库用法与实例
- 春雨医生创始人离世引关注 创业路上如何拼杀健康?
- xml的crud
- 欢迎自己来到这里
- C++中重载、重写(覆盖)和隐藏的区别实例分析
- java编程细节