8

私は興味深い問題に直面しました。onCreate/onStart/onResumeアクティビティのメソッドで次のコードを記述した場合:

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

また:

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

なぜそのような行動があるのか​​誰か教えてもらえますか?

アップデート:

私はAndroidのソースコードを学び、次の結論に達しました。ナンディーシュは真実を書いた。ビューのdispatchAttachedToWindow(AttachInfo info、int visible)メソッドと呼ばれるビューを初期化する場合。これにより、mAttachInfoフィールドが初期化されます。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.");
        }
    }

したがって、ビューが初期化されていない場合、チェックは行われず、変更によって例外がスローされることはありません。

4

1 に答える 1

9

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

ただし、textViewが表示されると、UIリレーアウトが必要になります。この場合、スレッドがチェックされます。したがって、例外はOncreateのしばらく後にのみ発生しますが、すぐには発生しません。

于 2012-10-25T07:56:35.917 に答える