普通应用使用Surface的方法

本文介绍如何使用Android NDK的Surface类进行屏幕绘图。包括添加必要权限、创建Surface、获取ISurface对象、注册buffer、提交修改等步骤,并提供了解决常见问题的方法。

Android的NDK提供了Surface类,可供应用向屏幕绘图,但使用这个类,有很多机关,
如果不注意,代码就不会正常工作。
下面是我们使用的时候遇到的问题与解决方法。

1,在C++代码里要使用Surface类,必须在APK的工程文件Android.mk里增加权限

uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER"
如果没有这句,则创建Surface会失败。

2,创建Surface

//sp client;
client = new SurfaceComposerClient();
// 然后向 Surfaceflinger 申请一个 Surface , surface 类型为 PushBuffers

DisplayInfo dispInfo;
client->getDisplayInfo(0,&dispInfo);

int ok = client->initCheck();

// 创建Surface,颜色为32位;ePushBuffers表示buffer由我们提供
surfaceControl = client->createSurface(getpid(), 0, 800, 600,
PIXEL_FORMAT_RGBA_8888, ISurfaceComposer::ePushBuffers);
if (surfaceControl == NULL) {
return JNI_FALSE;
}

// 设置位置,大小以及Z-order
client->openTransaction();
surfaceControl->setPosition(0, 0);
surfaceControl->setSize(800, 600);
surfaceControl->setLayer(99999);
surfaceControl->show();
client->closeTransaction();

3,获取ISurface对象
// 这一句需要权限,要在surface.h里加入frends class
isurface = Test::getISurface(surfaceControl);
这里使用了一个技巧,具体参见“欺骗编译器取得ISurface对象的方法”

4,注册buffer

static const char* pmem = "/dev/pmem";

// 这一句需要root权限
heap = new MemoryHeapBase(pmem, 800 * 600 * 4);
if (heap->heapID() < 0) {
return JNI_FALSE;
}
sp pmemHeap = new MemoryHeapPmem(heap, 0);
if (pmemHeap->getHeapID() >= 0) {
// pmemHeap->slap();
// heap.clear();
// pmemHeap.clear();
return JNI_FALSE;
}

mBufferHeap = ISurface::BufferHeap(800, 600,
800, 600, PIXEL_FORMAT_BGRA_8888, pmemHeap);

int ret = isurface->registerBuffers(mBufferHeap);
这里,因为要打开/dev/pmem设备文件,因此需要有权限,方法很简单,就是root手机,
然后使用命令
chmod a+rw /dev/pmem
来增加权限。
用完后记得复原,否则可能有安全风险。
在代码里修改权限参见“调用Su命令修改设备文件权限的Java代码”。

5,得到buffer指针
char * bp = static_cast(mBufferHeap.heap->base());

6,向buffer写位图数据,注意要是32位的
具体写的代码请参见“向Surface写位图数据的方法”

7,提交修改,通知Surface Flinger更新屏幕
isurface->postBuffer(0);

这样屏幕上就可以看到显示了。


http://blog.sina.com.cn/s/blog_53d1e55b0100ne4x.html

<think>好的,用户的问题是如何在Android中将View转换为Surface。首先,我需要理解用户的需求。可能他们想将某个视图的内容显示到Surface上,用于录制屏幕、视频处理或者其他需要Surface的场景。 接下来,我需要回忆Android中View和Surface的关系。Surface通常用于底层图形操作,比如通过SurfaceView或TextureView来显示。而普通的View属于视图层级的一部分,由系统管理其绘制流程。 直接转换可能不可行,因为View和Surface属于不同的层次。View的绘制是由ViewRootImpl管理的,而Surface通常需要自己处理绘制。可能的解决方案包括: 1. **使用SurfaceView或TextureView**:将View的内容绘制到这些组件提供的Surface上。例如,可以在Surface的Canvas上手动绘制View的内容。 2. **利用Canvas绘制到Surface**:获取Surface的Canvas,然后调用View的draw方法将内容绘制上去。这需要确保在正确的线程和时机进行,比如在SurfaceHolder.Callback的surfaceCreated回调之后。 3. **考虑View的绘制流程**:了解View的measure、layout、draw过程,确保在转换时这些步骤已经完成,否则可能导致内容为空。 然后,我需要验证这些方法的可行性。例如,直接调用View.draw(canvas)是否可行?可能需要先测量和布局View,确保其尺寸正确。此外,Surface的锁机制和线程安全也需要考虑,比如在UI线程外操作可能需要同步。 还要注意,从Android的版本差异来看,某些方法可能在不同版本中有不同的行为。例如,SurfaceView在早期版本中不能正确变形或动画,而TextureView更适合这种情况。 另外,是否需要使用硬件加速?如果View使用了硬件加速,绘制到Surface可能需要处理相应的配置,否则可能出现问题。 最后,整理步骤,给出一个示例代码,说明如何将View绘制到Surface。同时,提醒用户注意线程和生命周期管理,比如在Surface可用后才开始绘制,避免空指针异常。</think>在 Android 开发中,将 View 转换为 Surface 的核心思路是通过**绘制流程的主动控制**实现。以下是具体实现步骤和技术要点: ### 实现步骤 1. **创建自定义 Surface** ```java SurfaceView surfaceView = new SurfaceView(context); SurfaceHolder holder = surfaceView.getHolder(); ``` 2. **获取 View 的绘制内容** - 通过 `View.measure()` 和 `View.layout()` 确保视图完成测量布局: ```java view.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); ``` 3. **实现绘制逻辑** ```java holder.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { Canvas canvas = holder.lockCanvas(); view.draw(canvas); // 关键绘制步骤 holder.unlockCanvasAndPost(canvas); } // 其他回调方法省略... }); ``` ### 技术原理 1. **视图绘制流程**:通过主动触发 `measure()` 和 `layout()` 确保视图完成布局计算[^3] 2. **Surface 生命周期管理**:必须通过 `SurfaceHolder.Callback` 确保在 Surface 可用时进行绘制操作[^1] 3. **线程安全**:建议在 UI 线程执行绘制操作,避免并发问题 ### 高级应用场景 1. **动态内容捕获**:结合 `View.post()` 实现周期性画面捕获 2. **视频流处理**:将 Surface 与 MediaCodec 结合实现实时编码 3. **跨进程渲染**:通过 Surface 跨进程共享特性实现远程渲染 ### 注意事项 1. 硬件加速环境下需使用 `PixelCopy` API(API 26+) 2. Surface 的尺寸需与 View 的实际尺寸匹配 3. 避免在 `onLayout()` 中直接操作 Surface,应遵循 Android 的视图系统架构[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值