HandlerThread를 통해 네트워크 요청 성공률(스레드 간 통신) 보장

6700 단어
버그가 발생했습니다. 서버가 국내에 있기 때문에 외국 사용자가 사용할 때 네트워크 때문에 요청이 발송되었음에도 불구하고 서버가 업로드된 데이터를 받지 못했기 때문에 클라이언트가 요청을 성공적으로 발송했는지 확인해야 합니다.따라서 나의 사고방식은 실패한 요청을 수집하여 요청 실패 대기열에 추가하고 주기적인 시간 후에 대기열의 모든 실패 요청을 다시 요청하는 것이다. 성공하면 대기열에서 삭제하고 실패하면 다음 요청을 기다리는 것이다.
처음에 생각한 것은 Timer였지만 timer에 버그가 있다는 것을 알아냈다.
TimerTask에서 검사되지 않은 예외가 발생하면 Timer는 예측할 수 없는 행동을 합니다.Timer 스레드는 이상을 포착하지 않기 때문에 TimerTask에서 검사하지 않은 이상은 timer 스레드를 종료합니다.이 경우 Timer는 더 이상 라인 실행을 재개하지 않습니다.전체 Timer가 취소되었다고 잘못 생각했습니다.이 때, 이미 안배되었지만 아직 집행하지 않은 TimerTask는 영원히 집행하지 않을 것이며, 새로운 임무도 스케줄링할 수 없습니다.
그리고 자바에서 제공하는 네 가지 스레드 풀의 new ScheduledThreadPool을 생각해 보세요.
newCachedThreadPool은 캐시 가능한 스레드 탱크를 만듭니다. 만약 스레드 탱크의 길이가 처리 수요를 초과하면 빈 스레드를 유연하게 회수할 수 있고, 회수할 수 없으면 새 스레드를 만듭니다.newFixedThreadPool은 최대 병렬 수를 제어할 수 있는 장거리 스레드 탱크를 만듭니다. 초과된 스레드는 대기열에서 기다립니다.newScheduledThreadPool은 정시 및 주기적인 작업 수행을 지원하는 장거리 스레드 탱크를 만듭니다.newSingleThreadExecutor는 모든 작업이 지정된 순서(FIFO, LIFO, 우선순위)에 따라 실행될 수 있도록 유일한 작업 루트로만 작업을 수행합니다.
newScheduledThreadPool
정시 및 주기적인 작업 수행을 지원하는 장거리 스레드 탱크를 만듭니다.지연 실행 예제 코드는 다음과 같습니다.
// , ,int   
// 。 ,   
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);  
scheduledThreadPool.schedule(new Runnable() {  
  
    @Override  
    public void run() {  
        System.out.println("delay 3 seconds");  
    }  
}, 3, TimeUnit.SECONDS);  
// 3 

정기적 실행 예제 코드는 다음과 같습니다.
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {  
  
    @Override  
    public void run() {  
        System.out.println("delay 1 seconds, and excute every 3 seconds");  
    }  
}, 1, 3, TimeUnit.SECONDS);  
// 1 3 

Scheduled Executor Service는 Timer보다 안전하고 기능이 강하며 자바 프로젝트에서 반나절 동안 테스트를 했는데 사용할 수 있을 것 같았지만 안드로이드 프로젝트에 도착하자마자 문제가 생겼습니다.요청의 실패 리셋에서 주기task를 실행하면 task가 효력을 잃고 Can't create handler inside thread that has not called Looper를 포착합니다.prepare () 예외
@Override
public void fail(Object result) {
    executorService.scheduleAtFixedRate(new Runnable() {
       @Override
       public void run() {
            UpdateBusStatusTime updateBusStatusTime = new UpdateBusStatusTime();
            // 
             GetHttpResultTool tool = new GetHttpResultTool(updateBusStatusTime);
             tool.setCallback(new GetHttpResultTool.CallBack() {
                 @Override
                  public void success(Object result) {
                       throw new NullPointerException();
                   }

                  @Override
                  public void fail(Object result) {}
              });
              tool.setPost(true);
              tool.execute();
         }
   },5,5,TimeUnit.SECONDS);
}

