Android 2D图形很糟糕

时间:2013-07-03 19:20:48

标签: android performance 2d android-canvas surfaceview

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.

现在我做了一些随机观察:

  1. 如果我使用Thread.sleep()在while循环中引入延迟,那么LockCanvas()时间会更长,缩放时会延迟。

  2. 我仍然使用Snake示例的Invalidate() / onDraw()绘图过程看到此问题。

  3. 我在同样简单的libgdx项目中看到了同样的不稳定,尽管应用程序在桌面上运行完美。

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

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

  6. 在清单文件中,设置android:hardwareAccelerated="true"无效。

  7. 再次在清单文件中,设置支持屏幕android:anyDensity="true"无效。

  8. 构建到.apk并安装无济于事。

  9. 我在运行未经改变的电子游戏时看到了不稳定。

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

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

0 个答案:

没有答案