Table of Contents
Understand Android network requests and main thread restrictions
Synchronize network requests using CountDownLatch
Notes and best practices
Summarize
Home Java javaTutorial Effective policy for synchronous waiting for OkHttpClient network requests in Android

Effective policy for synchronous waiting for OkHttpClient network requests in Android

Aug 30, 2025 am 09:27 AM

Effective policy for synchronous waiting for OkHttpClient network requests in Android

In Android application development, when you need to wait for the result of OkHttpClient asynchronous network request in the main thread, using enqueue() directly will cause the data to return if it is not filled, and execute() will throw NetworkOnMainThreadException. This article will introduce in detail how to use the java.util.concurrent.CountDownLatch mechanism to safely and effectively block in the background thread and wait for the network request to complete, thereby ensuring that the logic that depends on network data can be executed correctly.

Understand Android network requests and main thread restrictions

On the Android platform, all time-consuming operations (such as network requests, file I/O, etc.) are prohibited from being executed on the main thread (UI thread) to avoid ANR (Application Not Responding) errors, thereby improving the user experience. OkHttpClient provides two ways to perform network requests by default:

  1. enqueue(Callback): This is an asynchronous method that will put the request into the background thread pool for execution and will return immediately. The request result is asynchronously notified via the callback interface onResponse or onFailure.
  2. execute(): This is a synchronous method that blocks the current thread until the request is completed and returns the response.

When we need to initiate a network request in a child Activity and expect to return data to the parent Activity only after the request is completed, using enqueue() directly will cause the child Activity to return before the network request is completed, because enqueue() is non-blocking. Trying to call execute() in the main thread will immediately trigger android.os.NetworkOnMainThreadException.

Synchronize network requests using CountDownLatch

To solve the above problem, we can initiate asynchronous network requests in a background thread and use the java.util.concurrent.CountDownLatch mechanism to synchronize the waiting request completion. CountDownLatch is a synchronous helper class that allows one or more threads to wait until a set of operations performed in other threads completes.

How CountDownLatch works:

  • Set a counter during initialization (usually 1, which means waiting for an event).
  • When a thread that needs to wait calls the await() method, the thread will be blocked until the counter returns to zero.
  • When the waiting event occurs, the execution thread calls the countDown() method to decrement the counter by 1.
  • When the counter is reduced to 0, all threads calling await() will be released.

Implementation steps:

  1. Create CountDownLatch instance: In the logic of initiating network requests, create a CountDownLatch instance and initialize its counter to 1.
  2. Initiate an asynchronous network request: Use the enqueue() method of OkHttpClient to initiate a network request.
  3. Call countDown() in the callback: Whether the network request is successful (onResponse) or failed (onFailure), latch.countDown() is called at the end of the callback method to notify the waiting thread request has been completed.
  4. Call await() to wait: Call the latch.await() method in the main thread (or other threads that need to be waited). To prevent indefinite waiting, it is recommended to set a reasonable timeout time.

Sample code:

