post 메소드는 정확히 무엇을합니까?


106

나는 매우 이상한 기능을 만났습니다.

메인 스레드에서 애니메이션을 실행하려고하면 시작되지 않습니다. 내가 말한 애니메이션을 실행할 때

getView().post(new Runnable() {
            @Override
            public void run() {
                getView().startAnimation(a);
            }
        });

시작합니다.

나는 CurrentThread애니메이션을 시작하기 전에를 인쇄했고 둘 다 인쇄했습니다 main.

분명히 여기에 뭔가 빠졌는데 둘 다 메인 스레드에서 애니메이션을 시작해야하기 때문입니다 ... 내 생각 엔 포스트가 작업을 대기열에 추가 할 때 더 "정확한 시간"에 시작된다는 것입니다.하지만 알고 싶습니다. 여기서 더 깊이있는 일이 발생합니다.

편집 : 정리해 보겠습니다-내 질문은 왜 포스트에서 애니메이션을 시작하면 메인 스레드에서 애니메이션을 시작하면 시작되지 않는지입니다.


이 동작이 Android 버전에만 해당됩니까? Android 4.1.2에서 재현 할 수 없었습니다!
Akdeniz

이 동작을 Android 2.3.3에서 재현했습니다. 하지만 AnimationDrawable! 일반 Animation인스턴스는 각 설정에서 성공적으로 애니메이션을 시작했습니다. 에서는 AnimationDrawable케이스; 에서 시작하려고하면 onCreate그 순간보기에 연결되지 않았기 때문에 시작되지 않습니다. 따라서 .NET에 대한 스레딩 문제가 아닙니다 AnimationDrawable. 어쩌면 똑같은 것이 적용 Animation될까요? developer.android.com/guide/topics/graphics/…
Akdeniz

답변:


161

post : post는 Runnable이 메시지 대기열에 추가되도록합니다.

Runnable : 실행할 수있는 명령을 나타냅니다. 종종 다른 스레드에서 코드를 실행하는 데 사용됩니다.

run () : 클래스 코드의 활성 부분 실행을 시작합니다. 이 메서드는 Runnable을 구현하는 클래스로 생성 된 스레드가 시작될 때 호출됩니다.

getView().post(new Runnable() {

         @Override
         public void run() {
             getView().startAnimation(a);
         }
     });

코드 :getView().startAnimation(a);

귀하의 코드에서

post는 Runnable ( 코드 가 다른 스레드에서 실행 됨)이 메시지 큐를 추가하도록합니다.

따라서 startAnimation은 messageQueue 에서 가져올 때 새 스레드에서 시작됩니다.

[편집 1]

UI 스레드 (메인 스레드) 대신 새 스레드를 사용하는 이유는 무엇입니까?

UI 스레드 :

  • 응용 프로그램이 시작되면 Ui Thread가 자동으로 생성됩니다.

  • 적절한 위젯에 이벤트를 전달하는 역할을하며 여기에는 그리기 이벤트가 포함됩니다.

  • Android 위젯과 상호 작용하는 스레드이기도합니다.

예를 들어 화면에서 a 버튼을 터치하면 UI 스레드가 터치 이벤트를 위젯에 전달하고이 위젯은 누른 상태를 설정하고 이벤트 대기열에 무효화 요청을 게시합니다. UI 스레드는 요청을 대기열에서 빼고 자신을 다시 그리도록 위젯에 알립니다.

사용자가 longOperation을 수행하는 버튼을 누르면 어떻게됩니까?

((Button)findViewById(R.id.Button1)).setOnClickListener(           
             new OnClickListener() {        
        @Override
    public void onClick(View v) {
            final Bitmap b = loadImageFromNetwork();
            mImageView.setImageBitmap(b);
}
});

UI가 멈 춥니 다. 프로그램이 충돌 할 수도 있습니다.

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
        final Bitmap b = loadImageFromNetwork();
        mImageView.setImageBitmap(b);
    }
  }).start();
}

작업자 스레드에서 직접 UI를 업데이트하지 않는 Android 규칙을 위반합니다.

Android는 다른 스레드에서 UI 스레드에 액세스하는 여러 방법을 제공합니다.

  • Activity.runOnUiThread (실행 가능)
  • View.post (실행 가능)
  • View.postDelayed (실행 가능, long)
  • 매니저

아래와 같이

View.post (실행 가능)

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
      final Bitmap b = loadImageFromNetwork();
      mImageView.post(new Runnable() {
        public void run() {
          mImageView.setImageBitmap(b);
        }
      });
    }
  }).start();
}

매니저

final Handler myHandler = new Handler(Looper.getMainLooper());

(new Thread(new Runnable() {

    @Override
    public void run() {
       final Bitmap b = loadImageFromNetwork();
      myHandler.post(new Runnable() {                           

        @Override
        public void run() {
           mImageView.setImageBitmap(b);
          }
        });
      }
    })).start();                
}

여기에 이미지 설명 입력

더 많은 정보를 위해서

http://android-developers.blogspot.com/2009/05/painless-threading.html

http://www.aviyehuda.com/blog/2010/12/20/android-multithreading-in-a-ui-environment/


