我正在使用SurfaceView和渲染线程来开发基于LunarLander等结构的游戏.
但是,我遇到了很多问题,我想在这里指出一切.我希望任何想要开发游戏的人都不需要再与他们斗争了.任何对结构有更好了解的人都可以分享他们的经验,因为我还是新手,并渴望学习:)
[1] thread.start()不应多次调用该函数.
在创建表面时创建线程时提到的许多文章,以便在使用该方法暂停活动后再次渲染:
public void surfaceCreated(SurfaceHolder holder) {
// start the thread here so that we don't busy-wait in run()
// waiting for the surface to be created
if (thread.getState() == Thread.State.TERMINATED)
{
thread = new LunarThread(getHolder(), getContext(), getHandler());
}
thread.setRunning(true);
thread.start();
}
Run Code Online (Sandbox Code Playgroud)
您可以看到,如果线程未终止且函数被调用,则活动崩溃.
[2]如果您按下"电源"或"红色电话"按钮,或者电话闲置几分钟,则活动将处于onPause()状态,但线程仍在运行.这是一个非常糟糕的做法,所以我需要找到让线程停止的方法,然后重新开始onResume().
[3]如果屏幕锁定是纵向/横向,并且您的游戏粘贴到另一个方向,则屏幕锁定会强制您"定向"一次.这意味着再次开始活动.我仍然无法找到解决方案.(正如我在Android屏幕方向错误中提到的那样)
以下是我修复这些问题的代码:
UIThread
public class UIThread extends Activity
{
private gameView gameview;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
gameview = (gameView) findViewById(R.id.gameview);
}
protected …Run Code Online (Sandbox Code Playgroud) 我有一个surfaceView设置并运行,但当我恢复它时,我得到一个错误,该线程已经启动.当应用程序进入后台然后返回前台时,处理的正确方法是什么?我已经修好了并且设法让应用程序无法崩溃而返回......但是SurfaceView不再绘制任何东西了.我的代码:
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.e("sys","surfaceCreated was called.");
if(systemState==BACKGROUND){
thread.setRunning(true);
}
else {
thread.setRunning(true);
thread.start();
Log.e("sys","started thread");
systemState=READY;
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e("sys","surfaceDestroyed was called.");
thread.setRunning(false);
systemState=BACKGROUND;
}
Run Code Online (Sandbox Code Playgroud) 在较慢的设备上测试我的游戏(Orange旧金山又名中兴Blade),我的帧速率令人震惊.
我将一些调试代码放入绘制循环中,发现以下行占用了100ms:
c = mSurfaceHolder.lockCanvas();
Run Code Online (Sandbox Code Playgroud)
其他人看到过这种行为吗?我通过扩展查看和执行的onDraw()暂时取代了surfaceview,我获得了很多更好的帧率.
虽然一般来说,SurfaceView在我的HTC Desire上要快得多.我怀疑这可能是Android 2.1问题.如果可能的话,我正在考虑生根并将其升级到2.2,但我确实想要在2.1上运行设备,这样从长远来看可能会适得其反.
**更新**
我一直在研究这个问题,并且发现了一些令人费解的方面.
我根据手机安装了2.2并且问题仍然存在.当应用程序首次启动时,lockCanvas按预期工作(0-1毫秒).然后在初始化期间的某个时刻,lockCanvas突然开始大约需要100ms.
值得指出的是,我正在异步任务中加载我的资产,以便我可以显示加载屏幕.
尽管我尽力确定程序在发生缓慢时实际正在做什么,但我无法做到这一点.事实上,当我在调试模式下单步运行时,它运行得很快!
现在我发现如果我在SurfaceView的构造函数中添加延迟(大约10秒),则不会发生缓慢而且一切正常.
但是,如果您按Home键然后切换回来,则缓慢返回.
对于这个愚蠢的不合逻辑的问题,我几乎已经到了最后!我有心思把它归结为特定于设备的问题.
我觉得它可能与内存使用有关.也许有些东西被换掉了,它会影响视频内存?
我至少对理论很感兴趣.
我有一个Bitmap大小,320x480我需要在不同的设备屏幕上拉伸它,我尝试使用这个:
Rect dstRect = new Rect();
canvas.getClipBounds(dstRect);
canvas.drawBitmap(frameBuffer, null, dstRect, null);
Run Code Online (Sandbox Code Playgroud)
它工作,图像像我想要的那样填满整个屏幕,但图像像素化,看起来很糟糕.然后我尝试了:
float scaleWidth = (float) newWidth / width;
float scaleHeight = (float) newHeight / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(frameBuffer, 0, 0,
width, height, matrix, true);
canvas.drawBitmap(resizedBitmap, 0, 0, null);
Run Code Online (Sandbox Code Playgroud)
这次它看起来很完美,漂亮和流畅,但是这段代码必须在我的主游戏循环中,并且Bitmap每次迭代创建它都会使它非常慢.如何调整图像大小以使其不会像素化并快速完成?
找到解决方案:
Paint paint = new Paint();
paint.setFilterBitmap();
canvas.drawBitmap(bitmap, matrix, paint);
Run Code Online (Sandbox Code Playgroud) 在Android中,我创建了一个并排有三个表面视图的布局,我想同时播放一个带有不同媒体播放器的视频文件.但是我面临的一个问题是,三个人都不能同时播放该视频.其中一两个人停下了显示器.如果我直接使用视频视图而不是Media Player类,但问题仍然存在.请任何人都可以提供帮助.问题是什么?它给错误表面创建失败原生错误.我尝试了不同的组合,例如3个不同视图中的一个文件,三个不同视图中的三个文件,但问题尚未解决.其他网站上的一些回复称它取决于内核版本.如果它取决于内核版本,请你在android网站上给我任何android文档链接,它取决于内核版本.或者可以玩,请给我代码的步骤.这是错误日志 -
04-10 19:23:37.995: E/ANDROID_DRM_TEST(2573): Client::notify In
04-10 19:23:37.995: V/AudioPolicyManager(2573): startOutput() output 1, stream 3, session 131
04-10 19:23:37.995: V/AudioPolicyManager(2573): getDeviceForStrategy() from cache strategy 0, device 2
04-10 19:23:37.995: V/AudioPolicyManager(2573): getNewDevice() selected device 2
04-10 19:23:37.995: V/AudioPolicyManager(2573): setOutputDevice() output 1 device 2 delayMs 0
04-10 19:23:37.995: V/AudioPolicyManager(2573): setOutputDevice() setting same device 2 or null device for output 1
04-10 19:23:37.995: I/AudioFlinger(2573): start output streamType (0, 3) for 1
04-10 19:23:37.995: D/AudioHardwareYamaha(2573): AudioStreamOut::setParameters(keyValuePairs="start_output_streamtype=3")
04-10 19:23:38.010: W/SEC_Overlay(2689): overlay_setPosition(0) 0,0,200,397 => 0,0,200,397 …Run Code Online (Sandbox Code Playgroud) android surfaceview android-ndk android-mediaplayer android-videoview
我有一个应用程序,我希望能够捕获屏幕截图.布局的背景是surfaceView,它显示后置摄像头的视频.以下代码可以截取屏幕截图,但surfaceView的内容保存为黑色.这是代码:
btn.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
Random num = new Random();
int nu=num.nextInt(1000);
Bitmap bmp;
CamView.setDrawingCacheEnabled(true);
CamView.buildDrawingCache(true);
Bitmap bmp2 = Bitmap.createBitmap(CamView.getDrawingCache()); //Screenshot of the layout
CamView.setDrawingCacheEnabled(false);
SurView.setDrawingCacheEnabled(true);
SurView.buildDrawingCache(true);
Bitmap bmp1 = Bitmap.createBitmap(SurView.getDrawingCache()); //Screenshot of the surfaceView
SurView.setDrawingCacheEnabled(false);
Bitmap bmOverlay = Bitmap.createBitmap(bmp1.getWidth(), bmp1.getHeight(),bmp1.getConfig());
Canvas canvas = new Canvas(bmOverlay); //Overlaying the 2 bitmaps
canvas.drawBitmap(bmp1, 0,0, null);
canvas.drawBitmap(bmp2, 0,0, null);
bmp=bmOverlay;
//saving the file
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bmp.compress(CompressFormat.JPEG, 100, bos);
byte[] bitmapdata = bos.toByteArray();
ByteArrayInputStream fis = new …Run Code Online (Sandbox Code Playgroud) 更新:在带有Android Oreo(8.X)的模拟器上工作。我有可能直接对android源进行更改,因此,如果有人知道我必须更改或更新以使其正常工作的android源中的内容,这也将有所帮助(因此,我实际上并不需要Android 7解决方法(尽管无法进行Android 8更新)。
我在FrameLayout中有一个SurfaceView。SurfaceView通常会显示视频,例如,我实际上是在绘制图像。问题是,如果我将FrameLayout(或SurfaceView)的尺寸设置为宽度大于10.000像素,则会在左侧裁剪。
在Android 7.1.1上进行了测试(在设备和仿真器上:Android TV(1080p)API 25
public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//add surfaceview
TestSurfaceView testSurfaceView = new TestSurfaceView(this);
setContentView(testSurfaceView);
//resize
FrameLayout.LayoutParams bgParams = (FrameLayout.LayoutParams) testSurfaceView.getLayoutParams();
//testcase full hd - working
bgParams.width = 1920;
//testcase 2 - working - each segment is 330px as 9900 / 1920 * 64 (default segment width) == 330
//bgParams.width = 9900;
//testcase 3 - working
//bgParams.width = 10000;
//testcase 4 - not working - …Run Code Online (Sandbox Code Playgroud) android surfaceview android-source android-x86 android-7.0-nougat
我的应用程序仅提供纵向模式.在肖像活动中,我有一个全屏VideoView.我想要做的是在横向模式下将VideoView(实际视频,视频缓冲)旋转90度.不允许将活动设置为Lanscape模式.扩展VideoView和画布旋转将不起作用,因为它是SurfaceView而不是实际视图.有没有办法用videoView实现这一目标?
在运行Android 4.0或4.0.3的模拟器上,我看到了可怕的色带,我似乎无法摆脱它.在我测试的每个其他Android版本上,渐变看起来很流畅.
我有一个配置为RGBX_8888的SurfaceView,并且渲染画布中不存在条带.如果我通过在渲染结束时叠加噪声模式来手动抖动图像,我可以使渐变再次平滑,但显然代价是我宁愿避免的性能.
因此绑带将在稍后介绍.我只能假设,在4.0+上,我的SurfaceView在被绘制和显示之间的某个点处被量化为较低的位深度,我可以从屏幕截图中看到渐变是一次步进8个值每个通道,建议量化到555(而不是565).
我将以下内容添加到我的Activity onCreate函数中,但它没有任何区别.
getWindow().setFormat(PixelFormat.RGBA_8888);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DITHER);
Run Code Online (Sandbox Code Playgroud)
我也尝试将上面的内容放在onAttachedToWindow()上,但仍然没有变化.
(我相信RGBA_8888无论如何都是2.2及以上版本的默认窗口格式,因此明确设置该格式对4.0+没有影响也就不足为奇了.)
这就留下了一个问题,如果源是8888,目的地是8888,那么引入量化/条带的原因是什么,它为什么只出现在4.0+?
非常令人费解.我想知道是否有人可以放弃一些光线?
谁能告诉我SurfaceView和GLSurfaceView之间的基本区别是什么?我什么时候应该使用SurfaceView,何时应该使用GLSurfaceView?
我在Stack Overflow上阅读了一些已经回答的问题,但它们并不能满足我的疑问.
任何帮助,将不胜感激.
android ×10
surfaceview ×10
android-ndk ×1
android-x86 ×1
bitmap ×1
camera ×1
canvas ×1
dithering ×1
frame-rate ×1
gradient ×1
opengl-es ×1
performance ×1
quantization ×1
resize ×1
screenshot ×1
storage ×1