Android의 단일 스레드

4770 단어
라인
응용 프로그램이 시작될 때, 시스템은 응용 프로그램에 '주 루틴' 이라는 실행 루틴을 만들 것입니다.이 라인은 매우 중요하다. 왜냐하면 이벤트를 해당하는 사용자 인터페이스의 작은 위젯에 나누어 주는 것을 책임지기 때문이다. 이는 그림 이벤트를 포함하기 때문이다.또한 안드로이드 UI 패키지 구성 요소 (android.widget과android.view 패키지에서 온 구성 요소) 와 상호작용을 하는 라인이기도 합니다.따라서 주 스레드를 UI 스레드라고도 합니다.
시스템은 모든 구성 요소의 실례에 대해 단독 라인을 만들지 않습니다.동일한 프로세스에서 실행되는 모든 구성 요소는 UI 스레드에서 인스턴스화되고 각 구성 요소에 대한 시스템 호출은 스레드로 분할됩니다.따라서 시스템 리셋에 응답하는 방법(예를 들어 사용자의 동작을 보고하는 onKeyDown()이나 생명주기 리셋 방법)은 프로세스의 UI 스레드에서 항상 실행된다.
예를 들어 사용자가 화면의 단추를 터치할 때, 적용된 UI 라인은 터치 이벤트를 작은 위젯에 나누어 주고, 작은 위젯은 거꾸로 누르는 상태를 설정하여, 실효 요청을 이벤트 대기열에 발표합니다.UI 스레드는 대기열에서 요청을 취소하고 작은 위젯이 자신을 다시 그려야 한다고 알립니다.
응용 프로그램이 사용자의 상호작용에 응답하기 위해 복잡한 작업을 수행할 때, 응용을 정확하게 실현하지 않으면, 이런 단일 라인 모드는 성능 저하를 초래할 수 있다.구체적으로 UI 스레드가 모든 작업을 처리해야 하는 경우 네트워크 액세스나 데이터베이스 조회와 같은 오랜 시간이 소요되는 작업을 수행하면 UI 전체가 차단됩니다.라인이 막히면 그림 그리기 이벤트를 포함한 모든 이벤트를 할당할 수 없습니다.사용자의 입장에서 볼 때, 응용은 마운트된 것으로 나타난다.더 심각한 것은 UI 스레드가 몇 초 이상 막히면 (현재 약 5초) 사용자들은 짜증나는 '응용 무응답' (ANR) 대화상자를 볼 수 있다.사용자의 불만을 일으키면, 이 프로그램을 종료하고 마운트 해제하기로 결정할 수도 있습니다.
또한 Android UI 키트는 스레드 보안 키트가 아닙니다.따라서 작업 스레드를 통해 UI를 조작할 수 없고 UI 스레드를 통해서만 사용자 인터페이스를 조작할 수 있습니다.따라서 Android의 단일 스레드 모드는 두 가지 규칙을 준수해야 합니다.
  • UI 스레드 차단 방지
  • UI 스레드 외부에서 Android UI 키트에 액세스하지 마십시오
  • 작업 스레드
    위의 단일 스레드 모드에 따라 UI 적용에 대한 응답성을 유지하려면 UI 스레드를 차단하지 않는 것이 중요합니다.만약 실행된 작업이 빨리 완성되지 않는다면, 단독 루트 ('백엔드' 또는 '작업' 루트) 에서 실행되는지 확인해야 한다.예를 들어, 다음 코드는 클릭 탐지기가 개별 스레드에서 이미지를 다운로드하여 ImageView에 표시하는 것을 보여줍니다.
    public void onClick(View v) {
      new Thread(new Runnable() {
        public void run() {
            Bitmap b = loadImageFromNetwork("http://example.com/image.png");
            mImageView.setImageBitmap(b);
        }
    }).start();}
    

    언뜻 보기에, 이 코드는 네트워크 조작을 처리하기 위해 새로운 라인을 만들었기 때문에 잘 작동하는 것 같다.그러나 단일 스레드 모드의 두 번째 규칙을 위반했다. UI 스레드 밖에서 안드로이드 UI 패키지에 접근하지 마라. 이 예는 UI 스레드가 아닌 작업 스레드에서 ImageView를 수정했다.이것은 명확하지 않고 예견할 수 없는 행위를 초래할 수 있지만, 이 행위를 추적하기는 어렵고 시간도 걸린다.
    Android는 이 문제를 해결하기 위해 다른 스레드에서 UI 스레드에 액세스할 수 있는 여러 가지 방법을 제공합니다.다음과 같은 유용한 방법이 있습니다.
  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable)
  • View.postDelayed(Runnable, long)

  • 예를 들어, View를 사용할 수 있습니다.post(Runnable) 방법으로 위의 코드를 수정합니다.
    public void onClick(View v) {
      new Thread(new Runnable() {
        public void run() {
            final Bitmap bitmap =
                    loadImageFromNetwork("http://example.com/image.png");
            mImageView.post(new Runnable() {
                public void run() {
                    mImageView.setImageBitmap(bitmap);
                }
            });
        }
    }).start();}
    

    이제 위와 같은 구현은 스레드 보안에 속합니다. 단독 스레드에서 네트워크 작업을 완성하고 UI 스레드에서 ImageView를 조작합니다.
    그러나 조작이 갈수록 복잡해지면서 이런 코드도 복잡해지고 유지보수하기 어려워진다.작업 스레드를 통해 더욱 복잡한 상호작용을 처리하려면 작업 스레드에서Handler를 사용하여 UI 스레드에서 온 메시지를 처리하는 것을 고려할 수 있습니다.물론 가장 좋은 해결 방안은 AsyncTask 클래스를 확장하는 것입니다. UI와 상호작용을 하는 데 필요한 작업 스레드 작업을 간소화하는 것입니다.
    AsyncTask 사용
    AsyncTask 를 사용하면 사용자 인터페이스에서 비동기식 작업을 수행할 수 있습니다.워크스레드의 작동을 차단한 다음 직접 스레드 및/또는 프로세서를 처리할 필요 없이 UI 스레드에 결과를 게시합니다.
    이를 사용하려면 AsyncTask의 하위 클래스를 만들고 DoInBackground () 리셋 방법을 실행해야 합니다. 이 방법은 백엔드 스레드 풀에서 실행됩니다.UI를 업데이트하려면 DoInBackground () 가 되돌아오는 결과를 전달하고 UI 스레드에서 실행해야 UI를 안전하게 업데이트할 수 있습니다.나중에 UI 스레드에서 excute()를 호출하여 작업을 실행할 수 있습니다.
    예를 들어, 다음과 같은 방법으로 AsyncTask를 사용하여 이러한 예제를 수행할 수 있습니다.
    public void onClick(View v) {
        new DownloadImageTask().execute("http://example.com/image.png");
    }
    
    private class DownloadImageTask extends AsyncTask {
        /** The system calls this to perform work in a worker thread and
          * delivers it the parameters given to AsyncTask.execute() */
        protected Bitmap doInBackground(String... urls) {
            return loadImageFromNetwork(urls[0]);
        }
    
        /** The system calls this to perform work in the UI thread and delivers
          * the result from doInBackground() */
        protected void onPostExecute(Bitmap result) {
            mImageView.setImageBitmap(result);
        }
    }
    

    현재 UI는 안전하고 코드도 간소화되었다. 왜냐하면 임무는 두 부분으로 분해되었기 때문이다. 하나는 작업 라인에서 완성해야 하고 다른 하나는 UI 라인에서 완성해야 한다.
    다음은 AsyncTask의 작동 방법에 대한 간략한 설명입니다. 그러나 이러한 방법을 완전히 이해하려면 AsyncTask 참조 문서를 읽어야 합니다.
    범용적으로 매개 변수 형식, 진도 값, 작업 최종 값을 지정할 수 있는 방법doInBackground () 는 작업 라인에서onPreExecute (), onPostExecute (), onProgressUpdate () 를 자동으로 실행합니다. UI 라인에서doInBackground () 를 호출하면 되돌아오는 값은 onPostExecute () 로 보내집니다. 언제든지 DoInBackground () 에서pushProgress () 를 호출할 수 있습니다.UI 스레드에서 onProgressUpdate () 를 실행하려면 언제든지 스레드의 작업을 취소할 수 있습니다.
    주의: 작업 스레드를 사용할 때 또 다른 문제가 발생할 수 있습니다. 즉, 실행 중 설정 변경 (예를 들어 사용자가 화면 방향을 변경한 것) 은 Activity를 의외로 다시 시작합니다. 이것은 작업 스레드를 삭제할 수 있습니다.이러한 재부팅 상황에서 작업을 계속 수행하는 방법과 Activity가 소각되었을 때 작업을 정확하게 취소하는 방법을 알아보려면 책꽂이의 예시 응용 프로그램의 원본 코드를 참고하십시오.

    좋은 웹페이지 즐겨찾기