15
그렇다면 포스트에서 애니메이션을 시작하는 것이 결국 동일한 스레드에서 실행될 때 메인 스레드에서 실행하는 것과 다른 이유는 무엇입니까?
Gal

이 단일 스레드 모델은 Android 애플리케이션에서 성능이 저하 될 수 있기 때문입니다.
Talha

1
저조한 성능이 애니메이션을 표시하지 않는 것과 어떤 관계가 있습니까?
Gal

17
나는 이것이 질문에 대한 대답이라고 생각하지 않습니다. 이것은 ui-thread 및 멀티 스레딩에 대해 아무것도 모르는 초보자를위한 일반적인 대답과 비슷합니다. 이것은 큐에서 애니메이션을 앞으로 던져서 애니메이션이 작동하는 이유를 설명하지 않습니다. 애니메이션은 post () 또는 runOnUiThread () 트릭을 사용하지 않고 ui-thread에서 직접 실행해야합니다.
carrizo

3
모든 UI 작업은 메인 스레드 (UI 스레드)에 있어야합니다. 메인 스레드에서 바로 호출하는 대신 post ()를 사용하여 애니메이션을 작동시키는 트릭은 시간입니다. 메인 스레드에서 바로 호출하면 "지금 애니메이션 시작"이라고 말했지만 지금은보기가 준비되지 않았을 수 있습니다. 애니메이션 (측정, 그리기 ...) 그러나 post ()에 넣으면 anim에 대한 준비보기를 위해 대기열에 startAnimation이 언젠가 보류됩니다.
NguyenDat

35

onCreate 또는 onCreateView에서 수행되고 있습니까? 그렇다면 앱은 View가 창에 연결된 상태가 아닐 수 있습니다. 보기 측정 항목 및 위치와 같은 항목이 계산되지 않았을 수 있으므로보기 측정 항목을 기반으로하는 많은 알고리즘이 작동하지 않을 수 있습니다. Android 애니메이션은 일반적으로 UI 수학을 통해 실행해야합니다.

View.post는 실제로 View의 메시지 루프에 애니메이션을 큐에 넣으므로 뷰가 창에 연결되면 수동으로 실행하는 대신 애니메이션을 실행합니다.

실제로 UI 스레드에서 작업을 실행하고 있지만 다른 시간에


포스터에 "게시물이 Runnable을 유발합니다 (코드가 다른 스레드에서 실행 됨)"라고 표시된 경우 허용되는 대답은 잘못된 것입니다. 이 정답입니다 "당신은 실제로 UI 스레드에서 일을 실행하고 있지만, 다른 시간에"- 플러스 1
smitty1

18

여기 에서 좋은 답변을 찾으 십시오 . view.post ()는 handler.post ()와 거의 동일합니다. 기본 스레드 큐로 이동하고 다른 보류중인 작업이 완료된 후 실행됩니다. activity.runOnUiThread ()를 호출하면 UI 스레드에서 즉시 호출됩니다.


31
내가 찾은 큰 (그리고 매우 유용한) 차이점 중 하나는 View가 처음 표시 될 때 view.post ()의 runnable이 호출된다는 것입니다. IE에서는 뷰가 팽창 할 때 애니메이션이 시작되도록 설정 한 다음 나중에 어느 시점에서 마지막으로 뷰 계층 구조에 추가 할 수 있습니다. 어느 시점에서 애니메이션이 실행되고 그것에 대해 걱정할 필요가 없습니다.
DeeV

실제로 handler.post ()는 항상 메인 스레드에 메시지 / 실행 파일을 게시하는 것은 아닙니다. 핸들러가 생성되는 방법에 따라 다릅니다 (다른 스레드의 Looper에 연결될 수 있음). 반면에, view.post ()는 항상 주 스레드에서 실행됩니다
Yair Kukielka

4

내가 생각하는 문제는 post () 메서드를 호출하는 라이프 사이클 메서드 일 수 있습니다. onCreate ()에서하고 있습니까? 그렇다면 활동의 onResume () 문서에서 찾은 내용을 살펴보십시오.

onResume ()

API 레벨 1에 추가되었습니다. void onResume () onRestoreInstanceState (Bundle), onRestart () 또는 onPause () 후에 호출되어 활동이 사용자와 상호 작용하기 시작합니다. 애니메이션을 시작하고 독점 액세스 장치 (예 : 카메라)를 열 수있는 좋은 장소입니다 .

https://developer.android.com/reference/android/app/Activity.html#onResume ()

따라서 Joe Plante가 말했듯이 post ()를 호출하는 순간 뷰가 애니메이션을 시작할 준비가되지 않았을 수 있으므로 onResume ()으로 이동해보십시오.

PD : 실제로 코드를 onResume ()으로 옮기면 이미 ui-thread에 있고 뷰가 애니메이션을 시작할 준비가 되었기 때문에 post () 호출을 제거 할 수 있다고 생각합니다.


3
onResume처음에 "보기가 준비 됨"이 된 후 여러 번 호출 될 수 있습니다 (화면이 절전 모드로 전환되고 활동이 백 스택으로 푸시 됨 등). 에서 호출 onResume되면 애니메이션이 이미 시작된 날씨를 추적하여 여러 번 (재) 시작되는 것을 방지하기 위해 플래그가 필요할 수 있습니다.
samis
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.