編輯:Android開發實例
在簡單定制VideoView中做了簡單的VideoView定制,其實就是在布局上做了一些事情。要向更靈活的定制播放器的行為,必須寫自己的VideoView。參考android VideoView源代碼,寫了個最簡單的實現。
看起來和簡單定制VideoView中的效果差不多,但是還有很多邏輯沒有加進來,比如:
自定義的VideoView源代碼:
package com.easymorse.videoplayer;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.widget.MediaController;
import android.widget.MediaController.MediaPlayerControl;public class CustomerVideoView extends SurfaceView implements
MediaPlayerControl {private static String TAG = "customer.videoplayer";
private boolean pause;
private boolean seekBackward;
private boolean seekForward;
private Uri videoUri;
private MediaPlayer mediaPlayer;
private Context context;
private OnPreparedListener onPreparedListener;
private int videoWidth;
private int videoHeight;
private MediaController mediaController;
protected SurfaceHolder surfaceHolder;
private Callback surfaceHolderCallback = new SurfaceHolder.Callback() {
public void surfaceChanged(SurfaceHolder holder, int format, int w,
int h) {
}public void surfaceCreated(SurfaceHolder holder) {
surfaceHolder = holder;
if (mediaPlayer != null) {
mediaPlayer.setDisplay(surfaceHolder);
resume();
} else {
openVideo();
}
}public void surfaceDestroyed(SurfaceHolder holder) {
surfaceHolder = null;
if (mediaController != null) {
mediaController.hide();
}release(true);
}
};private void release(boolean cleartargetstate) {
if (mediaPlayer != null) {
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
}
}public void resume() {
if (surfaceHolder == null) {
return;
}
if (mediaPlayer != null) {
return;
}
openVideo();
}public CustomerVideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
this.initVideoView();
}public CustomerVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
this.initVideoView();
}public CustomerVideoView(Context context) {
super(context);
this.context = context;
this.initVideoView();
}@Override
public boolean canPause() {
return this.pause;
}@Override
public boolean canSeekBackward() {
return this.seekBackward;
}@Override
public boolean canSeekForward() {
return this.seekForward;
}@Override
public int getBufferPercentage() {
return 0;
}@Override
public int getCurrentPosition() {
return mediaPlayer!=null?mediaPlayer.getCurrentPosition():0;
}@Override
public int getDuration() {
return mediaPlayer!=null?mediaPlayer.getDuration():0;
}@Override
public boolean isPlaying() {
return false;
}@Override
public void pause() {
}@Override
public void seekTo(int mSec) {
}@Override
public void start() {
}public void setVideoURI(Uri uri) {
this.videoUri = uri;
openVideo();
requestLayout();
invalidate();
}private void openVideo() {
this.mediaPlayer = new MediaPlayer();
try {
this.mediaPlayer.setDataSource(this.context, this.videoUri);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
throw new RuntimeException(e);
}
this.mediaPlayer.prepareAsync();
this.mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
this.mediaPlayer.setOnPreparedListener(onPreparedListener);
attachMediaController();}
private void attachMediaController() {
if (mediaPlayer != null && mediaController != null) {
mediaController.setMediaPlayer(this);
View anchorView = this.getParent() instanceof View ? (View) this
.getParent() : this;
mediaController.setAnchorView(anchorView);
mediaController.setEnabled(true);
}}
public void setMediaController(MediaController controller) {
if (mediaController != null) {
mediaController.hide();
}
mediaController = controller;
attachMediaController();
}public void setOnPreparedListener(OnPreparedListener onPreparedListener) {
this.onPreparedListener = onPreparedListener;
}@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getDefaultSize(videoWidth, widthMeasureSpec);
int height = getDefaultSize(videoHeight, heightMeasureSpec);
if (videoWidth > 0 && videoHeight > 0) {
if (videoWidth * height > width * videoHeight) {
height = width * videoHeight / videoWidth;
} else if (videoWidth * height < width * videoHeight) {
width = height * videoWidth / videoHeight;
}
}
Log.i(TAG, "setting size: " + width + ‘x’ + height);
setMeasuredDimension(width, height);
}private void initVideoView() {
videoWidth = 0;
videoHeight = 0;
getHolder().addCallback(surfaceHolderCallback);
getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
}}
和VideoView實現類似,繼承了SurfaceView並且實現了MediaPlayerControl。
一般情況下,android界面的繪制和更新,要交給主ui線程來操作,通過Handler機制。但是播放視頻,需要比較優先和實時的改變和繪制界面。android提供了使用單獨線程繪制UI的機制,就是SurfaceView。
使用SurfaceView,需要實現SurfaceHolder.Callback接口:
開發者不能直接操作Surface實例,要通過SurfaceHandler,在SurfaceView中可以通過getHandler方法獲取到SurfaceHandler實例。
SurfaceHander有一些類型,用來標識Surface實例界面數據來源,可以通過setType來操作:
CustomerVideoView的構造方法,使用超類的構造方法。都會執行initVideoView()方法用來初始化界面和參數。
另外一個主要的內容是openVideo()方法:
源代碼見:
http://easymorse.googlecode.com/svn/tags/videoplayer-0.4/
Android應用程序可以在許多不同地區的許多設備上運行。為了使應用程序更具交互性,應用程序應該處理以適合應用程序將要使用的語言環境方面的文字,數字,文件等。在本章中,我
文件管理器是管理文件的軟件,幫助用戶處理日常工作,管理儲存在本地和網絡中的文件。所有文件管理器都提供了基本的操作如創建、打開、查看、編輯、移動和刪除文件。許多An
JSON代表JavaScript對象符號。它是一個獨立的數據交換格式,是XML的最佳替代品。本章介紹了如何解析JSON文件,並從中提取所需的信息。Android提供了四個
1. UiObejct.getFromParent()的用法:從這個名字就知道,就是從當前對象的父對象中查找想要的子對象,該子對象和當前對象應該是同一層級。 如