Suppose we have a SecondaryActivity which needs to fetch data from the REST API and close and return the result after the data is fetched.

 import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class SecondaryActivity extends AppCompatActivity {

    private String apiResponseData = null; // Used to store network request results @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_secondary); // Suppose there is a layout// Execute network request and wait logic in background thread new Thread(new Runnable() {
            @Override
            public void run() {
                performNetworkRequestAndWait();
                // After the network request is completed, you can process the data and close the Activity here
                // Note: UI operations still need to return to the main thread runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (apiResponseData != null) {
                            // Process the obtained data, such as updating the UI or setting the result System.out.println("Received data: " apiResponseData);
                            // Example: Set the result and close the Activity
                            // Intent resultIntent = new Intent();
                            // resultIntent.putExtra("data", apiResponseData);
                            // setResult(RESULT_OK, resultIntent);
                            // finish();
                        } else {
                            System.out.println("Failed to retrieve data.");
                            // setResult(RESULT_CANCELED);
                            // finish();
                        }
                    }
                });
            }
        }).start();
    }

    private void performNetworkRequestAndWait() {
        // Create a CountDownLatch with the counter 1
        CountDownLatch latch = new CountDownLatch(1);

        OkHttpClient client = new OkHttpClient();
        // Assume someRequest is a JSON string String someRequest = "{ \"key\": \"value\" }";
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), someRequest);
        String myURL = "https://api.example.com/data"; // Replace with your API address Request request = new Request.Builder().url(myURL).post(body).build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                System.err.println("Network request failed: " e.getMessage());
                apiResponseData = null; // The request failed, the data is empty latch.countDown(); // No matter whether it succeeds and fails, latch must be released
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if (response.isSuccessful() && response.body() != null) {
                    apiResponseData = response.body().string();
                    System.out.println("Network response: " apiResponseData);
                } else {
                    System.err.println("Network request unsuccessful: " response.code());
                    apiResponseData = null;
                }
                latch.countDown(); // No matter whether it succeeds or fails, latch must be released
            }
        });

        try {
            // Wait for the network request to complete, wait for up to 10 seconds// The await() method will block the current thread until latch.countDown() is called or timeout boolean completed = latch.await(10, TimeUnit.SECONDS);
            if (!completed) {
                System.err.println("Network request timed out.");
                apiResponseData = null; // Timeout, data is empty}
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // Reset the interrupt status System.err.println("Waiting for network request was interrupted: " e.getMessage());
            apiResponseData = null; // interrupt, data is empty}
        // Here, the apiResponseData variable will contain the result of the network request (if successful and timeout is not)
        // Or null (if failed, timed out or interrupted)
    }
}

Code parsing:

  1. CountDownLatch latch = new CountDownLatch(1);: Initialize a CountDownLatch with a counter of 1.
  2. client.newCall(request).enqueue(...): initiates an asynchronous network request.
  3. In the onFailure and onResponse callbacks, latch.countDown() is called regardless of the result of the request. This reduces the counter to 0, freeing all threads waiting on latch.await().
  4. latch.await(10, TimeUnit.SECONDS);: The thread calling this method (in this case the newly created background thread) will be blocked until latch.countDown() is called (i.e., the network request is completed) or the waiting time is more than 10 seconds.
  5. apiResponseData: After await(), the apiResponseData variable will contain the result of the network request, which can be processed here.

Notes and best practices

  • Thread management: Be sure to execute the await() method of CountDownLatch and the enqueue() method of OkHttpClient in the background thread. Calling await() in the main thread will still result in ANR. In this example, we create a new background thread through new Thread().start() to execute the entire synchronization wait logic.
  • UI update: Even if the await() method of CountDownLatch is done in the background thread, any operation that needs to update the UI still has to go back to the main thread to execute, for example through Activity.runOnUiThread() or Handler.
  • Timeout processing: latch.await(timeout, unit) is mandatory. If the network request is not responded for a long time, the lack of a timeout mechanism will cause the background thread to block indefinitely. Setting timeout reasonably can prevent resource leakage and potential ANR.
  • Error handling: It is crucial to call latch.countDown() in the onFailure callback to ensure that the waiting thread can be released even if the request fails. At the same time, handling InterruptedException is also a good practice.
  • Data delivery: After await(), the obtained data can be stored in the activity member variable for subsequent processing. If you need to pass data back to the parent Activity, you can use setResult() and finish().
  • Alternative: For more complex asynchronous scenarios, such as multiple parallel requests, request chains, etc., you can consider using more advanced concurrency frameworks such as Kotlin Coroutines (recommended), RxJava or AsyncTask (deprecated, not recommended for new projects). CountDownLatch is suitable for simple "waiting for a specific set of events or sets of syncs" scenarios.

Summarize

CountDownLatch provides a simple and effective mechanism for synchronously waiting for the results of OkHttpClient asynchronous network requests in Android background threads. By releasing the lock in the request callback and blocking and waiting in another thread, we can ensure that the logic that depends on network data is executed only after the data is available, while avoiding NetworkOnMainThreadException and ANR. Correctly combining thread management, timeouts and error handling, it is possible to build robust and responsive Android applications.

The above is the detailed content of Effective policy for synchronous waiting for OkHttpClient network requests in Android. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Comparing Java Frameworks: Spring Boot vs Quarkus vs Micronaut Comparing Java Frameworks: Spring Boot vs Quarkus vs Micronaut Aug 04, 2025 pm 12:48 PM

