[Android] AsyncTask 메커니즘

8723 단어 Android
개인 블 로그:http://www.milovetingting.cn
AsyncTask 는 UI 스 레 드 를 쉽게 사용 할 수 있 습 니 다.백 스테이지 작업 을 허용 하고 결 과 를 UI 스 레 드 에 발표 합 니 다. 스 레 드 나 Handler 를 조작 하지 않 아 도 됩 니 다.AsyncTask 는 Thread, Handler 와 관련 된 도움말 클래스 로 설계 되 었 습 니 다.AsyncTask 는 짧 은 시간 (최대 몇 초) 의 작업 에 사 용 됩 니 다.
AsyncTask 사용 시 다음 과 같은 몇 가 지 를 주의해 야 합 니 다:
  • AsyncTask 류 는 UI 스 레 드 에 불 러 와 야 합 니 다.AsyncTask 는 UI 스 레 드 를 예화 해 야 합 니 다.execute () 방법 도 UI 스 레 드 에서 호출 해 야 합 니 다.
  • onPreExecute (), onPostExecute (), doInBackground (), onProgressUpdate () 방법 을 수 동 으로 호출 하지 마 십시오.
  • 모든 AsyncTask 인 스 턴 스 는 execute 를 한 번 만 호출 할 수 있 습 니 다. 다시 호출 하면 이상 이 발생 합 니 다.

  • AsyncTask 가 처음 도 입 했 을 때 AsyncTask 의 임 무 는 직렬 이 었 습 니 다.Android 1.6 이후 AsyncTask 는 병행 으로 설계 되 었 다.Android 3.0 이후 AsyncTask 는 직렬 로 재 설계 되 었 다.3.0 이후 버 전에 서 병행 이 필요 하 다 면 AsyncTask 의 execute OnExecutor (java. util. concurrent. Executor, Object []) 방법 을 사용 하여 수 동 으로 Executor 에 전송 할 수 있 습 니 다.
    AsyncTask 클래스 를 불 러 올 때 Thread PoolExecutor 를 초기 화 합 니 다.
    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }
    

    그 중에서 핵심 스 레 드 수 는 최소 2 개, 최대 4 개 입 니 다.
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    

    최대 스 레 드 수 CPU 수량 * 2 + 1:
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    

    KeepAlive 시간 은 30s 입 니 다.
    private static final int KEEP_ALIVE_SECONDS = 30;
    

    퀘 스 트 대기 열 최대 128:
    private static final BlockingQueue sPoolWorkQueue =
            new LinkedBlockingQueue(128);
    

    AsyncTask 의 기본 사용:
    1. 하나의 종 류 를 정의 합 니 다. AsyncTask 에서 계승 하고 필요 에 따라 doInBackground (), onProgressUpdate (), onPostExecute () 방법 을 다시 작성 합 니 다. 보통 doInBackground (), onPostExecute () 방법 은 다시 써 야 합 니 다. 여기 서 자신의 업 무 를 실현 합 니 다.doInBackground () 방법 은 하위 스 레 드 에서 실 행 됩 니 다.onProgressUpdate () 와 onPostExecute () 는 UI 스 레 드 에서 실 행 됩 니 다.
    private class DownloadFilesTask extends AsyncTask {
          protected Long doInBackground(URL... urls) {
              int count = urls.length;
              long totalSize = 0;
              for (int i = 0; i < count; i++) {
                  totalSize += Downloader.downloadFile(urls[i]);
                  publishProgress((int) ((i / (float) count) * 100));
                  // Escape early if cancel() is called
                  if (isCancelled()) break;
              }
              return totalSize;
          }
     
          protected void onProgressUpdate(Integer... progress) {
              setProgressPercent(progress[0]);
          }
     
          protected void onPostExecute(Long result) {
              showDialog("Downloaded " + result + " bytes");
          }
      }
    

    2. DownloadFilesTask 의 인 스 턴 스 를 만 들 고 execute () 방법 을 실행 합 니 다.
    new DownloadFilesTask().execute(url1, url2, url3);
    

    다음은 소스 코드 측면 에서 AsyncTask 의 원 리 를 분석 해 보 자.
    AsyncTask 의 실행 입 구 는 execute 방법 입 니 다.
    @MainThread
    public final AsyncTask execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    

    execute () 방법 은 UI 스 레 드 에서 호출 되 어야 합 니 다.방법 내부 에서 execute OnExecutor () 방법 을 호출 하 였 습 니 다.
    @MainThread
    public final AsyncTask executeOnExecutor(Executor exec,
            Params... params) {
    	//  AsyncTask  ,       (           ),        
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }
    
    	//     RUNNING
        mStatus = Status.RUNNING;
    
        onPreExecute();
    
        mWorker.mParams = params;
        exec.execute(mFuture);
    
        return this;
    }
    

    execute OnExecutor () 방법 도 UI 스 레 드 에서 호출 해 야 합 니 다.방법 이 시 작 될 때 AsyncTask 상 태 를 검사 합 니 다. 실행 되 지 않 은 상태 (예 를 들 어 작업 이 실행 중이 거나 완료 되 었 을 때) 가 아 닌 이상 을 던 집 니 다.그 다음 에 작업 상 태 를 RUNNING 상태 로 설정 하고 onPreExecute () 방법 을 호출 합 니 다. 이 방법 은 스스로 재 작성 해 야 합 니 다. UI 알림 을 할 수 있 습 니 다.그리고 매개 변 수 를 mWorker 로 설정 하고 Executor 의 execute () 방법 을 호출 합 니 다.
    기본 Executor 를 사용 하면 직렬 입 니 다.
    @MainThread
    public static void execute(Runnable runnable) {
        sDefaultExecutor.execute(runnable);
    }
    

    다음은 sDefaultExecutor 의 정 의 를 살 펴 보 겠 습 니 다.
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    

    그리고 SERIALEXECUTOR 의 구체 적 인 실현 은 다음 과 같다.
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    
    private static class SerialExecutor implements Executor {
        final ArrayDeque mTasks = new ArrayDeque();
        Runnable mActive;
    
        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }
    
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
    

    mWorker 의 정의:
    mWorker = new WorkerRunnable() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
    				//          
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
    				//  doInBackground  
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
    				//    
                    postResult(result);
                }
                return result;
            }
        };
    

    execute () 방법 을 실행 하면 mWorker 의 call () 방법 을 호출 합 니 다. 이 방법 에서 스 레 드 를 배경 스 레 드 로 설정 한 다음 doInBackground () 방법 을 호출 하고 실행 이 끝 난 후에 post Result () 방법 을 호출 합 니 다.doInBackground () 방법 에 서 는 PublishProgress () 방법 을 사용 하여 진행 정 보 를 UI 스 레 드 에 보 낼 수 있 습 니 다.
    postResult () 방법:
    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult(this, result));
        message.sendToTarget();
        return result;
    }
    

    Handler 에 메시지 보 내기.
    private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }
    
        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult> result = (AsyncTaskResult>) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }
    

    Handler 의 handle Message () 방법 에서 메 시 지 를 처리 합 니 다.실행 이 완료 되면 AsyncTask 의 finish () 방법 을 사용 합 니 다. 업데이트 진도 라면 AsyncTask 의 onProgressUpdate () 방법 을 사용 합 니 다.
    private void finish(Result result) {
        if (isCancelled()) {
    		//       ,   onCancelled()  。
            onCancelled(result);
        } else {
    		//  onPostExecute()  
            onPostExecute(result);
        }
    	//     FINISHED
        mStatus = Status.FINISHED;
    }
    
    @MainThread
    protected void onProgressUpdate(Progress... values) {
    }
    

    publishProgress () 방법:
    @WorkerThread
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult(this, values)).sendToTarget();
        }
    }
    

    좋은 웹페이지 즐겨찾기