AsyncTask 의 올 바른 사용

9607 단어 기초 지식
우선, AsyncTask 사용 시의 결함 문 제 를 첨부 합 니 다.
출처:
http://blog.csdn.net/goodlixueyong/article/details/45895997
원문 내용:
안 드 로 이 드 개발 에서 AsyncTask 는 사용자 가 Thread 류 와 Handler 를 직접 사용 하여 배경 작업 을 처리 하 는 것 을 피 할 수 있 고 비동기 처리 데이터 가 필요 하고 데 이 터 를 인터페이스 에 업데이트 하 는 경우 에 적용 된다.AsyncTask 는 백 스테이지 작업 에 몇 초 밖 에 걸 리 지 않 는 짧 은 시간 작업 에 적 용 됩 니 다.그러나 AsyncTask 자체 에 나 쁜 문제 가 많 습 니 다. 사용 중 주의 하지 않 으 면 프로그램의 건장 성에 영향 을 줄 수 있 습 니 다.
1. 수명 주기
       많은 개발 자 들 은 Activity 에서 만 든 AsyncTask 가 Activity 의 폐기 에 따라 폐기 된다 고 생각 할 것 이다.그러나 사실은 그렇지 않다.AsyncTask 는 doInBackground () 방법 이 실 행 될 때 까지 계속 실 행 됩 니 다.그리고 cancel (boolean) 이 호출 되면 onCanceled (Result result) 방법 이 실 행 됩 니 다.그렇지 않 으 면 onPost Execute (Result result) 방법 을 실행 합 니 다.만약 우리 의 Activity 가 폐기 되 기 전에 AsyncTask 를 취소 하지 않 았 다 면, 이것 은 우리 의 AsyncTask 를 붕괴 시 킬 수 있 습 니 다 (crash).처리 하고 자 하 는 view 가 존재 하지 않 기 때문이다.그래서 우 리 는 항상 행 사 를 소각 하기 전에 임 무 를 취소 하도록 확보 해 야 한다.한 마디 로 하면, 우 리 는 AsyncTask 를 사용 하려 면 AsyncTask 가 정확하게 취소 되 는 지 확인 해 야 한다.
       또한, 우리 가 cancle () 을 정확하게 호출 했다 고 해서 임 무 를 진정 으로 취소 할 수 있 는 것 은 아니다.doInBackgroud 에서 BitmapFactory. decodeStream () 과 같은 중단 할 수 없 는 동작 이 있 으 면 이 동작 은 계 속 될 것 이기 때문이다.
2. 메모리 유출
        AsyncTask 가 Activity 의 비정 상 내부 클래스 로 밝 혀 지면 AsyncTask 는 AsyncTask 를 만 든 Activity 에 대한 인용 을 보류 합 니 다.Activity 가 삭제 되 었 다 면 AsyncTask 의 배경 스 레 드 가 실행 되 고 있 습 니 다. 이 인용 을 메모리 에 계속 보관 하여 Activity 가 회수 되 지 못 하고 메모리 유출 을 일 으 킬 것 입 니 다.
3. 결국 분실
       화면 회전 이나 Activity 가 배경 에서 시스템 에 의 해 죽 임 을 당 하 는 경우 Activity 를 다시 만 들 수 있 습 니 다. 이전에 실 행 된 AsyncTask 는 이전 Activity 의 인용 을 가지 고 있 습 니 다. 이 인용 은 잘못 되 었 습 니 다. 이 때 onPost Execute () 를 호출 하여 인터페이스 를 업데이트 하면 더 이상 유효 하지 않 습 니 다.
4. 병렬 또는 직렬
      Android 1.6 이전 버 전에 서 는 AsyncTask 가 직렬 로 되 어 있 으 며 1.6 ~ 2.3 버 전에 서 병렬 로 바 뀌 었 습 니 다.2.3 이후 버 전이 수정 되 었 습 니 다. 병렬 와 직렬 을 지원 할 수 있 습 니 다. 직렬 로 실행 하려 면 execute () 방법 을 직접 실행 하고 병렬 로 실행 하려 면 execute OnExecutor (Executor) 를 실행 해 야 합 니 다.
