2012-10-25 24 views
8

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.

+0

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. –

+0

Myślę, że "opóźnienie" jest spowodowane tym, co 'nandeesh' mówi w swojej odpowiedzi. To jest prawdopodobnie odpowiedź. – Luksprog

Odpowiedz

9

Kontrola wątku jest obecna tylko wtedy, gdy wykonywany jest przekaz na numer textView. Ale Układ widoku jest wykonywany tylko po wywołaniu OnCreate. Dopóki więc nie pojawi się Ui, zmiana textView nie spowoduje unieważnienia widoku.

Ale po wyświetleniu textView, wymagany jest przekaźnik UI, w którym to przypadku wątek jest sprawdzany. Więc masz wyjątek dopiero po pewnym czasie Oncreate, ale nie od razu.

+0

Dzięki za odpowiedź. Jest bardzo podobny do prawdy. –