Android 에서 OkHttp 3 의 예 와 하위 스 레 드 에서 UI 스 레 드 를 업데이트 하 는 방법 을 자세히 알 아 봅 니 다.

9445 단어 okhttp업데이트 ui
okHttp 는 android 의 http 요청 에 사 용 됩 니 다.대단 하 다 고 하 니 우리 함께 맛 을 보 자.하지만 okHttp 를 사용 하면 작은 구덩이 가 있 고,뒤에 구덩이 에 빠 져 기어 나 오 는 방법 에 대해 이야기 합 니 다.
우선 좀 알 아야 합 니 다.여기 서 말 하 는 UI 스 레 드 와 메 인 스 레 드 는 같은 것 입 니 다.UI 를 업데이트 할 수 있 는 유일한 스 레 드 입 니 다.이 건 그냥 점 이에 요.그리고 이 내용 자 체 는 일상적인 개발 에 도 자주 사용 되 므 로 잘 배 워 볼 만하 다.
okHttp 동기 화 요청
첫 번 째 열 은 동기 화 요청 의 예 입 니 다.

private void performSyncHttpRequest() {
  OkHttpClient client = new OkHttpClient();

  Request request = new Request.Builder()
    .url("http://www.baidu.com")
    .build();
  Call call = client.newCall(request);
  Response response = call.execute();
}
그러나 이러한 안 드 로 이 드 의 메 인 스 레 드 에서 네트워크 요청 을 직접 호출 하 는 방법 은 통 하지 않 습 니 다.UI Thread 요청 네트워크 의 이상 을 직접 던 집 니 다.그래서 우 리 는 숨 길 수 있 도록 약간의 변경 을 해 야 한다.요청 을 동기 화 요청 방식 으로 쓰 지만 워 커 스 레 드 에 두 고 이 동작 을 수행 합 니 다.

  private Handler requestHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      switch (msg.what) {
        case REQUEST_SUCCESS:
          Toast.makeText(MainActivity.this, "SUCCESSFUL", Toast.LENGTH_SHORT).show();
          break;
        case REQUEST_FAIL:
          Toast.makeText(MainActivity.this, "request failed", Toast.LENGTH_SHORT).show();
          break;
        default:
          super.handleMessage(msg);
      }
    }
  };

  private void performSyncHttpRequest() {
    Runnable requestTask = new Runnable() {
      @Override
      public void run() {
        Message msg = requestHandler.obtainMessage();
        try {
          OkHttpClient client = new OkHttpClient();

          Request request = new Request.Builder()
              .url("http://www.baidu.com")
              .build();
          Call call = client.newCall(request);
          // 1
          Response response = call.execute();

          if (!response.isSuccessful()) {
            msg.what = REQUEST_FAIL;
          } else {
            msg.what = REQUEST_SUCCESS;
          }
        } catch (IOException ex) {
          msg.what = REQUEST_FAIL;
        } finally {
          // send the message
          // 2
          msg.sendToTarget();
        }
      }
    };

    Thread requestThread = new Thread(requestTask);
    requestThread.start();
  } 

