2011-09-14 1 views
1

私はいくつかのアニメーションロジックを使用する時計アプリを書いています。 onCreate()では、私のアプリアクティビティは、run()内のループでロジック処理を実行するThreadを継承するクラスのインスタンスを割り当てます。私は、キャンバスへの描画を管理するために、(LunarLanderの例によるが、コンテキスト修正スイッチを備えた)スレッド化されたSurfaceViewを使用している。Android:私のアプリケーションから離れたところでシステムが応答しなくなる

フォーカスがある限り、アプリは正常に動作します。私はonPause()の論理スレッドをsuspend()し、onDesroy()でonResume()とstop()をresume()して、ユーザーが離れたときにリソースを消費していないことを確認します。

このアプリはエミュレータで問題なく動作します。私は離れて、私は邪悪な効果がないように私はしばしばアプリに切り替えることができます。

しかし、物理ハードウェア上でAndroidで実行しているときに、アプリから離れて数回戻っても、システム全体が応答しなくなります。最終的には、電話機は上部のスリープ/電源スイッチを含むすべての入力を無視し、バッテリを取り外して再起動する必要があります。

テストとして、私はロジックスレッドの作成を無効にしましたが、レンダリングコードをすべて同じにして、アニメーションロジックの小さなビットを実行して、問題を解決しました。この論理処理スレッドは、システムにとって非常に悪いものでなければなりません。私はこれに新しいので、おそらくnoobの間違いをしています。

この問題をどのようにプロファイルできるかについての助けや助言をいただければ幸いです。

EDIT:アクティビティのソースを一覧表示します。私はリストを明確にすることを望んでスレッドに無関係な小塊を取り出しました。廃止され

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

はい、私の元の投稿への編集として違反行為を追加しました。 。 – BHCPHX

答えて

1
Javaスレッドで

stop()resume()、およびsuspend()(すみません、私はここに新しい書式を、めちゃめちゃ場合)、使用すべきではありません。スレッドの自然順序は、onPause()で死に至らせて、新しいスレッドを再起動します。onResume()

+0

ああ、大丈夫です。私はそれが非難されているそれらの機能の言及をしなかったので、私が私の情報を得た古代のウェブページだったと思います。私はスレッドのrunメソッドがonPause()(システムがリソースをクリーンアップすると仮定します)、onResume()の別のスレッドを割り当て、システムを不安定化しないように変更しました。ありがとう。 – BHCPHX

+0

まだ 'Thread'オブジェクトへの参照を保持していない限り、Javaのガーベジコレクタはすべてをクリーンアップします(またはそれは想定されていますが、それはJVMプログラマにとっては問題です:P)。スレッドのrun()メソッドが完了すると、そのスレッドは死んだとみなされ、再起動できないか、例外がスローされることに注意してください。 – DeeV

関連する問題