4

なぜこのコードが機能するのですか?

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Log.i("onCreate", Thread.currentThread().toString());
    textView = (TextView) findViewById(R.id.textView);
    imageView = (ImageView) findViewById(R.id.imageView);

    HandlerThread thread = new HandlerThread("myHandlerThread");
    thread.start();
    mUiHandler = new Handler(thread.getLooper());
    mUiHandler.post(new Runnable() {
        @Override
        public void run() {
            Log.i("Thread: ", Thread.currentThread().toString());
            Toast.makeText(getApplicationContext(), "Hello Cats!", Toast.LENGTH_SHORT).show();
            textView.setText("Hello Cats");
            imageView.setImageResource(R.mipmap.ic_launcher);
        }
    });

}

UI オブジェクトと通信できる唯一のスレッドは UI スレッドであるとどこかで読んだ、または何かを見逃している

私はいくつかの調査を行っていますが、まだ答えが見つかりません。助けてください。どうもありがとうございました。

これは私がログから得たものです

10-13 18:47:42.888 23841-23841/th.co.me.sampleapp I/onCreate: Thread[main,5,main] 10-13 18:47:42.891 23841-24041/th.co.me.sampleapp I/Thread:: Thread[myHandlerThread,5,main]

更新 1

私は@nshmuraからこのコードを試しましたが、エラーが発生しました。今はとても混乱しています

   textView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        HandlerThread thread = new HandlerThread("myHandlerThread");
        thread.start();
        mUiHandler = new Handler(thread.getLooper());
        mUiHandler.post(new Runnable() {
            @Override
            public void run() {
                Log.i("Thread: ", Thread.currentThread().toString());
                Toast.makeText(getApplicationContext(), "Hello Cats!", Toast.LENGTH_SHORT).show();
                textView.setText("Hello Cats");
                imageView.setImageResource(R.mipmap.ic_launcher);
            }
        });

    }
});

android.view.ViewRootImpl$CalledFromWrongThreadException: ビュー階層を作成した元のスレッドのみがそのビューにアクセスできます。

4

4 に答える 4

0

Handler オブジェクトは、それが作成されたスレッドに自身を登録します。このスレッドにデータを送信するチャネルを提供します。たとえば、アクティビティの onCreate() メソッドで新しい Handler インスタンスを作成すると、それを使用してデータをメイン スレッドにポストできます。Handler クラスを介して投稿できるデータは、Message または Runnable クラスのインスタンスです。

したがって、以下の行に基づいて、ハンドラーは HandlerThread に属している必要があります。

mUiHandler = new Handler(thread.getLooper());

OnCreate() はメインスレッドですが、OnClick Listener は別のクラスです。つまり、コンテキストの違いがあります。

例えば:

// onCreate() we are writing like this
 Toast.makeText(this, "Hello Cats!", Toast.LENGTH_SHORT).show();
// but in Onclick method we are writing like this
 Toast.makeText(MainActivity.this, "Hello Cats!", Toast.LENGTH_SHORT).show();
于 2016-10-13T12:52:42.670 に答える
0

次の場合にのみ、例外android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.がスローされます。

  1. 非 UI スレッドから呼び出されました
  2. 呼び出しにはレイアウトの変更が必要です。たとえば、TextView文字列が長すぎるために a のサイズ (幅と高さ) を拡張する必要がある場合

そのため、UI 操作によってレイアウトの変更 (作成または再作成) が発生しない場合、例外はスローされない可能性があります。

于 2016-10-13T12:34:40.687 に答える
-1

次のように確認します。

    textView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            HandlerThread thread = new HandlerThread("myHandlerThread");
            thread.start();
            mUiHandler = new Handler(thread.getLooper());
            mUiHandler.post(new Runnable() {
                @Override
                public void run() {
                    Log.i("Thread: ", Thread.currentThread().toString());
                    Toast.makeText(getApplicationContext(), "Hello Cats!", Toast.LENGTH_SHORT).show();
                    textView.setText("Hello Cats");
                    imageView.setImageResource(R.mipmap.ic_launcher);
                }
            });

        }
    });

例外が発生します:

  android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
      at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6556)
      at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:942)
      at android.view.ViewGroup.invalidateChild(ViewGroup.java:5081)
      at android.view.View.invalidateInternal(View.java:12719)
      at android.view.View.invalidate(View.java:12683)
      at android.view.View.invalidate(View.java:12667)
      at android.widget.TextView.checkForRelayout(TextView.java:7156)
      at android.widget.TextView.setText(TextView.java:4347)
      at android.widget.TextView.setText(TextView.java:4204)
      at android.widget.TextView.setText(TextView.java:4179)

多分 はViewRootImpl.checkThread()で呼び出されませんActivity.onCreate()

于 2016-10-13T12:21:05.053 に答える
-2

このコードを試してください

mHandler = new Handler();

new Thread(new Runnable() {
    @Override
    public void run () {
        // Perform long-running task here
        // (like audio buffering).
        // you may want to update some progress
        // bar every second, so use handler:
        mHandler.post(new Runnable() {
            @Override
            public void run () {
                // make operation on UI - on example
                // on progress bar.
            }
        });
    }
}).start();
于 2016-10-13T12:03:11.557 に答える