SurfaceView.LockCanvas()需要15毫秒到75毫秒才能完成。有没有办法解决这个问题,或者减少零星的发生?
背景:我是Android 2d图形开发的新手,所以我开始使用jetboy示例并将其更改为只是在屏幕上滚动其中一个位图(使用速度向量和基于System.currentTimeMillis()
的差异来获取经过的时间)。
位图将完美滚动一两秒钟,但间歇性地暂停,给人一种不稳定的外观。
经过一些调试后,我认为这个问题是由SurfaceView.LockCanvas()
需要15ms到75ms才能返回Canvas
的事实引起的 - 即使没有重要的更新代码在运行,也没有任何内容画布。
以下是我的调试代码。从Jetboy示例开始,我使用以下代码替换了run()
方法:
public void run() {
while (true) {
time = SystemClock.elapsedRealtime();
elapsed_cycle = time - prev_time;
prev_time = time;
if (elapsed_cycle > 35.0){
Log.d(LOCKING, String.valueOf(elapsed_cycle) + MSAFTER + String.valueOf(count) + CYCLES);
count = 0;
}
else count++;
elapsed_draw += elapsed_cycle;
if (elapsed_draw > 30){
elapsed_draw -= 30;
c = null;
try {c = mSurfaceHolder.lockCanvas(null);} catch (IllegalArgumentException e) {Log.d("ERROR", "Lock Canvas 1.");}
if (c != null) {mSurfaceHolder.unlockCanvasAndPost(c);} else {Log.d(ERROR, "Couldn't unlock.");System.exit(0);}
}
}
}
因此,代码执行两项操作:1)只需尝试锁定,而不是每30ms解锁一次画布。 2)如果while循环的任何单个循环(迭代)花费的时间超过35ms,则生成LogCat输出。运行此代码将提供以下LogCat输出:
07-03 13:07:44.587: D/LOCKING(4805): 39ms, after 24 cycles.
07-03 13:07:44.757: D/LOCKING(4805): 39ms, after 5 cycles.
07-03 13:07:44.838: D/LOCKING(4805): 50ms, after 1 cycles.
07-03 13:07:45.048: D/LOCKING(4805): 44ms, after 5 cycles.
07-03 13:07:45.799: D/LOCKING(4805): 74ms, after 41 cycles.
07-03 13:07:49.432: D/LOCKING(4805): 36ms, after 215 cycles.
以下是未经过滤的LogCat的味道:
07-03 13:33:11.058: D/BatteryService(712): update start
07-03 13:33:11.068: D/BatteryService(712): level:99 scale:100 status:2 health:2 present:true voltage: 4332 temperature: 315 technology: Li-ion AC powered:false USB powered:true icon:17303207 invalid charger:0
07-03 13:33:11.078: D/LOCKING(5804): 39ms, after 40 cycles.
07-03 13:33:11.088: D/STATUSBAR-BatteryController(896): onReceive() - ACTION_BATTERY_CHANGED
07-03 13:33:11.088: D/STATUSBAR-BatteryController(896): onReceive() - level:99
07-03 13:33:11.088: D/STATUSBAR-BatteryController(896): onReceive() - plugged:2
07-03 13:33:11.088: D/STATUSBAR-BatteryController(896): onReceive() - BATTERY_STATUS_CHARGING:
07-03 13:33:11.088: D/STATUSBAR-PhoneStatusBar(896): ACTION_BATTERY_CHANGED
07-03 13:33:11.118: W/AlarmManager(712): FACTORY_ON= 0
07-03 13:33:11.128: E/MtpService(1013): In MTPAPP onReceive:android.intent.action.BATTERY_CHANGED
07-03 13:33:11.128: E/MtpService(1013): battPlugged Type : 2
07-03 13:33:11.128: D/LOCKING(5804): 49ms, after 0 cycles.
现在我做了一些随机观察:
如果我使用Thread.sleep()
在while循环中引入延迟,那么LockCanvas()
时间会更长,缩放时会延迟。
我仍然使用Snake示例的Invalidate()
/ onDraw()
绘图过程看到此问题。
我在同样简单的libgdx项目中看到了同样的不稳定,尽管应用程序在桌面上运行完美。
我在(物理)三星Galaxy SIII上进行调试。
给lockCanvas()
一个1像素宽度和1像素高度的“脏”Rectangle
不会加速任何事情 - 我认为做更少的工作可能会更快乐。
在清单文件中,设置android:hardwareAccelerated="true"
无效。
再次在清单文件中,设置支持屏幕android:anyDensity="true"
无效。
构建到.apk并安装无济于事。
我在运行未经改变的电子游戏时看到了不稳定。
对于那些不熟悉jetboy示例的人,这里是onCreate()
方法:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// get handles to the JetView from XML and the JET thread.
mJetBoyView = (JetBoyView)findViewById(R.id.JetBoyView);
mJetBoyThread = mJetBoyView.getThread();
// look up the happy shiny button
mButton = (Button)findViewById(R.id.Button01);
mButton.setOnClickListener(this);
mButtonRetry = (Button)findViewById(R.id.Button02);
mButtonRetry.setOnClickListener(this);
// set up handles for instruction text and game timer text
mTextView = (TextView)findViewById(R.id.text);
mTimerView = (TextView)findViewById(R.id.timer);
mJetBoyView.setTimerView(mTimerView);
mJetBoyView.SetButtonView(mButtonRetry);
mJetBoyView.SetTextView(mTextView);
}
线程在这里开始:
public void surfaceCreated(SurfaceHolder arg0) {
// start the thread here so that we don't busy-wait in run()
// waiting for the surface to be created
thread.setRunning(true);
thread.start();
}
即使您不知道如何解决此问题,如果您在自己的设置中没有看到此问题,那么我很想听听您的绘图方式以及调试方式。