2

SurfaceView.LockCanvas() 需要 15 毫秒到 75 毫秒才能完成。有没有办法解决这个问题,或者减少它的零星?

背景:我是 Android 2d 图形开发的新手,所以我从 jetboy 示例开始,并将其更改为简单地在屏幕上滚动其中一个位图(使用速度矢量和System.currentTimeMillis()基于差异来获取经过的时间)。

位图将完美滚动一两秒,但会间歇性地停顿,看起来不连贯。

经过一些调试,我认为问题是由于SurfaceView.LockCanvas()需要 15 毫秒到 75 毫秒才能返回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)每 30 毫秒尝试锁定而不是解锁画布。2) 如果 while 循环的任何单个循环(迭代)花费的时间超过 35 毫秒,则会生成 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.

现在对于我所做的一些随机观察:

  1. 如果我在 while 循环中引入延迟,Thread.sleep()那么LockCanvas()时间会更长,随着延迟量的增加。

  2. Invalidate()我仍然使用 Snake 示例的/ onDraw()drawing-process看到这个问题。

  3. 我在一个类似简单的 libgdx 项目中看到了同样的波动,尽管该应用程序可以在桌面上完美运行。

  4. 我正在(物理)三星 Galaxy SIII 上进行调试。

  5. 提供1 像素宽度和 1 像素高度lockCanvas()的“脏”Rectangle并不会加快任何速度——我认为做更少的工作可能会更快乐。

  6. 在清单文件中,设置android:hardwareAccelerated="true"没有帮助。

  7. 同样在清单文件中,设置 supports-screensandroid:anyDensity="true"没有帮助。

  8. 构建到 .apk 并安装没有帮助。

  9. 运行未更改的喷气机游戏时,我看到了波涛汹涌的感觉。

对于不熟悉 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();
}

即使您不知道如何解决此问题,如果您在自己的设置中没有看到此问题,那么我很乐意听取您的意见,了解您的绘图方式和调试方式。

4

0 回答 0