2011-10-25 56 views
4

我有這個簡單的活動(Scala中,進口中省略):Android(在Scala中):StackOverflowError取決於何時啓動線程?

class TestActivity extends Activity { 
    private val TAG = "TestActivity" 

    private val mHandler = new Handler { 
    override def handleMessage(msg: Message) { 
     Log.d(TAG, "handleMessage") 
    } 
    } 

    private val mThread = new Thread { 
    override def run { 
     mHandler.sendEmptyMessage(0) 
     Thread.sleep(10) 
     run 
    } 
    }.start 

    override def onCreate(savedInstanceState: Bundle) { 
    super.onCreate(savedInstanceState) 
    setContentView(new TextView(this) { 
     setText("hello, world") 
    }) 
    } 
} 

正如你所看到的,mThread立即開始,run被重寫尾遞歸,它發送一個空的消息mHandler,睡了短週期並再次發送相同的消息。當活動開始時,我得到這個錯誤:

.... 
D/TestActivity(28224): handleMessage 
D/TestActivity(28224): handleMessage 
D/TestActivity(28224): handleMessage 
D/TestActivity(28224): handleMessage 
I/dalvikvm(28224): threadid=9: stack overflow on call to Landroid/os/MessageQueue;.nativeWake:VI 
I/dalvikvm(28224): method requires 8+20+0=28 bytes, fp is 0x43e33310 (16 left) 
I/dalvikvm(28224): expanding stack end (0x43e33300 to 0x43e33000) 
I/dalvikvm(28224): Shrank stack (to 0x43e33300, curFrame is 0x43e35fe0) 
W/dalvikvm(28224): threadid=9: thread exiting with uncaught exception (group=0x40015560) 

E/AndroidRuntime(28224): FATAL EXCEPTION: Thread-10 
E/AndroidRuntime(28224): java.lang.StackOverflowError 
E/AndroidRuntime(28224): at android.os.MessageQueue.enqueueMessage(MessageQueue.java:223) 
E/AndroidRuntime(28224): at android.os.Handler.sendMessageAtTime(Handler.java:457) 
E/AndroidRuntime(28224): at android.os.Handler.sendMessageDelayed(Handler.java:430) 
E/AndroidRuntime(28224): at android.os.Handler.sendEmptyMessageDelayed(Handler.java:394) 
E/AndroidRuntime(28224): at android.os.Handler.sendEmptyMessage(Handler.java:379) 
E/AndroidRuntime(28224): at com.iped.audiotest.MainActivity$$anon$2.run(Activity.scala:20) 
E/AndroidRuntime(28224): at com.iped.audiotest.MainActivity$$anon$2.run(Activity.scala:22) 
E/AndroidRuntime(28224): at com.iped.audiotest.MainActivity$$anon$2.run(Activity.scala:22) 
E/AndroidRuntime(28224): at com.iped.audiotest.MainActivity$$anon$2.run(Activity.scala:22) 
... 

現在,如果我沒有在創建後立即啓動mThread,像這樣:

private val mThread = new Thread { 
    override def run { 
     mHandler.sendEmptyMessage(0) 
     Thread.sleep(10) 
     run 
    } 
    } 

,並觸發它在其他地方,比如,在觸摸事件:

override def onTouchEvent(event: MotionEvent): Boolean = { 
    if (event.getAction == MotionEvent.ACTION_DOWN) 
     mThread.start 
    true 
    } 

事情會很好。

我無法解釋這一點。

+0

如果將睡眠超時時間增加爲100ms會發生什麼? – 2011-10-25 03:52:39

+0

結果是一樣的。我想什麼時候開始線程事宜。 – Aufheben

+0

似乎尾遞歸優化在第一種情況下不起作用。 – starblue

回答

1

所以我做了一些實驗,我不得不得出結論,如果尾部遞歸重寫的線程run在其創建的同一個表達式中啓動,尾部調用優化將失敗(或者是任何其他原因可能會導致錯誤)

壞?

class Test { 
    val mThread = new Thread { 
    override def run { 
     println("hello") 
     run 
    } 
    }.start 
} 

好:

class Test { 
    val mThread = new Thread { 
    override def run { 
     println("hello") 
     run 
    } 
    } 
    mThread.start 
} 

PS我正在運行Scala 2.9.1,但由於庫的規模較小,因此使用2.8.2進行Android開發。

0

如果你想立即啓動線程,爲什麼不把它放在onCreate()? 我不確定,但我認爲線程和onCreate的順序可能會導致錯誤。

+0

其實是什麼我發現只要我不立即啓動線程,StackOverflowError就不會發生。我認爲這與dalvik機制或scala類初始化的一些底層細節有關。 – Aufheben

相關問題