Android:从我的应用程序切换后系统变得无法响应

时间:2011-09-14 09:19:18

标签: android

我正在编写一个使用一些动画逻辑的时钟应用程序。在onCreate()中,我的应用程序Activity分配一个扩展Thread的类的实例,该类在run()的循环中执行逻辑处理。我正在使用线程化SurfaceView(根据LunarLander示例,但使用上下文修复开关)来管理绘图到Canvas。

只要具有焦点,应用程序就可以正常运行。我在onPause()中挂起()逻辑线程,并在onResume()中恢复它()并在onDestroy()中停止()它以确保在用户切换时不消耗资源。

此应用在模拟器上运行时没有问题。我可以随心所欲地切换回应用程序,没有任何不良影响。

但是当在物理硬件上运行Android时,如果你从我的应用程序切换回来几次,整个系统将无法响应。最终手机会忽略所有输入,包括顶部的睡眠/电源开关,必须通过取出电池重新启动。

作为一个测试,我禁用了逻辑线程的创建但是让渲染代码完全相同并运行了一小部分动画逻辑,它解决了问题,所以我觉得这是我正在做的事情逻辑处理系统必须非常坏的线程。我是新手,所以我可能会犯一个菜鸟错误。

我们非常感谢有关如何描述此问题的任何帮助或指示信息。

编辑:列出活动源。为了澄清清单,我已经拿出了一小部分无关紧要的帖子。 (对不起,如果我弄乱了格式化,这里新的)

public class EyesClockActivity extends Activity
implements SensorEventListener
{
// ---- options (shared preferences) ----
// snip, couple of booleans 

// --------------------------------------------------------
private void    LoadPreferences()
{
}   // end EyesClockActivity.LoadPreferences()

// --------------------------------------------------------
private void    SavePreferences()
{
}   // end EyesClockActivity.SavePreferences()

// ========================================================
private class EyesClockActivityThread extends Thread
{
    private long m_LastUpdateMilliSeconds;

    private boolean m_running = false;

    public void SetRunning( final boolean running ) 
    {
        // if restarting, don't want huge time leap
        if (        ( m_running == false )
                &&  ( running == true ) )
        {
            m_LastUpdateMilliSeconds = System.currentTimeMillis();
        }

        m_running = running; 
    }

    // ----------------------------------------------
    public EyesClockActivityThread()
    {
        m_digits = new EyeDigit[4];
        int index;
        for ( index = 0; index < m_digits.length; ++index )
        {
            m_digits[ index ] = new EyeDigit();
        }

        m_digits[0].SetCurrentDigit( 0 );
        m_digits[1].SetCurrentDigit( 0 );
        m_digits[2].SetCurrentDigit( 0 );
        m_digits[3].SetCurrentDigit( 0 );

        m_TestDigit.SetCurrentDigit( m_currentDigit );

        m_LastUpdateMilliSeconds = System.currentTimeMillis();

        m_lastDigitChangeMilliseconds = System.currentTimeMillis();

        int minute = Calendar.getInstance().get(Calendar.MINUTE);
        int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY );
        SetTime( hour, minute );            
    }   // end EyesClockActivityThread constructor

    // --------------------------------------------------------------------
    // sets digits to display specified hour,minute
    private void    SetTime( final int hour, final int minute )
    {
    }   // end method EyesClockActivityThread.SetTime()

    // ----------------------------------------------
    public  void    run()
    {
        while (true)
        {
            if ( m_running )
            {
                final   float   updatesPerSecond = 30.0f;

                final   long    milliSecondsBetweenUpdates = (long)(( 1.0f / updatesPerSecond ) * 1000.0f);

                long    currentTimeMilliSeconds = System.currentTimeMillis();

                // TODO sleep here instead of checking constantly
                if ( (currentTimeMilliSeconds - m_LastUpdateMilliSeconds) > milliSecondsBetweenUpdates )
                {
                    int minute = Calendar.getInstance().get(Calendar.MINUTE);

                    // don't bother setting time unless minute has changed
                    if ( (minute % 10) != m_digits[0].GetCurrentDigit() )
                    {
                        int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY );

                        SetTime( hour, minute );
                    }

                    float   secondsSinceLastUpdate = (float)((currentTimeMilliSeconds - m_LastUpdateMilliSeconds) / 1000.0);

                    for ( EyeDigit digit : m_digits )
                    {
                        digit.Update( secondsSinceLastUpdate );
                    }

                    // global update routines
                    m_LastUpdateMilliSeconds = System.currentTimeMillis();
                }
            }   // end if m_running
        }
    }   // end EyesClockActivityThread.run()

}   // end class EyesClockActivityThread