------------------------------------------------------------------------------------------------------------------------------
현재 프로젝트 에 서 는 배경 인터페이스의 데 이 터 를 처리 하기 위해 대량의 비동기 작업 (AsyncTask) 을 사용 하고 있 습 니 다.때때로 네트워크 가 느 리 거나 장시간 네트워크 를 실행 할 때 (장시간 네트워크 에서 AsyncTask 를 사용 하 는 것 을 권장 하지 않 음) 사용 자 는 현재 Activity 로 돌아 갑 니 다. 그러나 doInBackground 방법 은 실행 되 고 있 습 니 다. 만약 에 우리 가 정적 내부 클래스 의 방식 으로 AsyncTask 를 만 들 지 않 는 다 면 이 task 는 activity 의 인용 을 계속 가지 고 있 기 때문에 메모리 유출 을 초래 할 수 있 습 니 다.또한 doInBackground 방법 이 실행 되 었 을 때 onPost Execute 를 호출 하여 UI 를 업데이트 할 때 이상 이 발생 할 수 있 습 니 다 (존재 하지 않 는 View 를 사 용 했 습 니 다).
따라서 task 를 정확하게 닫 고 activity 를 참조 하여 메모리 유출 을 방지 해 야 합 니 다.
작업 을 닫 는 방법:
AsyncTask 는 cancel 방법 을 제공 합 니 다. 그러나 cancel 만 실행 하면 작업 을 완전히 중단 할 수 없습니다. 특히 doInBackground 방법 에서 네트워크 작업 을 수행 하거나 스 레 드 가 sleep 순환 작업 을 수행 할 때 이 동작 을 중단 할 수 없습니다.그렇다면 cancle 은 무슨 소 용이 있 을 까?
다음 코드 를 살 펴 보 겠 습 니 다.
private AsyncTask task;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*            */
         task = new AsyncTask() {
            @Override
            protected Object doInBackground(Object[] params) {
                for(int i=0;i<10;i++){
                    Log.i("task","i="+i);
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(isCancelled()){
                        break;
                    }
                }
                return null;
            }

             @Override
             protected void onPostExecute(Object o) {
                 super.onPostExecute(o);
                 Log.i("task","     ");
             }

             @Override
             protected void onCancelled() {
                 super.onCancelled();
                 Log.i("task","     ");
             }
         };
        task.execute();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        task.cancel(true);
    }
저 는 activity 에서 간단하게 비동기 작업 을 만 들 었 습 니 다.
task.cancel(true);
설명 이 떨 어 지면 이 작업 을 어떻게 수행 해 야 하 는 지, 어떻게 실행 해 야 하 는 지, 리 턴 키 를 누 르 면 현재 activity 를 종료 한 후 이 순환 수 는 배경 에서 계속 실 행 됩 니 다. 실행 이 완료 되면 onPost Execute 방법 을 호출 합 니 다 (인쇄 결 과 를 볼 수 있 습 니 다)
삭제 하 다
task.cancel(true);
의 주석
if(isCancelled()){
                        break;
                    }
