Miałem do czynienia z interesującym problemem. Jeśli piszesz następujący kod w metodzie aktywności onCreate/onStart/onResume
:Brak błędu "Tylko oryginalny wątek, który utworzył hierarchię widoku, może dotknąć jej widoków", gdy widok jest aktualizowany bez opóźnienia.
final Button myButton = (Button)findViewById(R.id.myButton);
final TextView myTextView = (TextView)findViewById(R.id.myTextView);
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
myTextView.setText("Hello text");
}
});
myButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
thread.start();
}
});
czyli
final TextView myTextView = (TextView)findViewById(R.id.myTextView);
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.currentThread().sleep(500);
}
catch (InterruptedException e) {
e.printStackTrace();
}
myTextView.setText("Hello text");
}
});
thread.start();
jak należy, zostanie zgłoszony błąd
android.view.ViewRoot $ CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."
Jest oczywiste, że w takim przypadku muszę zaktualizować widok w wątku interfejsu użytkownika:(Handler, AsyncTask, runOnUiThread, view.post).
Ale jeśli zaktualizujesz widok w innym wątku bez opóźnień (bez wywoływania snu lub bez uruchamiania wątku przez naciśnięcie przycisku), wyjątek nie zostanie zgłoszony.
final TextView myTextView = (TextView)findViewById(R.id.myTextView);
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
myTextView.setText("Hello text");
}
});
thread.start();
Czy ktoś może mi powiedzieć, dlaczego istnieje takie zachowanie?
UPDATE:
nauczyłem kod źródłowy Androida i doszła do następujących wniosków. Nandeesh napisał prawdę. Podczas inicjowania widoku o nazwie dispatchAttachedToWindow (informacja AttachInfo info, int visibility) metody View, która inicjalizuje pole mAttachInfo. Obiekt mAttachInfo ma pole mViewRootImpl. Jeśli jest null, getViewRootImpl będą zwracane jako wartość null:
public ViewRootImpl getViewRootImpl() {
if (mAttachInfo != null) {
return mAttachInfo.mViewRootImpl;
}
return null;
}
ViewRootImpl zawiera metodę checkThread. Porównuje wątki: wątek, który utworzył widok i wątek żądania aktualizacji widoku.
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
Tak więc, jeśli widok nie został zainicjowany, nie ma czeku i zmiany nie wyrzuca wyjątków.
Tak, eksperymentowałem również z parametrem opóźnienia. Ale zastanawiam się, dlaczego. Wydaje się, że wątek zajmuje trochę czasu, aby zainicjować, podczas którego możemy zmieniać składniki interfejsu użytkownika. Ale nie widziałem wzmianki o tym w dokumentacji. –
Myślę, że "opóźnienie" jest spowodowane tym, co 'nandeesh' mówi w swojej odpowiedzi. To jest prawdopodobnie odpowiedź. – Luksprog