网站建设与管理案例教程 柳,修改wordpress语言设置,闵行区 网站制作,设计公司企业分析一、为什么要使用SurfaceView
我们知道View是通过刷新来重绘视图#xff0c;系统通过发出VSSYNC信号来进行屏幕的重绘#xff0c;刷新的时间间隔是16ms,如果我们可以在16ms以内将绘制工作完成#xff0c;则没有任何问题#xff0c;如果我们绘制过程逻辑很复杂#xff0c;…一、为什么要使用SurfaceView
我们知道View是通过刷新来重绘视图系统通过发出VSSYNC信号来进行屏幕的重绘刷新的时间间隔是16ms,如果我们可以在16ms以内将绘制工作完成则没有任何问题如果我们绘制过程逻辑很复杂并且我们的界面更新还非常频繁这时候就会造成界面的卡顿影响用户体验为此Android提供了SurfaceView来解决这一问题
View和SurfaceView的区别:
1 . View适用于主动更新的情况而SurfaceView则适用于被动更新的情况比如频繁刷新界面。
2 . View在主线程中对页面进行刷新而SurfaceView则开启一个子线程来对页面进行刷新。
3 . View在绘图时没有实现双缓冲机制SurfaceView在底层机制中就实现了双缓冲机制。
这摘录了一段网上对于双缓冲技术的介绍
双缓冲技术是游戏开发中的一个重要的技术。当一个动画争先显示时程序又在改变它前面还没有显示完程序又请求重新绘制这样屏幕就会不停地闪烁。而双缓冲技术是把要处理的图片在内存中处理好之后再将其显示在屏幕上。双缓冲主要是为了解决 反复局部刷屏带来的闪烁。把要画的东西先画到一个内存区域里然后整体的一次性画出来。
注意SurfaceView的内容不在应用窗口上所以不能使用变换平移、缩放、旋转等。也难以放在ListView或者ScrollView中不能使用UI控件的一些特性比如View.setAlpha()
二、使用案例
下面我们通过两个小案例来展示SurfaceView的使用。先放上效果图 示例代码
public class SurfaceViewSinFun extends SurfaceView implements SurfaceHolder.Callback, Runnable { private SurfaceHolder mSurfaceHolder; //绘图的Canvas private Canvas mCanvas; //子线程标志位 private boolean mIsDrawing; private int x 0, y 0; private Paint mPaint; private Path mPath; public SurfaceViewSinFun(Context context) { this(context, null); } public SurfaceViewSinFun(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SurfaceViewSinFun(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint new Paint(); mPaint.setColor(Color.BLACK); mPaint.setStyle(Paint.Style.STROKE); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(5); mPath new Path(); //路径起始点(0, 100) mPath.moveTo(0, 100); initView(); } Override public void surfaceCreated(SurfaceHolder holder) { mIsDrawing true; new Thread(this).start(); } Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } Override public void surfaceDestroyed(SurfaceHolder holder) { mIsDrawing false; } Override public void run() { while (mIsDrawing){ drawSomething(); x 1; y (int)(100 * Math.sin(2 * x * Math.PI / 180) 400); //加入新的坐标点 mPath.lineTo(x, y); } } private void drawSomething() { try { //获得canvas对象 mCanvas mSurfaceHolder.lockCanvas(); //绘制背景 mCanvas.drawColor(Color.WHITE); //绘制路径 mCanvas.drawPath(mPath, mPaint); }catch (Exception e){ }finally { if (mCanvas ! null){ //释放canvas对象并提交画布 mSurfaceHolder.unlockCanvasAndPost(mCanvas); } } } /** * 初始化View */ private void initView(){ mSurfaceHolder getHolder(); mSurfaceHolder.addCallback(this); setFocusable(true); setKeepScreenOn(true); setFocusableInTouchMode(true); } } 三、问题集
1.View和SurfaceView的区别
View必须在UI的主线程中更新画面用于被动更新画面。 SurfaceViewUI线程和子线程中都可以。在一个新启动的线程中重新绘制画面主动更新画面。
2.SurfaceView为什么可以直接子线程绘制
通常View更新的时候都会调用ViewRootImpl中的performXXX()方法在该方法中会首先使用checkThread()检查是否当前更新位于主线线程
SurfaceView提供了专门用于绘制的Surface可以通过SurfaceView来控制Surface的格式和尺寸SurfaceView更新就不需要考虑线程的问题它既可以在子线程更新也可以在主线程更新。
TextsureView
TextureView 适用于 Android 4.0 和之后的版本在很多的情况下可以顺便作为 SurfaceView 的替代品来使用。TextureView 的行为更像传统的 View可以对绘制在它上面的内容实现动画和变换。但要求运行它的环境是硬件加速的这可能会导致某些应用程序的兼容性问题。应用程序在 SDK 为 11或以上的版本时默认启动了硬件加速。如果需要禁用硬件加速可在 AndroidManifest.xml 文件中的 activity 或整个 application 标签中添加 android:hardwareAcceleratedfalse即可。
例子利用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被执行); surfaceTexturenull; surfacenull; 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 filenew File(Environment.getExternalStorageDirectory()/tv.mp4); if (!file.exists()){ copyFile(); } mediaPlayernew 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); } }); } }
SurfaceView和TextureView总结 TextureView和SurfaceView都是继承自View类的但是TextureView在Andriod4.0之后的API中才能使用。SurfaceView可以通过SurfaceHolder.addCallback方法在子线程中更新UITextureView则可以通过TextureView.setSurfaceTextureListener在子线程中更新UI个人认为能够在子线程中更新UI是上述两种View相比于View的最大优势。 但是两者更新画面的方式也有些不同由于SurfaceView的双缓冲功能可以是画面更加流畅的运行但是由于其holder的存在导致画面更新会存在间隔并且由于holder的存在SurfaceView也不能进行像View一样的setAlpha和setRotation方法但是对于一些类似于坦克大战等需要不断告诉更新画布的游戏来说SurfaceView绝对是极好的选择。但是比如视频播放器或相机应用的开发TextureView则更加适合。