주석 을 달 아 라.종료 할 때 cancel 을 실 행 했 지만 doInBackground 의 순환 은 계속 실행 되 고 있 습 니 다. 그러나 실행 이 완료 되 었 을 때 onPost Execute 방법 을 사용 하지 않 고 onCanceled 방법 을 호출 했 습 니 다. (인쇄 결 과 를 볼 수 있 습 니 다)
설명 을 모두 취소 합 니 다. doInBackground 의 for 순환 체 에서 isCanceled 판단 을 했 습 니 다. 종료 할 때 task. cancel 방법 을 호출 할 때 이 조건 에 들 어 갑 니 다. 이 조건 을 통 해 순환 을 종료 하고 작업 을 끝 낼 수 있 으 며 마지막 으로 onCanceled 방법 을 호출 할 수 있 습 니 다.
이러한 장면 에 대해 우 리 는 task 의 cancel 방법 을 실행 하여 isCanceled 값 을 판단 하여 임 무 를 종료 할 수 있 으 며, activity 가 끝 날 때 임 무 를 끝 낼 수 있 습 니 다.그러나 다른 상황 (예 를 들 어 네트워크 를 조작 할 때) 에 비해 doInBackground 방법 은 끝 날 때 까지 계속 실 행 됩 니 다.그러나 적어도 저 희 는 cancel 방법 을 사 용 했 습 니 다. 최종 적 으로 onPost Execute 를 실행 하지 않 고 실행 합 니 다.
onCancelled
우 리 는 이 방법 에서 UI 를 조작 하지 않 을 것 이다.이렇게 하면 약간의 이상 한 발생 을 피 할 수 있다.
따라서 중단 할 수 없 는 작업 에 비해 작업 이 activity 를 가지 고 있 지 않도록 정적 내부 클래스 를 사용 하고 Weak Reference 를 사용 하여 activity 를 감 싸 서 UI 를 업데이트 하 는 목적 을 달성 할 수 있 습 니 다.
다음 코드:
static class MyTask extends AsyncTask{
        private WeakReference weakAty;
        public MyTask(Activity activity){
            weakAty = new WeakReference(activity);
        }

        @Override
        protected String doInBackground(String... params) {
            for(int i=0;i<10;i++){
                Log.i("Mytask","i="+i);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(isCancelled()){
                    break;
                }
            }
            return null;
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            Log.i("Mytask","     ");
            AsyncTaskActivity mActivity;
            if((mActivity= (AsyncTaskActivity) weakAty.get())!=null){
                mActivity.doSomething();
            }
        }

        @Override
        protected void onCancelled() {
            super.onCancelled();
            Log.i("Mytask","     ");
        }
    }

전체 코드 첨부:
public class AsyncTaskActivity extends Activity {
    private AsyncTask task;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*            */
         task = new AsyncTask() {
            @Override
            protected Object doInBackground(Object[] params) {
                for(int i=0;i<10;i++){
                    Log.i("task","i="+i);
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(isCancelled()){
                        break;
                    }
                }
                return null;
            }

             @Override
             protected void onPostExecute(Object o) {
                 super.onPostExecute(o);
                 Log.i("task","     ");
             }

             @Override
             protected void onCancelled() {
                 super.onCancelled();
                 Log.i("task","     ");
             }
         };
        task.execute();
        // log    ,  task    task      
        new MyTask(this).execute();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        task.cancel(true);
        //      MyTask        weakReference     
    }


    public void doSomething(){
        //   ,         activity      ,  weakReference               
        Log.i("AsyncActivity","      ,  UI");
    }


    static class MyTask extends AsyncTask{
        private WeakReference weakAty;
        public MyTask(Activity activity){
            weakAty = new WeakReference(activity);
        }

        @Override
        protected String doInBackground(String... params) {
            for(int i=0;i<100;i++){
                Log.i("Mytask","i="+i);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(isCancelled()){
                    break;
                }
            }
            return null;
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            Log.i("Mytask","     ");
            AsyncTaskActivity mActivity;
            if((mActivity= (AsyncTaskActivity) weakAty.get())!=null){
                mActivity.doSomething();
            }
        }

        @Override
        protected void onCancelled() {
            super.onCancelled();
            Log.i("Mytask","     ");
        }
    }
}

기록 은 자신 이 이해 하 는 것 을 정리 하기 위해 서 입 니 다. 잘못 이 있 으 면 지적 해 주세요!

좋은 웹페이지 즐겨찾기