2012-10-25 4 views
8

面白い問題が発生しました。ビューが遅れずに更新されたときに「ビュー階層を作成した元のスレッドのみがビューにアクセスできます」

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(); 
    } 
}); 

か:あなたは活動のonCreate/onStart/onResume方法に次のコードを記述する場合

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(); 

は、エラーがスローされ、それはすべきか

android.view.ViewRoot $ CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views." 

それはあることは明らかですこの場合は、ui-threadでビューを更新する必要があります(Handler, AsyncTask, runOnUiThread, view.post).

しかし、別のスレッドのビューを遅く(スリープ呼び出しをせずに、またはボタンを押してスレッドを開始せずに)更新すると、例外はスローされません

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(); 

なぜこのような動作があるのですか?

UPDATE:

私は、Androidのソースコードを学んだし、次の結論に達したてきました。 ナンディーは真実を書きました。 ビューの初期化時に、mAttachInfoフィールドを初期化するViewのdispatchAttachedToWindow(AttachInfo info、int visibility)メソッドが呼び出されました。 mAttachInfoオブジェクトにはmViewRootImplフィールドがあります。それがnullの場合、getViewRootImplはnullを返します:

public ViewRootImpl getViewRootImpl() { 
     if (mAttachInfo != null) { 
      return mAttachInfo.mViewRootImpl; 
     } 
     return null; 
    } 

ViewRootImplはcheckThreadメソッドが含まれています。これはスレッドを比較します。ビューを作成したスレッドと、ビューの更新要求のスレッドです。

void checkThread() { 
     if (mThread != Thread.currentThread()) { 
      throw new CalledFromWrongThreadException(
        "Only the original thread that created a view hierarchy can touch its views."); 
     } 
    } 

したがって、ビューが初期化されていない場合、チェックと変更は例外をスローしません。

+0

はい、遅延パラメータも試しました。しかし、なぜ私は不思議に思っています。 スレッドが初期化するまでに時間がかかり、その間にui-componentが変更されるようです。しかし、私はドキュメンテーションでこれについては言及していません。 –

+0

「遅延」は、「nandeesh」が答えていることによると思います。それはおそらく答えです。 – Luksprog

答えて

9

textView再レイアウトが行われた場合にのみ、スレッドのチェックが存在します。しかし、ビューのレイアウトは、OnCreateが呼び出された後にのみ行われます。 Uiが表示されなくなるまで、textViewを変更してもビューが無効になることはありません。

しかし、いったんtextViewが表示されると、UIの再レイアウトが必要になります。その場合は、スレッドがチェックされます。だから、あなたはOncreateのある時間の後で例外を得るが、すぐにはそれを取得しない。

+0

返事をありがとう。真実に非常に似ています。 –

関連する問題