Pre-formanceTartuptimeMoryusage, Quarkusandmicronautleadduetocompile-Timeprocessingandgraalvsupport, Withquarkusoftenperforminglightbetterine ServerLess scenarios.2.Thyvelopecosyste,

What is a deadlock in Java and how can you prevent it? What is a deadlock in Java and how can you prevent it? Aug 23, 2025 pm 12:55 PM

AdeadlockinJavaoccurswhentwoormorethreadsareblockedforever,eachwaitingforaresourceheldbytheother,typicallyduetocircularwaitcausedbyinconsistentlockordering;thiscanbepreventedbybreakingoneofthefournecessaryconditions—mutualexclusion,holdandwait,nopree

How to join an array of strings in Java? How to join an array of strings in Java? Aug 04, 2025 pm 12:55 PM

Using String.join() (Java8) is the easiest recommended method for connecting string arrays, just specify the separator directly; 2. For old versions of Java or when more control is needed, you can use StringBuilder to manually traverse and splice; 3. StringJoiner is suitable for scenarios that require more flexible formats such as prefixes and suffixes; 4. Using Arrays.stream() combined with Collectors.joining() is suitable for filtering or converting the array before joining; To sum up, if Java8 and above is used, the String.join() method should be preferred in most cases, which is concise and easy to read, but for complex logic, it is recommended.

How to implement a simple TCP client in Java? How to implement a simple TCP client in Java? Aug 08, 2025 pm 03:56 PM

Importjava.ioandjava.net.SocketforI/Oandsocketcommunication.2.CreateaSocketobjecttoconnecttotheserverusinghostnameandport.3.UsePrintWritertosenddataviaoutputstreamandBufferedReadertoreadserverresponsesfrominputstream.4.Usetry-with-resourcestoautomati

How to compare two strings in Java? How to compare two strings in Java? Aug 04, 2025 am 11:03 AM

Use the .equals() method to compare string content, because == only compare object references rather than content; 1. Use .equals() to compare string values equally; 2. Use .equalsIgnoreCase() to compare case ignoring; 3. Use .compareTo() to compare strings in dictionary order, returning 0, negative or positive numbers; 4. Use .compareToIgnoreCase() to compare case ignoring; 5. Use Objects.equals() or safe call method to process null strings to avoid null pointer exceptions. In short, you should avoid using == for string content comparisons unless it is explicitly necessary to check whether the object is in phase.

How to send and receive messages over a WebSocket in Java How to send and receive messages over a WebSocket in Java Aug 16, 2025 am 10:36 AM

Create a WebSocket server endpoint to define the path using @ServerEndpoint, and handle connections, message reception, closing and errors through @OnOpen, @OnMessage, @OnClose and @OnError; 2. Ensure that javax.websocket-api dependencies are introduced during deployment and automatically registered by the container; 3. The Java client obtains WebSocketContainer through the ContainerProvider, calls connectToServer to connect to the server, and receives messages using @ClientEndpoint annotation class; 4. Use the Session getBasicRe

Correct posture for handling non-UTF-8 request encoding in Spring Boot application Correct posture for handling non-UTF-8 request encoding in Spring Boot application Aug 15, 2025 pm 12:30 PM

This article discusses the mechanism and common misunderstandings of Spring Boot applications for handling non-UTF-8 request encoding. The core lies in understanding the importance of the charset parameter in the HTTP Content-Type header, as well as the default character set processing flow of Spring Boot. By analyzing the garbled code caused by wrong testing methods, the article guides readers how to correctly simulate and test requests for different encodings, and explains that Spring Boot usually does not require complex configurations to achieve compatibility under the premise that the client correctly declares encoding.

Exploring Common Java Design Patterns with Examples Exploring Common Java Design Patterns with Examples Aug 17, 2025 am 11:54 AM

The Java design pattern is a reusable solution to common software design problems. 1. The Singleton mode ensures that there is only one instance of a class, which is suitable for database connection pooling or configuration management; 2. The Factory mode decouples object creation, and objects such as payment methods are generated through factory classes; 3. The Observer mode automatically notifies dependent objects, suitable for event-driven systems such as weather updates; 4. The dynamic switching algorithm of Strategy mode such as sorting strategies improves code flexibility. These patterns improve code maintainability and scalability but should avoid overuse.

See all articles