그래서 동기 화 요청 은 모두 이렇게 합 니 다.Response response=call.execute().
1.동기 화 요청 을 시작 하기 전에 OkHttpClient 를 새로 초기 화 합 니 다.그리고 구체 적 인 요청 입 니 다.요청 builder 로 이 Request 를 만 듭 니 다.저희 가 여기 서 간단 한 url 을 위해 서 는 바로*입 니 다.http://www.baidu.com*됐어 요.다음은 앞에서 초기 화 된 client 로 call:Call call=client.newCall(request)를 시작 합 니 다.마지막 으로 이 call:Response response=call.execute()를 실행 합 니 다.요청 한 response 를 받 습 니 다.
2.이 부분 은 당분간 관심 을 갖 지 않 아 도 된다.이 예 는 okHttp 가 동기 화 요청 을 하 는 방법 을 실행 하 는 방식 으로 보 여주 기 위 한 것 이기 때문이다.
okHttp 비동기 요청
안 드 로 이 드 자체 가 동기 화 요청 을 지원 하지 않 는 이상 동기 화 요청 을 할 사람 도 없습니다.이렇게 하면 심각 한 사용자 체험 문 제 를 초래 할 수 있다.만약 당신 이 폭포 류 를 가지 고 있다 면 폭포 류 에 모두 그림 이 표 시 될 것 이 라 고 상상 해 보 세 요.현재 사용 자 는 폭포 흐름 의 그림 을 끊임없이 내 려 다 보아 야 한다.이 그림 들 이 모두 동기 화 요청 을 한다 면 언제 한 페이지 를 넘 길 수 있 는 지 시스템 의 ANR 은 이미 튀 어 나 왔 다.
그래서 우 리 는 어떻게 비동기 적 인 요 구 를 하 는 지 탐구 해 보 자.

  private void performAsyncHttpRequest() {
    OkHttpClient client = new OkHttpClient();

    Request request = new Request.Builder()
        .url("http://www.baidu.com")
        .build();
    Call call = client.newCall(request);
    // 1
    call.enqueue(new Callback() {
      // 2
      @Override
      public void onFailure(Call call, IOException e) {
        //Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
        
        if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
          Log.d(TAG, "Main Thread");
        } else {
          Log.d(TAG, "Not Main Thread");
        }
      }

      @Override
      public void onResponse(Call call, final Response response) throws IOException {
        // 3
        if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
          Log.d(TAG, "Main Thread");
        } else {
          Log.d(TAG, "Not Main Thread");
        }
      }
    });
  }  

1.동기 화 요청 은 execute 방법 을 사용 하고,비동기 화 는 call.enqueue(new Callback()방법 을 사용 합 니 다.
2.이 Callback 인 터 페 이 스 는 두 가지 방법 을 제공 합 니 다.하 나 는 onFailure 이 고 하 나 는 onResponse 입 니 다.이 두 가지 방법 은 요청 이 실 패 했 을 때 와 성공 할 때 각각 호출 된다.
3.원래 모든 것 이 쉬 울 것 같 았 다.네트워크 요청 이 성공 하거나 실 패 했 습 니 다.인터페이스 에서 직접 업 데 이 트 했 습 니 다.하지만 나 무 는 이렇게 하면 이상 하 게 던 질 줄 알 았 다.그리고 보 니 onFailure 와 onResponse 두 가지 방법 이 메 인 스 레 드 에서 실행 되 는 것 이 아니 었 습 니 다.인쇄 된 log 는 okhttp.demo.com.okhttpdemo D/\#\#okHttp:Not Main Thread 입 니 다.
그래서 메 인 스 레 드 에서 view 를 업데이트 하려 면 다른 방법 을 생각해 야 합 니 다.워 커 스 레 드 에서 메 인 스 레 드 를 업데이트 하면 이상 합 니 다.일반적으로 하위 스 레 드 에서 view 를 업데이트 하 는 몇 가지 방법 이 있 습 니 다.
하위 스 레 드 에서 UI 스 레 드 업데이트
1.Activity 의 runOnUiThread 방법
Activity 에 서 는 runOnUiThread 라 는 방법 이 있 습 니 다.이 방법 은 Runnable 인 스 턴 스 를 매개 변수 로 해 야 합 니 다.

  MainActivity.this.runOnUiThread(new Runnable() {
    @Override
    public void run() {
      Log.d(TAG, "code: ");
      Toast.makeText(MainActivity.this, String.valueOf(response.code()), Toast.LENGTH_SHORT).show();
    }
  });

2.View 의 post 방법
View 의 post 방법 도 마찬가지 입 니 다.Runnable 의 인 스 턴 스 를 던 져 넣 습 니 다.그리고 메 인 스 레 드 에서 실 행 했 습 니 다.Toast 는 그 럴 방법 이 없 을 거 야.

MainActivity.this.mView.post(new Runnable() {
  public void run() {
    Log.d("UI thread", "I am the UI thread");
  }
});
기타
1.Handler 를 사용 합 니 다.이 앞의 okHttp 동기 화 요청 의 예 를 사용 할 수 있 습 니 다.
2.AsyncTask,메 인 스 레 드 에서 실행 할 수 있 는 두 가지 방법 이 있 습 니 다:onProgressUpdate 와 onPost Execute.여기 서 우 리 는 진 도 를 갱신 하려 는 것 이 아니 기 때문에 다음 방법 을 고려 하 는 것 이다.

private class BackgroundTask extends AsyncTask<String, Void, Bitmap> {
  protected void onPostExecute(Bitmap result) {
    Log.d("UI thread", "I am the UI thread");
  }
}
이상 을 종합해 보면 UI 스 레 드 를 업데이트 하 는 방법 에서 마지막 으로 말 한 Handler 방법 과 AsyncTask 가 너무 무겁다.특히 AsyncTask.한 무더기 의 방법 을 계승 해 야 목적 을 달성 할 수 있 고 우리 가 사용 해 야 할 okHttp 의 사용 방법 과 호 환 되 지 않 는 부분 이 많다.
그래서 우 리 는 앞의 두 가지 만 생각한다.하지만 두 가지 방법 은 다르다.물론 방법의 이름 이 다르다 는 것 은 아니다.안 드 로 이 드 의 소스 코드 를 살 펴 보 자.이 두 가지 방법 이 어떻게 실현 되 었 는 지.

  public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
      mHandler.post(action);
    } else {
      action.run();
    }
  }
  // mHandler.post(action);  post     
  public final boolean post(Runnable r) {
    return sendMessageDelayed(getPostMessage(r), 0);
  }

