Android面试题(29)-surfaceView与TextureView
2018-03-08 16:50
435 查看
SurfaceView:
模板代码:public class SurfaceViewText extends SurfaceView implements SurfaceHolder.Callback,Runnable{
private SurfaceHolder surfaceHolder;
private boolean isDrawing;
public SurfaceViewText(Context context) {
super(context);
//初始化
init();
}
private void init() {
surfaceHolder = getHolder();//获取Surface管理对象,SurfaceHolder
surfaceHolder.addCallback(this);//注册SurfaceHolder
setFocusable(true);//设置SurfaceView可获取焦点
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);//保持屏幕常亮
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
isDrawing =true;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isDrawing =false;
}
@Override
public void run() {
while (isDrawing){
drawUI();
}
}
private void drawUI() {
Canvas canvas=surfaceHolder.lockCanvas();
try {
drawView(canvas);
}catch (Exception e){
e.printStackTrace();
}finally {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
private void drawView(Canvas canvas) {
//画一些东西
}
}
例子:触摸板
public class SurfaceViewText extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private SurfaceHolder surfaceHolder;
private boolean isDrawing;
private Canvas canvas;
private Paint paint;
private Path path;
private float mLastX, mLastY;//上次的坐标
public static final int TIME_IN_FRAME = 30;
public SurfaceViewText(Context context) {
super(context);
//初始化
init();
}
private void init() {
surfaceHolder = getHolder();//获取Surface管理对象,SurfaceHolder
surfaceHolder.addCallback(this);//注册SurfaceHolder
setFocusable(true);//设置SurfaceView可获取焦点
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);//保持屏幕常亮
//设置画笔
paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
paint.setColor(Color.RED);
paint.setStrokeWidth(10f);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);//设置线段连接处样式,圆弧
paint.setStrokeCap(Paint.Cap.ROUND);//画笔笔刷类型,影响画
10ab8
笔始末端
//初始化路径
path = new Path();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
isDrawing = true;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isDrawing = false;
}
@Override
public void run() {
while (isDrawing) {
/**取得更新之前的时间**/
long startTime = System.currentTimeMillis();
synchronized (surfaceHolder){
drawUI();
}
/**取得更新结束的时间**/
long endTime = System.currentTimeMillis();
/**计算出一次更新的毫秒数**/
int diffTime = (int)(endTime - startTime);
/**确保每次更新时间为30帧**/
while(diffTime <=TIME_IN_FRAME) {
diffTime = (int)(System.currentTimeMillis() - startTime);
/**线程等待**/
Thread.yield();
}
}
}
private void drawUI() {
try {
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
canvas.drawPath(path, paint);
} catch (Exception e) {
e.printStackTrace();
} finally {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float xStart = event.getRawX();
float yStart = event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastX = xStart;
mLastY = yStart;
path.moveTo(mLastX, mLastY);
break;
case MotionEvent.ACTION_MOVE:
float dx = Math.abs(xStart - mLastX);
float dy = Math.abs(yStart - mLastY);
if (dx >= 3 || dy >= 3) {
path.quadTo(mLastX, mLastY, (mLastX + xStart) / 2, (mLastY + yStart) / 2);
}
mLastX = xStart;
mLastY = yStart;
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int wSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int wSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int hSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int hSpecSize = MeasureSpec.getSize(heightMeasureSpec);
if (wSpecMode == MeasureSpec.AT_MOST && hSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(300, 300);
} else if (wSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(300, hSpecSize);
} else if (hSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(wSpecSize, 300);
}
}
}
SurfaceView中采用了双缓冲机制,保证了UI界面的流畅性,同时SurfaceView不在主线程中绘制,而是另开辟一个线程去绘制,所以它不妨碍UI线程;
SurfaceView继承于View,他和View主要有以下三点区别:
(1)View底层没有双缓冲机制,SurfaceView有;
(2)view主要适用于主动更新,而SurfaceView适用与被动的更新,如频繁的刷新
(3)view会在主线程中去更新UI,而SurfaceView则在子线程中刷新;
SurfaceView的内容不在应用窗口上,所以不能使用变换(平移、缩放、旋转等)。也难以放在ListView或者ScrollView中,不能使用UI控件的一些特性比如View.setAlpha()
TextsureView:
TextureView 适用于 Android 4.0 和之后的版本,在很多的情况下可以顺便作为 SurfaceView 的替代品来使用。TextureView 的行为更像传统的 View,可以对绘制在它上面的内容实现动画和变换。但要求运行它的环境是硬件加速的,这可能会导致某些应用程序的兼容性问题。应用程序在 SDK 为 11或以上的版本时,默认启动了硬件加速。(如果需要禁用硬件加速可在 AndroidManifest.xml 文件中的 <activity> 或整个 <application> 标签中添加 android:hardwareAccelerated="false",即可。)例子:利用TextureView播放视频
public class TextureViewActivity extends Activity implements TextureView.SurfaceTextureListener {
private MediaPlayer mediaPlayer;
@Bind(R.id.texture)
TextureView textureView;
@Bind(R.id.video_image)
ImageView video_image;
private Surface surface;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_surface);
ButterKnife.bind(this);
textureView.setSurfaceTextureListener(this);//设置监听,实现四个方法
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
System.out.println("onSurfaceTextureAvailable被执行");
surface = new Surface(surfaceTexture);
new PlayerVideo().start();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
System.out.println("onSurfaceTextureSizeChanged被执行");
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
System.out.println("onSurfaceTextureDestroyed被执行");
surfaceTexture=null;
surface=null;
mediaPlayer.stop();
mediaPlayer.release();
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
class PlayerVideo extends Thread{
@Override
public void run() {
MPermissionUtils.requestPermissionsResult(TextureViewActivity.this, 1, new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, new MPermissionUtils.OnPermissionListener() {
@Override
public void onPermissionGranted() {
File file=new File(Environment.getExternalStorageDirectory()+"/tv.mp4");
if (!file.exists()){
copyFile();
}
mediaPlayer=new MediaPlayer();
try {
mediaPlayer.setDataSource(file.getAbsolutePath());
mediaPlayer.setSurface(surface);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
video_image.setVisibility(View.GONE);
mediaPlayer.start();
}
});
mediaPlayer.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onPermissionDenied() {
MPermissionUtils.showTipsDialog(TextureViewActivity.this);
}
});
}
}
/**
* 如果sdcard没有文件就复制过去
*/
private void copyFile() {
AssetManager assetManager = this.getAssets();
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open("tv.mp4");
String newFileName = Environment.getExternalStorageDirectory()+"/tv.mp4";
out = new FileOutputStream(newFileName);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
MPermissionUtils.onRequestPermissionsResult(requestCode, permissions, grantResults);
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}首先,TextureView和SurfaceView都是继承自View类的,但是TextureView在Andriod4.0之后的API中才能使用。SurfaceView可以通过SurfaceHolder.addCallback方法在子线程中更新UI,TextureView则可以通过TextureView.setSurfaceTextureListener在子线程中更新UI,个人认为能够在子线程中更新UI是上述两种View相比于View的最大优势。
但是,两者更新画面的方式也有些不同,由于SurfaceView的双缓冲功能,可以是画面更加流畅的运行,但是由于其holder的存在导致画面更新会存在间隔,并且,由于holder的存在,SurfaceView也不能进行像View一样的setAlpha和setRotation方法,但是对于一些类似于坦克大战等需要不断告诉更新画布的游戏来说,SurfaceView绝对是极好的选择。但是比如视频播放器或相机应用的开发,TextureView则更加适合。
相关文章推荐
- Android TextureView 和 SurfaceView 对比浅析
- Android TextureView 与 SurfaceView用法区别
- Android面试题——Android中View,SurfaceView和GLSurfaceView
- Android显示系统之View与SurfaceView更新屏幕的区别
- Android开发学习SurfaceView显示动画效果
- Android SurfaceView游戏开发示例
- SurfaceView游戏框架--android开发
- Android -- 视频音频多媒体播放,在线播放, MediaPlayer, SurfaceView, SoundPool, Timer定时器使用
- Android提高第二篇之SurfaceView的基本使用
- Android surfaceView 与View 的区别
- 【Android游戏开发十八】解放手指,利用传感器开发游戏!(本文讲解在SurfaceView中用重力传感器控制圆球的各方向移动)
- Android SurfaceView 的应用
- Android SurfaceView 绘图覆盖刷新及脏矩形刷新方法
- 【Android游戏开发】追加简述SurfaceView 与 GLSurfaceView效率!
- Android_Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系
- Android之SurfaceView
- 【Android游戏开发之六】在SurfaceView中添加系统控件,并且相互交互数据!
- android SurfaceView实现人物动画
- Android UI Internal : SurfaceView Vs View
- Android SurfaceTexture和GLSurfaceView做Camera预览