13_SurfaceView和SurfaceHolder类的学习

本文详细解析了Android中SurfaceView及其管理类SurfaceHolder的工作原理和使用方法,包括如何通过SurfaceHolder获取画布进行绘图,如何监听Surface状态变化等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#1 大约理解一下他们俩:

      SurfaceView继承自View,从单词意思也可以看得出来它是显示用的,它相当于一个布局配置文件,

所以可以这样:定义一个MySurfaceView extends SurfaceView,然后在Activity的onCreate()方法中,

不是有这句吗:setContentView(R.layout.某个布局xml文件);  那么,现在就可以改成是:setContentView(new MySurfaceView()); 

而且,SurfaceView一般多用于表示2d图形多些!


      SurfaceHolder可以理解成是某个SurfaceView的“管理类”,即:每个SurfaceView通过它的getHolder()方法都可以获得一个

SurfaceHolder对象,比如: SurfaceHolder hoder = mySurView.getHolder();

那么,Holder类怎么管理Surface类呢,或者说可以管理什么呢?比如:holder可以从Surface上取一张画布过来,然后在画布上

画画,然后这个Surface的图案就变成了刚刚画的内容!即Holder可以改变Surface的图案;

holder还可以“监视”Surface的图案变化情况,只要让holder.addCallback(这里new一个SurfaceHolder.Callback的实现类对象);

并且在SurfaceHolder.Callback类的实现类对象中实现这3个方法:

surfaceCreated、surfaceDestroyed、surfaceChanged,

那么,这个hoder就可以实时监听这个Surface的状态,当Surface第一次加载时就会执行surfaceCreated方法,显然,由于是

从无到有,所以,Surface肯定也变化了,所以也会执行surfaceChanged方法,而且,以后Surface只要变化了那么就会自动

触发一次surfaceChanged方法,当Surface消亡时触发surfaceDestroyed方法!


#2  一般会这样使用他们俩(不这样也可以,但你会发现各种传参数不方便!):

      一般在定义某个MySurfaceView时,他不是继承自SurfaceView吗,

而且到时候不是会让他的holder对象addCallback(这里new一个SurfaceHolder.Callback的实现类对象)吗,

就意味着要重新定义一个新的类实现SurfaceHolder.Callback,那么,我这里就让我的MySurfaceView亲自

继承自他,到时候我的holder对象.addCallback时,就很显然可以看到:在MySurfaceView类中:holder.addCallback(this);


所以,以后的套路一般是在定义某个SurfaceView的子类时:class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {}

如果你想要给Surface绘一个图,可能这个绘图操作很长时间,那么,一般做法是在一个子线程中去画图,什么时候启动这个子线程呢?在

surfaceCreated()方法中启动这个子线程,因为这个方法必然会执行的!那么,怎么在这个SurfaceView中画图呢,前面说过holder可以拿到它的画布,

所以,,,,可以实现让SurfaceView的图案改变!如果让当前Activity的setContentView() = 当前MySurfaceView对象,那么,就可以,,,,,

而且,如果holder在画图时每隔一段时间画一次则图案会定期改变吧!     

如果你想在图案改变时做一些事情也可以实现:事先写好surfaceChanged方法即可!当然你也可以什么都不做,随你!


上面注意几点:

第一,在交给子线程绘图时,一定要把holder对象带过去,否则给谁绘图呢?

第二,在以后使用holder的过程中,尤其是摄像头方面的时候,可能经常会看到这句代码:

holder.setType(SURFACE_TYPE_PUSH_BUFFERS);  这句话的意思是什么呢?

SURFACE_TYPE_PUSH_BUFFERS表明该Surface不包含原生数据,Surface用到的数据由其他对象提供,

在Camera图像预览中就使用该类型的Surface,由Camera负责提供给预览Surface数据,这样图像预览会比较流畅


#3  看一个简单的例子,关于SurfaceView和SurfaceHolder用法的:http://blog.youkuaiyun.com/andyhuabing/article/details/7657069   


### 使用 MediaPlayer、SurfaceView SurfaceHolder.Callback 实现视频播放器 #### 设计思路 为了构建一个基于 `MediaPlayer` `SurfaceView` 的自定义视频播放器,设计的核心在于管理好各个组件之间的交互。具体来说: - 创建并配置 `MediaPlayer` 对象用于处理音频/视频文件的加载与回放操作。 - 利用 `SurfaceView` 组件作为视频渲染的目标窗口。 - 通过实现 `SurfaceHolder.Callback` 接口监听 `SurfaceView` 生命周期事件(创建、改变大小、销毁),从而同步调整 `MediaPlayer` 状态。 #### 关键方法说明 当 `SurfaceView` 被创建时,在 `surfaceCreated()` 中初始化 `MediaPlayer` 并准备好它所使用的数据源以及关联至当前视图持有的 `SurfaceHolder`[^2]。 一旦准备工作完成,则可以在 `onPrepared(MediaPlayer mp)` 回调函数内启动实际的媒体流传输过程;而每当检测到视频帧尺寸发生变化时,应相应更新容器控件的实际显示区域以匹配新参数——这通常是在 `onVideoSizeChanged(mp, width, height)` 函数里执行的操作。 最后,在 `surfaceDestroyed(SurfaceHolder holder)` 方法中确保及时清理不再需要的对象实例及其占用资源,防止内存泄漏等问题发生。 #### 示例代码 下面给出一段简化版的 Java 代码片段,展示了上述概念的具体实践方式: ```java public class VideoPlayerActivity extends AppCompatActivity implements SurfaceHolder.Callback { private MediaPlayer mediaPlayer; private SurfaceView surfaceView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_video_player); surfaceView = findViewById(R.id.surface_view); surfaceView.getHolder().addCallback(this); // 注册回调接口 // 设置其他必要的属性... } @Override public void surfaceCreated(SurfaceHolder holder) { try { Uri videoUri = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.samplevideo); mediaPlayer = new MediaPlayer(); mediaPlayer.setDataSource(getApplicationContext(), videoUri); mediaPlayer.setDisplay(holder); mediaPlayer.prepareAsync(); // 异步准备 mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mp.start(); // 开始播放 } }); mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { // 处理播放结束后的逻辑 } }); mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { // 错误处理机制 return false; } }); mediaPlayer.setOnVideoSizeChangedListener((mp, w, h) -> { // 更新界面布局适应新的宽高比例 }); } catch (IOException e) { Log.e("VideoPlayer", "Unable to play video"); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} @Override public void surfaceDestroyed(SurfaceHolder holder) { if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.stop(); } if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; // 防止泄露 } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值