방법 runOnUiThread 는 마지막 으로 Handler 의 sendmessageDelayed 를 호출 합 니 다.근 데 여 기 는 0 밖 에 안 됐어 요.즉,방법 이 여기에 전 달 될 때 runOnUiThread 의 인자 Runnable 인 스 턴 스 를 즉시 실행 합 니 다.
다음은 View 의 post 방법 을 살 펴 보 겠 습 니 다.

  public boolean post(Runnable action) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
      return attachInfo.mHandler.post(action);
    }
    // Assume that post will succeed later
    ViewRootImpl.getRunQueue().post(action);
    return true;
  }

보통 ViewRootImpl.getRunQueue().post(action)를 실행 합 니 다.즉,Runnable 의 인 스 턴 스 는 이벤트 대기 열 에 만 추가 되 어 순서대로 실 행 됩 니 다.반드시 즉각 집행 되 는 것 은 아니다.
우 리 는 그렇게 많은 것 을 연 구 했 는데 마지막 으로 runOnUi Thread 를 사용 하여 인터페이스 를 업데이트 하 는 것 이 바로 방법 이다.

call.enqueue(new Callback() {
  @Override
  public void onFailure(Call call, IOException e) {
    final String errorMMessage = e.getMessage();

    if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
      Log.d(TAG, "Main Thread");
    } else {
      Log.d(TAG, "Not Main Thread");
    }

    MainActivity.this.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        Toast.makeText(MainActivity.this, errorMMessage, Toast.LENGTH_SHORT).show();
      }
    });
  }

  @Override
  public void onResponse(Call call, final Response response) throws IOException {
    if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
      Log.d(TAG, "Main Thread");
    } else {
      Log.d(TAG, "Not Main Thread");
    }

    MainActivity.this.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        Log.d(TAG, "code: ");
        Toast.makeText(MainActivity.this, String.valueOf(response.code()), Toast.LENGTH_SHORT).show();
      }
    });
  }
});
요청 이 성공 하 든 실패 하 든 Toast 를 팝 업 합 니 다.UI 스 레 드 에서 이 Toast 를 MainActivity.this.runOnUiThread 로 팝 업 합 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기