2016-10-13 2 views
3

이 코드가 작동하는 이유는 무엇입니까?HandlerThread의 루퍼를 설정 한 Handler가 UI 개체와 상호 작용할 수있는 이유는 무엇입니까?

@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 스레드, 또는 내가 너무 감사합니다, 나는 몇 가지 조사를 가지고 있지만 아직, 도와주세요 답을 찾을 수없는 무언가를

를 그리워 어딘가에서 읽을 많은 사람들.

내가 @nshmura에서이 코드를 시도

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]

UPDATE 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 $ CalledFromWr ongThreadException : 뷰 계층 구조를 만든 원래 스레드 만 해당 뷰를 만질 수 있습니다.

+0

나는 당신의 가야를 받고 있지 않다. –

+0

핸들러를 no-args 생성자 또는 Handler (Looper.getMainLooper())를 사용하여 초기화하십시오. 이렇게하면 핸들러가 주 스레드에서 실행되고이 핸들러에서 뷰를 업데이트 할 수 있습니다 –

답변

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

     } 
    }); 

예외 상황이 발생합니다 아마 ViewRootImpl.checkThread()Activity.onCreate()

에서 호출되지 않습니다

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) 

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.이 경우에만 발생합니다

+0

이 코드를 시도하고 동일한 오류가 너무 혼란 스럽습니다. – kittenforcode

0

제외 : 비 UI 스레드

  • 전화에서 호출

    1. 는 레이아웃 변경이 필요합니다. 예를 들어, TextView의 크기 (폭과 높이) 때문에 너무 긴 문자열

    그래서 UI 작업이 레이아웃 변경 (만들거나 다시)으로 이어질하지 않는 경우에는 예외로 확장 할 필요가있는 경우 던져 질 수 없다.

  • +0

    폭과 높이 모두 TextView를 'wrap_content'로 설정하여 OP와 동일한 예제를 실행합니다. 이 예제는 텍스트를 변경합니다. 레이아웃 변경을 최종적으로 요구해서는 안됩니까? –

    +0

    yes 고정 크기로 시도하십시오 – dit

    +0

    제 생각에 당신이 놓친 것 같아요 ... 레이아웃 변경을 트리거하기 위해 크기'wrap_content'를 만들었습니다. 당신이 제안 된 답변이 정확하다면, 앱은'CalledFromWrongThreadException' 때문에 충돌 할 것입니다 -하지만 그렇지 않습니다. –

    0

    핸들러 객체는 자신이 생성 된 스레드에 자신을 등록합니다. 이 스레드에 데이터를 보낼 수있는 채널을 제공합니다. 예를 들어, 액티비티의 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(); 
    
    +0

    사실이라면 onClick 메서드에서 코드를 사용할 때 여전히 오류가 발생합니다. – kittenforcode

    +0

    HandlerThread의 생성 인스턴스를 이동 한 이유는 무엇입니까? 처리기 부분에 onClick 메서드하지만 오류가 여전히 발생합니다 : ( – kittenforcode

    +0

    btw onClick 다른 thead에서 실행하는 경우 UI보기를 만지지 수 있습니다. – kittenforcode