[Android]임의의 시간 에 하위 스 레 드 에서 주 스 레 드 로 전환 합 니 다.

17404 단어 Android
=========================================================================================================================================================http://blog.csdn.net/qiujuer/article/details/41599383========================================================
끌어들이다
안 드 로 이 드 개발 에 서 는 네트워크 요청,데이터베이스 데이터 준비 등 시간 이 걸 리 는 작업 이 자주 발생 합 니 다.이 작업 들 은 메 인 스 레 드 에서 진행 할 수 없습니다.메 인 스 레 드 를 막 아 프로그램 이 응답 하지 않 기 때문이다.
그래서 다른 키 스 레 드 에서 만 시간 이 걸 리 는 작업 을 하고 완성 한 후에 화면 에 표시 할 수 있 습 니 다.알다 시 피 인터페이스 등 컨트롤 작업 은 메 인 스 레 드 에서 만 이 루어 집 니 다.그래서 불가피 하 게 하위 스 레 드 에서 주 스 레 드 로 전환 해 야 합 니 다.
방법.
이런 경우 Android 에서 흔히 볼 수 있 는 것 은 AsynTask 클래스 를 사용 하거나... Handler 가 스 레 드 전환 하기;그 중에서 AsynTask 는 공식 적 으로 포 장 된 유형 으로 비교적 간단 하고 효율 도 비교적 좋 지만 모든 상황 에 적합 하지 않다.적어도 나 는 한두 번 사용 한 후에 다 시 는 사용 하지 않 았 다.쓰다 Handler 는 가장 만능 적 인 방식 이 라 고 할 수 있 는데 그 원 리 는 메시지 순환 이다.메 인 스 레 드 에 Handler 변 수 를 만 들 때 Handler 메시지 순환 을 시작 하고 메시지 대기 열 에 있 는 작업 을 하나씩 처리 하 는 것 이다.하지만 까다 로 울 때 도 있다.그 까다 로 운 점 은 번 거 로 움 이다.
매번 하 나 를 만들어 야 돼 요. Handler 클래스,그리고 voidhandleMessage(Messagemsg)를 사용 합 니 다. 방법 은 정 보 를 꺼 내 서 인터페이스 조작 을 하 는데 그 중에서 매개 변수의 전달 등 문제 에 부 딪 혀 서 말하자면 정말 번거롭다.
생각.
이렇게 많은 문제 가 있 지만 또 그 장점 이 있 는데,우 리 는 왜 스스로 한 번 포장 하지 않 습 니까?
여기 서 나 는 생각 을 정리 했다.
4.567917.역시 사용 Handler 스 레 드 전환4.567917.서브 스 레 드 에서 간단 한 호출 을 통 해 메 인 스 레 드 로 전환 하여 작업 을 할 수 있 습 니 다4.567917.서브 스 레 드 가 메 인 스 레 드 로 전환 할 때 서브 스 레 드 는 메 인 스 레 드 가 실 행 될 때 까지 차단 에 들 어 갑 니 다(왜 이런 수요 가 있 는 지 아 세 요?)
4.567917.반드시 그 효율 을 확보 해 야 한다.
4.567917.메 인 스 레 드 의 집행 은 시간 제한 이 있어 야 하고 너무 오래 실행 하면 메 인 스 레 드 가 막 히 지 않 습 니 다내 가 생각 할 수 있 는 것 은 바로 이것 이다.시청자 여러분 어때요?더 필요 하 십 니까?
한다 면 한다,실현 방법 을 정리 하 다
Handler 사용 실현,그렇다면 주 된 방법 은 당연히 상속 Handler 를 사용 하 는 것 이다. 실현
4.567917.간단 하면 서도 수시로 들 어 갈 수 있 는 방법 이 있어 야 한다.그러면 대외 적 으로 정태 적 인 방법 을 사용 하 는 것 이 좋 은 선택 이다효율 성 을 확보 하려 면 Handler 를 메시지 대기 열 이 너무 많 지만 수시로 호출 할 수 있다 는 것 을 만족 시 키 려 면 외부 로 Queue
4.567917.더욱 상황 이 막 히 거나 막 히 지 않 는 서브 스 레 드 두 가지 상황 이 있 으 면 두 개 를 사용한다. Queue 야,헤어져4.567917.메 인 스 레 드 에서 오래 실행 되 지 않도록 해 야 합 니 다.그러면 대기 열의 실행 에 시간 제한 이 있어 야 합 니 다.시간 변 수 를 추가 하 세 요
  • 물론 마지막 으로 고려 해 봤 습 니 다.간단 하 다 면 들 어 오 는 매개 변 수 는 Runnable 을 사용 하 는 것 이 시원 합 니 다
  • 모든 것 이 준비 되 었 는데,동풍 만 불 었 다.자,다음 코너 로 넘 어 갑 니 다.
    CodeTime
    우선 우 리 는 ToolKit 클래스 를 만 듭 니 다.
    public class ToolKit {
        /**
         * Asynchronously
         *
         * @param runnable Runnable Interface
         */
        public static void runOnMainThreadAsync(Runnable runnable) {
        }
    
        /**
         * Synchronously
         *
         * @param runnable Runnable Interface
         */
        public static void runOnMainThreadSync(Runnable runnable) {
        }
    }

    두 가지 대외 적 인 방법 은 쉽게 말 하면 이렇다.하지만 그 기능 이 실현 되 려 면 계승 핸들 러 를 사용 해 야 한다.
    클래스 Handler Poster 를 만 들 고 Handler 에서 계승 합 니 다:
    final class HandlerPoster extends Handler {
        private final int ASYNC = 0x1;
        private final int SYNC = 0x2;
        private final Queue asyncPool;
        private final Queue syncPool;
        private final int maxMillisInsideHandleMessage;
        private boolean asyncActive;
        private boolean syncActive;
    
        HandlerPoster(Looper looper, int maxMillisInsideHandleMessage) {
            super(looper);
            this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
            asyncPool = new LinkedList<>();
            syncPool = new LinkedList<>();
        }
    
        void dispose() {
            this.removeCallbacksAndMessages(null);
            this.asyncPool.clear();
            this.syncPool.clear();
        }
    
        void async(Runnable runnable) {
            synchronized (asyncPool) {
                asyncPool.offer(runnable);
                if (!asyncActive) {
                    asyncActive = true;
                    if (!sendMessage(obtainMessage(ASYNC))) {
                        throw new GeniusException("Could not send handler message");
                    }
                }
            }
        }
    
        void sync(SyncPost post) {
            synchronized (syncPool) {
                syncPool.offer(post);
                if (!syncActive) {
                    syncActive = true;
                    if (!sendMessage(obtainMessage(SYNC))) {
                        throw new GeniusException("Could not send handler message");
                    }
                }
            }
        }
    
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == ASYNC) {
                boolean rescheduled = false;
                try {
                    long started = SystemClock.uptimeMillis();
                    while (true) {
                        Runnable runnable = asyncPool.poll();
                        if (runnable == null) {
                            synchronized (asyncPool) {
                                // Check again, this time in synchronized
                                runnable = asyncPool.poll();
                                if (runnable == null) {
                                    asyncActive = false;
                                    return;
                                }
                            }
                        }
                        runnable.run();
                        long timeInMethod = SystemClock.uptimeMillis() - started;
                        if (timeInMethod >= maxMillisInsideHandleMessage) {
                            if (!sendMessage(obtainMessage(ASYNC))) {
                                throw new GeniusException("Could not send handler message");
                            }
                            rescheduled = true;
                            return;
                        }
                    }
                } finally {
                    asyncActive = rescheduled;
                }
            } else if (msg.what == SYNC) {
                boolean rescheduled = false;
                try {
                    long started = SystemClock.uptimeMillis();
                    while (true) {
                        SyncPost post = syncPool.poll();
                        if (post == null) {
                            synchronized (syncPool) {
                                // Check again, this time in synchronized
                                post = syncPool.poll();
                                if (post == null) {
                                    syncActive = false;
                                    return;
                                }
                            }
                        }
                        post.run();
                        long timeInMethod = SystemClock.uptimeMillis() - started;
                        if (timeInMethod >= maxMillisInsideHandleMessage) {
                            if (!sendMessage(obtainMessage(SYNC))) {
                                throw new GeniusException("Could not send handler message");
                            }
                            rescheduled = true;
                            return;
                        }
                    }
                } finally {
                    syncActive = rescheduled;
                }
            } else super.handleMessage(msg);
        }
    }

    다음은 제 가 시간 이 많이 걸 려 서 만 든 종 류 를 말씀 드 리 겠 습 니 다.
    클래스 의 변수 부분:
    두 개의 표지,두 개의 대기 열,두 개의 실행 상태,한 개의 시간 제한;잘 이해 하 시 죠?표 지 는 그 대기 열 을 처리 하기 위해 사용 합 니 다.대열 은 당연히 임 무 를 담 고 있 지.실행 상 태 는 메 시 지 를 반복 해서 보 내 는 것 을 피하 기 위해 메시지 대기 열 이 너무 많 습 니 다.시간 제한 은 이해 하 는 게 좋 을 거 야.
    다음은 방법 부분 을 말씀 드 리 겠 습 니 다.
    구조 함수 HandlerPoster(Looperlooper,int_maxMillisInsideHandleMessage):
    두 개의 매개 변 수 를 입력 합 니 다.각각 Looper 입 니 다.메 인 스 레 드 로 초기 화 하 는 데 사 용 됩 니 다.그 다음은 시간 제한 입 니 다.그리고 두 대기 열 을 초기 화 했 습 니 다.
    폐기 함수 voiddispose():처리 되 지 않 은 메 시 지 를 먼저 제거 한 다음 대기 열 을 비 웁 니 다.
    비동기 실행 방법 추가 voidasync(Runnable_runnable):
        void async(Runnable runnable) {
            synchronized (asyncPool) {
                asyncPool.offer(runnable);
                if (!asyncActive) {
                    asyncActive = true;
                    if (!sendMessage(obtainMessage(ASYNC))) {
                        throw new GeniusException("Could not send handler message");
                    }
                }
            }
        }

    진입 방법 을 볼 수 있 습 니 다.첫 번 째 일 은 동기 화 상태 에 들 어간 다음 에 asyncPool.offer(runnable)를 호출 하 는 것 입 니 다.작업 을 대기 열 에 기록 하 다.
    그 다음 에 현재 비동기 작업 수행 여 부 를 판단 합 니 다.그렇지 않 으 면 즉시 상 태 를 바 꾸 고 현재 Handler 에 메 시 지 를 보 냅 니 다.물론 표지 에 들 어 가 는 것 을 잊 지 마 세 요.
    물론 효율 적 인 메 시 지 를 위 한 구조 도 obtainMessage(ASYNC)방법 을 통 해 이 루어 집 니 다.새로운 Message 를 만 들 고 현재 대기 열 에 남 은 메 시 지 를 사용 하기 위해 서 입 니 다.
    동기 화 실행 방법 추가 voidsync(SyncPost_post):
        void sync(SyncPost post) {
            synchronized (syncPool) {
                syncPool.offer(post);
                if (!syncActive) {
                    syncActive = true;
                    if (!sendMessage(obtainMessage(SYNC))) {
                        throw new GeniusException("Could not send handler message");
                    }
                }
            }
        }

    여기 서 들 어 오 는 것 은 Runnable 이 아니 라 SyncPost 입 니 다.이 는 동기 화 를 위해 Runnable 을 한 번 패키지 한 클래스 입 니 다.소개
    마찬가지 로 동기 화,추가,판단,메 시 지 를 보 냅 니 다.
    퀘 스 트 수행 자@Overridevoid_handleMessage(Message_msg):
    이것 은 복사 한 Handler 의 메시지 처리 방법 입 니 다.현재 Handler 메시지 대기 열 에 메시지 가 있 을 때 순서대로 이 방법 을 호출 합 니 다.
    단계별 로 보면:
            if (msg.what == ASYNC) {
                boolean rescheduled = false;
                try {
                    long started = SystemClock.uptimeMillis();
                    while (true) {
                        Runnable runnable = asyncPool.poll();
                        if (runnable == null) {
                            synchronized (asyncPool) {
                                // Check again, this time in synchronized
                                runnable = asyncPool.poll();
                                if (runnable == null) {
                                    asyncActive = false;
                                    return;
                                }
                            }
                        }
                        runnable.run();
                        long timeInMethod = SystemClock.uptimeMillis() - started;
                        if (timeInMethod >= maxMillisInsideHandleMessage) {
                            if (!sendMessage(obtainMessage(ASYNC))) {
                                throw new GeniusException("Could not send handler message");
                            }
                            rescheduled = true;
                            return;
                        }
                    }
                } finally {
                    asyncActive = rescheduled;
                }
            }

    들 어가 면 우선 비동기 처리 소식 인지,그렇다면 이 자리 에 들어간다.
    들 어 와 서 저희 가 try 를 했 어 요.finally 변수 logstarted 는 시작 시간 을 표시 하 는 데 사 용 됩 니 다.
    한 작업 을 수행 한 후 한 번 판단 합 니 다.주 스 레 드 를 사용 할 때마다 시간 제한 을 초과 하면 대기 열 에 있 는 작업 이 수행 되 든 안 되 든 종료 하고 Handler 순환 대기 열 에 새로운 메 시 지 를 보 냅 니 다.
    while 부분 에서 우 리 는 대기 열 에서 임 무 를 꺼 내 폴 방법 을 사용 합 니 다.비어 있 는 지 여 부 를 판단 합 니 다.비어 있 는 대기 열 동기 화 블록 에 들 어가 면;그리고 다시 한 번 취하 여 다시 판단 한다.
    공교롭게도 동기 화 대기 열 에 들 어가 기 전에 새로운 작업 이 왔 다 면 두 번 째 로 얻 은 것 은 당연히 NULL 이 아니 라 계속 실 행 될 것 이다.반대로 비어 있다 면;현재 대기 열의 상 태 를 false 로 초기 화하 고 순환 을 동시에 뛰 어 넘 습 니 다.
    다음은 두 번 째 부분 을 살 펴 보 겠 습 니 다.
    else if (msg.what == SYNC) {
                boolean rescheduled = false;
                try {
                    long started = SystemClock.uptimeMillis();
                    while (true) {
                        SyncPost post = syncPool.poll();
                        if (post == null) {
                            synchronized (syncPool) {
                                // Check again, this time in synchronized
                                post = syncPool.poll();
                                if (post == null) {
                                    syncActive = false;
                                    return;
                                }
                            }
                        }
                        post.run();
                        long timeInMethod = SystemClock.uptimeMillis() - started;
                        if (timeInMethod >= maxMillisInsideHandleMessage) {
                            if (!sendMessage(obtainMessage(SYNC))) {
                                throw new GeniusException("Could not send handler message");
                            }
                            rescheduled = true;
                            return;
                        }
                    }
                } finally {
                    syncActive = rescheduled;
                }
            } else super.handleMessage(msg);

    우선 동기 화 작업 메시지 가 들 어 오 는 지 판단 합 니 다.그렇지 않 으 면 슈퍼 handleMessage(msg)만 호출 합 니 다.됐어.
    위의 처리 부분 에서 알 수 있 듯 이 그 처리 과정 은 첫 번 째 부분 과 완전히 같다 고 할 수 있다.
    서로 다른 대기 열 에서 서로 다른 종류의 SyncPost 를 꺼 내 서 실행 을 판단 하고 서로 다른 표지 의 메 시 지 를 보 내 는 것 에 불과 합 니 다.첫 부분 을 알 게 되면 이 부분 은 영양 이 없다 고 할 수 있다.
    여기 서 문제 가 있 습 니 다.방법 조작 절차 가 같은 이상 동기 화 와 비동기 화 는 어디서 구분 합 니까?
    여기 SyncPost 를 봐 야 겠 어 요.
    final class SyncPost {
        boolean end = false;
        Runnable runnable;
    
        SyncPost(Runnable runnable) {
            this.runnable = runnable;
        }
    
        public void run() {
            synchronized (this) {
                runnable.run();
                end = true;
                try {
                    this.notifyAll();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        public void waitRun() {
            if (!end) {
                synchronized (this) {
                    if (!end) {
                        try {
                            this.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    먼저 SyncPost 의 구조 함 수 를 보십시오.
    Runnable 인터페이스 로 들 어 가 는 거 아니 야?그 러 니까 Runnable 에 대한 간단 한 패키지.
    그 public 를 볼 수 있 습 니 다.void_run()방법:
    이 방법 에서 우 리 는 동기 블록 에 들 어간 후에 Runnable 인터페이스의 run 방법 을 호출 했다.동시에 실행 완료 후 상태 변 수 를 boolean 변경 하 였 습 니 다.end=true;
    그리고 this.notifyAll()을 호출 합 니 다.기다 리 는 부분 은 계속 할 수 있 습 니 다.물론 이런 상황 이 있 습 니 다.이 동기 블록 에 들 어 갈 때 하위 스 레 드 가 this.wait()에 실행 되 지 않 았 다 면;부분 은 요?그래서 우 리 는 이 를 위해 end 와 try 를 준비 했다.
    그리고 publicvoid_waitRun()방법:
    이 중에서 우 리 는 먼저 상 태 를 판단 합 니 다.만약 상태 가 이미 변 했다 면 하위 스 레 드 가 여기까지 실 행 했 을 때 메 인 스 레 드 와 void 를 실 행 했 음 을 증명 합 니 다.run()。
    그 러 니까 동기 블록 에 들 어가 서 기다 리 지 않 아 도 돼.그렇지 않 으 면 죽 을 때 까지 기다 릴 거 야?반대로 메 인 스 레 드 가 this.notifyAll()을 호출 할 때 까지 대기 합 니 다.
    격정 부분
    곧 완성 부분 에 들 어가 구성 이 완 선 됐 으 니 마지막 조립 을 해 야 한다.
    클래스 classToolKit 로 돌아 가기
    public class ToolKit {
        private static HandlerPoster mainPoster = null;
    
        private static HandlerPoster getMainPoster() {
            if (mainPoster == null) {
                synchronized (ToolKit.class) {
                    if (mainPoster == null) {
                        mainPoster = new HandlerPoster(Looper.getMainLooper(), 20);
                    }
                }
            }
            return mainPoster;
        }
    
        /**
         * Asynchronously
         * The child thread asynchronous run relative to the main thread,
         * not blocking the child thread
         *
         * @param runnable Runnable Interface
         */
        public static void runOnMainThreadAsync(Runnable runnable) {
            if (Looper.myLooper() == Looper.getMainLooper()) {
                runnable.run();
                return;
            }
            getMainPoster().async(runnable);
        }
    
        /**
         * Synchronously
         * The child thread relative thread synchronization operation,
         * blocking the child thread,
         * thread for the main thread to complete
         *
         * @param runnable Runnable Interface
         */
        public static void runOnMainThreadSync(Runnable runnable) {
            if (Looper.myLooper() == Looper.getMainLooper()) {
                runnable.run();
                return;
            }
            SyncPost poster = new SyncPost(runnable);
            getMainPoster().sync(poster);
            poster.waitRun();
        }
    
        public static void dispose() {
            if (mainPoster != null) {
                mainPoster.dispose();
                mainPoster = null;
            }
        }
    }

    정적 변수 중 하나 입 니 다.Handler Poster
    그리고 초기 화 부분 Handler PostergetMainPoster()는 다 중 스 레 드 동시 호출 상황 에 적응 하기 위해 동기 화 방식 으로 초기 화 합 니 다.물론 초기 화 할 때 저희 가 들 어 왔 죠.
    mainPoster=newHandlerPoster(Looper.getMainLooper(),20); 메 인 스 레 드 에서 실행 되 는 HandlerPoster 를 결정 하 는 동시에 메 인 스 레 드 의 단일 실행 시간 을 20 밀리초 로 지정 합 니 다.
    방법 voidrunOnMainThreadAsync(Runnable_runnable)중:
    우선 이 방법 을 호출 하 는 것 이 메 인 스 레 드 인지 아 닌 지 를 판단 합 니 다.그렇다면 대열 에서 무엇 을 수행 하 시 겠 습 니까?직접 집행 하 라 고?하위 스 레 드 라면 getMainPoster().async(runnable)를 호출 합 니 다.대기 열 에 추가 하여 실행 합 니 다.
    방법 voidrunOnMainThreadSync(Runnable_runnable)중:
        public static void runOnMainThreadSync(Runnable runnable) {
            if (Looper.myLooper() == Looper.getMainLooper()) {
                runnable.run();
                return;
            }
            SyncPost poster = new SyncPost(runnable);
            getMainPoster().sync(poster);
            poster.waitRun();
        }

    같은 스 레 드 판단 을 한 다음 에 패 키 징 을 한 다음 에 대기 열 에 던 져 서 실행 을 기다 리 고 이 방법 에서 poster.wait Run()을 호출 합 니 다.대기 하기;주 스 레 드 가 SyncPost 류 의 run 방법 을 실행 할 때 까지마지막 으로 당연히 소각 방법 을 남 겼 다.엄 마 는 쓰레기 를 남기 지 않 고 치 우 는 법 을 배 워 야 한다 고 말씀 하 셨 다.voiddispose()
    OK,완 성 했 습 니 다.
    // "Runnable"       "run()"   
    // "run()"        ,          
    //        ,                 
    ToolKit.runOnMainThreadSync(Runnable runnable);
    //        ,    
    ToolKit.runOnMainThreadAsync(Runnable runnable);

    대외 적 으로 는 이렇게 두 가지 방법 이 있 습 니 다.간단 하고 편리 합 니 다.모두 해 보 세 요.한 글자 시원 하 다!
    코드:코드 가 변경 되 어 이름 이 바 뀌 었 습 니 다.
    UIKit.java
    UIKitHandlerPoster.java
    UIKitSyncPost.java
    오픈 소스 항목:
    Genius-Android
    새로운 문장
    [Android]임의의 시간 에 하위 스 레 드 에서 주 스 레 드 로 전환 하 는 실현 원리 및 강화 판

    좋은 웹페이지 즐겨찾기