private EyesClockActivityThread     m_EyesActivityThread;

private EyesClockSurfaceView        m_EyesSurfaceView;

// ---- sensor interface ----
private SensorManager m_SensorManager;
private Sensor m_Accelerometer;


// -------------------------------------------------------------------------------
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) 
{
    EyeDigit.InitDigitDescriptors();

    m_EyesActivityThread = new EyesClockActivityThread();

    // No Title bar
    requestWindowFeature(Window.FEATURE_NO_TITLE);

    m_EyesActivityThread.SetRunning(true);
    m_EyesActivityThread.start();

    LoadPreferences();

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    m_EyesSurfaceView = (EyesClockSurfaceView)findViewById(R.id.eyesclocksurfaceview);

    Configuration config = getResources().getConfiguration();

    m_EyesSurfaceView.SetOrientation( config.orientation );

    m_EyesSurfaceView.SetDigits( m_EyesActivityThread.GetDigits() );

    m_SensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
    m_Accelerometer = m_SensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}   // end method EyesClockActivity.onCreate()

// ----------------------------------------------
protected void onPause() 
{
    super.onPause();

    // pause activity thread
    m_EyesActivityThread.SetRunning(false);
    m_EyesActivityThread.suspend();

    // quit sensor listening
    m_SensorManager.unregisterListener(this);
}   // end method EyesClockActivity.onPause()

// ----------------------------------------------------
protected void onResume() 
{
    super.onResume();

    // resume activity thread
    m_EyesActivityThread.SetRunning(true);
    m_EyesActivityThread.resume();

    m_SensorManager.registerListener(this, m_Accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}   // end method EyesClockActivity.onResume()

// ------------------------------------------------------
protected   void    onDestroy()
{
    super.onDestroy();

    m_EyesActivityThread.SetRunning(false);
    m_EyesActivityThread.stop();

    m_SensorManager.unregisterListener(this);

    // quit sensor listening
    m_SensorManager.unregisterListener(this);
}   // end method EyesClockActivity.onDestroy()

// -------------------------------------------------------
public void onAccuracyChanged(Sensor sensor, int accuracy) 
{
}

// ----------------------------------------------------
public void onSensorChanged(SensorEvent event) 
{
    if (        ( event.values[0] > 15.0f )
            ||  ( event.values[1] > 15.0f )
            ||  ( event.values[2] > 15.0f ) )
    {
        m_EyesActivityThread.StartGoogleyEvent();
    }
}   // end method EyesClockActivity.onSensorChanged()

// ---- options menu ----
@Override
public boolean onCreateOptionsMenu(Menu menu) 
{
    // add cursor blink toggle item
    menu.add( Menu.NONE, R.id.toggle_blink, Menu.NONE, R.string.string_blink_cursor);

    if ( GetTwelveHourDisplay())
    {
        menu.add( Menu.NONE, R.id.toggle_twelve_hour_display, Menu.NONE, R.string.string_24_hour_display );
    }
    else
    {
        menu.add( Menu.NONE, R.id.toggle_twelve_hour_display, Menu.NONE, R.string.string_12_hour_display );
    }

    return true;
}    

@Override
public boolean onPrepareOptionsMenu(Menu menu) 
{
    super.onPrepareOptionsMenu(menu);

    MenuItem displayItem = menu.getItem(1);

    if ( displayItem != null )
    {
        if ( GetTwelveHourDisplay())
        {
            displayItem.setTitle(R.string.string_24_hour_display);
        }
        else
        {
            displayItem.setTitle(R.string.string_12_hour_display);
        }
    }

    return true;
}    

@Override
public boolean onOptionsItemSelected(MenuItem item) 
{
    // Handle item selection
    switch (item.getItemId()) 
    {
    case R.id.toggle_twelve_hour_display:
        ToggleTwelveHourDisplay();

        int minute = Calendar.getInstance().get(Calendar.MINUTE);
        int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY );
        m_EyesActivityThread.SetTime( hour, minute );

        SavePreferences();

        return true;
    case R.id.toggle_blink :
        ToggleBlinkCursor();

        SavePreferences();

        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
} 

}

1 个答案:

答案 0 :(得分:1)

在java线程中,不推荐使用stop()resume()suspend(),不应使用它们。线程的自然顺序是让它在onPause()中死亡并在onResume()

重启一个新的线程