okhttp의 접근 요청을 제거하면 모든 것이 정상입니다. okhttp의 냄비일 것입니다. 계속 바꿀 수 없습니다. 결국 HandlerThread를 찾았습니다.
HandlerThread
HandlerThread는 Thread에서 상속되기 때문에 본질은 Thread입니다.일반thread와의 차이점은 하나의 라인을 구축했을 뿐만 아니라 메시지 대기열을 창설했다. 자신의 looper가 있기 때문에 우리는 자신의 라인에서 메시지를 나누어 주고 처리하며 이 Looper 대상의 get 방법을 대외적으로 제공할 수 있다.HandlerThread는 Looper를 가지고 있어서 메시지 대기열을 통해 현재 라인을 반복해서 사용할 수 있습니다.소모 작업이 이 순환 라인에 투입되었을 때, 라인은 소모 작업을 실행하고, 실행이 끝난 후에 순환 라인은 다음 새로운 소모 작업이 투입될 때까지 대기 상태에 있습니다.이렇게 하면 Thread 라인을 여러 번 만들어서 발생하는 성능 문제를 피할 수 있다.이것은 그의 장점이자 단점이다. 모든 임무는 대열의 방식으로 하나하나 실행될 것이다. 일단 대열에 어떤 임무가 너무 오래 실행되면 후속 임무가 지연되어 처리될 것이다.
HandlerThread의 일반적인 사용 방법
1. onCreate 메서드에서 초기화
protected void onCreate(Bundle savedInstanceState) {
   // HandlerThread 
   mCheckMsgThread= new HandlerThread("handler_thread");
   // HandlerThread 
   mCheckMsgThread.start();
   // Handler
   mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper(), mSubCallback);
   // 1 
   mCheckMsgHandler.sendEmptyMessageDelayed(1, 60 * 1000);
}

2. 순환 메시지 처리 메커니즘 구축
  private Handler.Callback mSubCallback = new Handler.Callback() {
        // , 
        @Override
        public boolean handleMessage(Message msg) {
            checkForUpdate();
            // 5 
            mCheckMsgHandler.sendEmptyMessageDelayed(1, 5 * 60 * 1000);
            return false;
        }
    };
   /**
    *  
    */
    private void checkForUpdate() {
        if (errorQueueMap != null && errorQueueMap.size() > 0) {
            for (final Map.Entry entry : errorQueueMap.entrySet()) {
                if (!entry.getValue()) {
                    // 
                    final GetHttpResultTool tool = new GetHttpResultTool(entry.getKey());
                    tool.setCallback(new GetHttpResultTool.CallBack() {
                        @Override
                        public void success(final Object result) {
                            Log.i("", " ,  " + result);
                            entry.setValue(true);
                            // , 
                            mUIHandler .sendEmptyMessage(2) ;
                        }
                        @Override
                        public void fail(Object result) {
                            Log.i("", " ,  " + result);
                        }
                    });
                }
            }
        }
    }

3. UI 스레드 구축 Handler 처리 메시지
    private Handler mUIHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            // handler , UI , 
        }
    };

4. 순환 Looper를 종료하는 것은 loop 방법을 호출하여 메시지 순환을 구동하는 것입니다. MessageQueue에서 메시지를 막힘없이 꺼내서 Handler로 하여금 이 메시지를 처리하게 하고 반복합니다. loop 방법은 사순환 방법입니다.따라서 onDestroy에서 리소스 방출을 종료해야 합니다.
mCheckMsgThread.quit() ;

원생 스레드 간 통신
간단히 말하자면, Handler를 버리고 원생 자바에서도 사실 라인 간 통신을 할 수 있는 방법이 있다.다만 방법이 우아하지 않거나 cpu 연산 부하가 너무 높거나 자물쇠가 끊어지는 상황을 초래할 수 있다.그리고 기술이 제대로 되지 않아 전복되는 경우가 많다.그래서 android 중의 Hander 통신 메커니즘은 이런 문제를 교묘하게 피하고 원생 방법을 참고하여 학습하도록 제공한다.
  • 공유 메모리 변수는 동기식 자물쇠를 사용합니다(사물쇠가 쉽게 사라집니다)
  • 공유 메모리 변수 판단 변수 상태(메모리 극히 소모)
  • 파이프 통신

  • 총결산
  • HandelrThread는 Looper를 가진 라인이기 때문에 하위 라인으로만 사용할 수 있기 때문에 네트워크 요청 작업을 순환적으로 수행할 수 있다
  • HandlerThread 처리 작업은 직렬로 실행되며 메시지 발송 순서에 따라 처리됩니다. 안의 네트워크 요청은 비동기적이며 충돌하지 않습니다..
  • mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper(), mSubCallback)라는 코드를 통해 mCheckMsgHandler는 HandlerThread 라인의 Looper를 획득하여 그들을 연결시켰다.이 코드가 mCheckMsgThread에 있는 이유.start() 후 실행은 start 후 run() 방법이 실행되기 때문에 Looper가 생성할 수 있습니다. mCheckMsgThread.getLooper()가 올바르게.
  • HandlerThread를 통해 하위 스레드를 연결하는 Handler와 UI 스레드의 Handler를 통해 스레드 간 통신을 실현..

  • 참고http://www.cnblogs.com/wufeng0927/p/5374191.html http://www.jianshu.com/p/69c826c8a87d http://blog.csdn.net/m0_37837382/article/details/70143224

    좋은 웹페이지 즐겨찾기