Когда вы комментируете Thread.sleep(3000)
, ваше приложение по-прежнему работает без сбоев, потому что в это время textView
еще не отображается на экране.Чтобы убедиться, что textView
видна на экране, вы можете использовать addOnGlobalLayoutListener .Теперь ваше приложение всегда дает сбой, независимо от того, комментируете ли вы Thread.sleep(3000)
или нет.
class MainActivity : AppCompatActivity() {
lateinit var textView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView = findViewById(R.id.textView)
textView.viewTreeObserver.addOnGlobalLayoutListener {
// This view is visible on screen
val task = MyAsyncTask()
task.execute()
}
}
inner class MyAsyncTask : AsyncTask<Void, Void, String>() {
override fun doInBackground(vararg params: Void?): String {
// Thread.sleep(3000)
textView.text = "From AsyncTask From AsyncTask From AsyncTask"
return "hello"
}
}
}
С другой стороны, когда вы не комментируете Thread.sleep(3000)
, ваше приложение немедленно вылетает через 3 секунды.потому что в это время textView
уже виден на экране, поэтому ваше приложение вылетает.
Итак, откуда взялась эта исключительная ситуация.Взгляните на исходный код ViewRootImpl
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
с по этой ссылке
requestLayout ()
Если что-то в вашем представлении изменится, что повлияет на размер, вам следует вызвать requestLayout ().Это вызовет onMeasure и onLayout не только для этого представления, но и до линии родительских представлений.
Когда вы обновляете текст для textView
, его размер будет изменен, поэтому requestLayout
вызывается, в результате он вызывает checkThread
и выбрасывает CalledFromWrongThreadException
.