SoFunction
Updated on 2025-03-11

Detailed explanation of the example of OkHttp3 in Android and the method of updating UI threads in child threads

okHttp is used for android http requests. It is said that it is very powerful, let’s try it together. However, there will be some small pits when using okHttp, and later we will talk about how to fall into the pit and crawl out.

First of all, we need to understand one thing. The UI thread and the main thread mentioned here are the same thing. It is the only thread that can update the UI. This is just a point that will be used when filling in pits for okHttp. Moreover, this content itself is often used in daily development and is worth learning.

okHttp initiates synchronization request

The first column is an example of a synchronous request.

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

  Request request = new ()
    .url("")
    .build();
  Call call = (request);
  Response response = ();
}

However, this method of directly calling a network request in the main thread of Android does not work, and it directly throws an exception to request the network by UI Thread. So we need to make some minor changes to cover up. Write the request into a synchronous request, but put it in a worker thread to do this asynchronously.

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

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

          Request request = new ()
              .url("")
              .build();
          Call call = (request);
          // 1
          Response response = ();

          if (!()) {
             = REQUEST_FAIL;
          } else {
             = REQUEST_SUCCESS;
          }
        } catch (IOException ex) {
           = REQUEST_FAIL;
        } finally {
          // send the message
          // 2
          ();
        }
      }
    };

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

So the synchronized requests are done in this way Response response = ();.

1. Newly initialize an OkHttpClient before initiating a synchronization request. Then there is a specific request, using the request builder to create this Request. We are here to make the url simple. Next, use the client initialized earlier to initiate a call: Call call = (request);. Finally execute this call: Response response = (); and get the requested response.

2. Don’t pay attention to this part for the time being. Because this example is just to show how okHttp initiates synchronization requests in a running way.

okHttp initiates an asynchronous request

Since Android itself does not support initiating synchronization requests, of course no one wants to initiate synchronization requests. Doing so can lead to serious user experience problems. Imagine if you have a waterfall flow, and then all the waterfall flows are displayed in the picture. Now users have to keep looking down at the pictures of the waterfall flow. If these pictures were requested synchronously, the system's ANR would have long since popped up when they could turn a page.

So let's explore how to initiate an asynchronous request.

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

    Request request = new ()
        .url("")
        .build();
    Call call = (request);
    // 1
    (new Callback() {
      // 2
      @Override
      public void onFailure(Call call, IOException e) {
        //(, (), Toast.LENGTH_SHORT).show();
        
        if (().getThread() == ()) {
          (TAG, "Main Thread");
        } else {
          (TAG, "Not Main Thread");
        }
      }

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

1. Use the execute method for synchronous requests, and use the (new Callback() method asynchronously.

2. This Callback interface provides two methods, one is onFailure and the other is onResponse. These two methods are called when the request fails and succeeds.

3. Everything seemed to be very simple. The network request is successful or failed and is updated directly on the interface. But I never thought that this would throw exceptions. Then I looked and found that the two methods onFailure and onResponse were not executed in the main thread. The printed log is: D/###okHttp: Not Main Thread.

So I have to think of other ways to update the view in the main thread. Updating the main thread in the worker thread will throw an exception. Generally speaking, there are several ways to update the view in the child thread.

Update UI thread in child thread

1. Activity's runOnUiThread method

There is such a method in Activity to runOnUiThread. This method requires a Runnable instance as a parameter.

  (new Runnable() {
    @Override
    public void run() {
      (TAG, "code: ");
      (, (()), Toast.LENGTH_SHORT).show();
    }
  });

2. View post method

The same is true for the post method of View, throw a Runnable instance in. Then it executes in the main thread. Toast definitely doesn't have this method.

(new Runnable() {
  public void run() {
    ("UI thread", "I am the UI thread");
  }
});

3. Others

1. Use Handler, this previous example of okHttp synchronization request can be used.

, There are two methods that can be executed in the main thread: onProgressUpdate and onPostExecute. We are not trying to update the progress here, so we are considering the latter method.

private class BackgroundTask extends AsyncTask<String, Void, Bitmap> {
  protected void onPostExecute(Bitmap result) {
    ("UI thread", "I am the UI thread");
  }
}

Based on the above, the Handler method and AsyncTask mentioned in the method of updating UI threads are both too heavy. Especially AsyncTask. You also need to inherit and implement a bunch of methods before you can achieve your goal. At the same time, it is also incompatible with the usage method of okHttp we want to use.

So we only consider the first two. But the two methods are actually different. Of course, this is not to say that the methods have different names. Let's take a look at the source code of Android, how these two methods are implemented.

  public final void runOnUiThread(Runnable action) {
    if (() != mUiThread) {
      (action);
    } else {
      ();
    }
  }
  // (action); implementation of post method  public final boolean post(Runnable r) {
    return sendMessageDelayed(getPostMessage(r), 0);
  }

The method runOnUiThread will finally call Handler's sendMessageDelayed. But here only 0 is delayed. That is, when the method is passed here, the runOnUiThread parameter will be executed immediately. The Runnable instance will be executed immediately.

Let’s take a look at the post method of View:

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

Generally, what is executed is ().post(action);. That is, the instance of Runnable is just added to the event queue and executed in order. It does not necessarily execute immediately.

We have discussed so much, and finally we use runOnUiThread to update the interface, which is the first method.

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

    if (().getThread() == ()) {
      (TAG, "Main Thread");
    } else {
      (TAG, "Not Main Thread");
    }

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

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

    (new Runnable() {
      @Override
      public void run() {
        (TAG, "code: ");
        (, (()), Toast.LENGTH_SHORT).show();
      }
    });
  }
});

Whether the request succeeds or fails, a Toast pops up. Use this toast to pop up in the UI thread.

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.