OkHttp

High-performance HTTP client for Java/Kotlin by Square, the Android development company. Built-in HTTP/2 support, connection pooling, GZIP compression, response caching, and automatic recovery from network failures. Optimized for Android and JVM platforms.

HTTP ClientAndroidJavaKotlinHigh PerformanceSync/Async

Library

OkHttp

Overview

OkHttp is developed as "a high-performance HTTP client for Android and Java" - an open-source library created by Square. It has established itself as the de facto industry standard for HTTP communication in Android applications, supporting both synchronous and asynchronous APIs. With built-in HTTP/2 support, automatic connection pooling, transparent GZIP compression, and response caching, it enables efficient network communication. Used as the underlying technology for major libraries like Retrofit and Picasso, it has become a core component of the Android ecosystem.

Details

OkHttp 2025 edition continues to evolve as the standard HTTP client for Android development, optimized for the latest HTTP specifications and Android platform. Supporting HTTP/1.1 and HTTP/2 completely, along with SPDY support, WebSocket functionality, and a customizable Interceptor system, it supports enterprise-level mobile application development. Through efficient connection management via ConnectionPool, automatic retry functionality, and detailed logging capabilities, it achieves both stability and performance. Integration with the Square ecosystem also enhances development efficiency in Android app network layers.

Key Features

  • Android Optimization: Design and optimization specifically tailored for the Android platform
  • Complete HTTP/2 Support: Multiplexing and efficient connection utilization
  • Connection Pooling: Automatic connection reuse and performance improvement
  • Interceptor System: Flexible customization of request and response processing
  • Transparent Caching: Automatic response caching and offline support
  • WebSocket Support: Built-in real-time communication functionality

Pros and Cons

Pros

  • De facto standard in Android development with extensive track record and reliability
  • High-speed communication and battery consumption optimization through HTTP/2 support
  • Robust network processing through connection pooling and automatic retry
  • Flexible customization through the Interceptor system
  • Excellent integration with Square ecosystem (Retrofit, Moshi, etc.)
  • Efficient debugging through detailed logging functionality

Cons

  • Android/Java platform exclusive with no cross-platform support
  • High learning cost and overhead for simple HTTP requests
  • Increased APK size making applications larger
  • Complex initial setup with many configuration options
  • Additional considerations needed for integration with Kotlin coroutines
  • Cannot be used in web environments (JavaScript)

Reference Pages

Code Examples

Installation and Basic Setup

// build.gradle (Module: app)
dependencies {
    // Latest version of OkHttp
    implementation 'com.squareup.okhttp3:okhttp:4.12.0'
    
    // Version with logging functionality (recommended for debugging)
    implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
    
    // WebSocket functionality (if needed)
    implementation 'com.squareup.okhttp3:okhttp-ws:4.12.0'
}
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Basic Requests (GET/POST/PUT/DELETE)

import okhttp3.*;
import java.io.IOException;

public class OkHttpExample {
    private final OkHttpClient client = new OkHttpClient();

    // Basic GET request (synchronous)
    public void basicGetRequest() throws IOException {
        Request request = new Request.Builder()
                .url("https://api.example.com/users")
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                String responseBody = response.body().string();
                System.out.println("Response: " + responseBody);
                
                // Get header information
                System.out.println("Content-Type: " + response.header("Content-Type"));
                System.out.println("Status Code: " + response.code());
            } else {
                System.out.println("Request failed: " + response.code());
            }
        }
    }

    // Asynchronous GET request
    public void asyncGetRequest() {
        Request request = new Request.Builder()
                .url("https://api.example.com/users")
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                System.out.println("Request failed: " + e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    String responseBody = response.body().string();
                    System.out.println("Async response: " + responseBody);
                } else {
                    System.out.println("Async request failed: " + response.code());
                }
                response.close();
            }
        });
    }

    // POST request with JSON
    public void postJsonRequest() throws IOException {
        String json = "{\"name\": \"John Doe\", \"email\": \"[email protected]\"}";
        
        RequestBody body = RequestBody.create(json, MediaType.parse("application/json"));
        Request request = new Request.Builder()
                .url("https://api.example.com/users")
                .post(body)
                .addHeader("Authorization", "Bearer your-token")
                .addHeader("Content-Type", "application/json")
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                String responseBody = response.body().string();
                System.out.println("Created user: " + responseBody);
            } else {
                System.out.println("POST failed: " + response.code());
            }
        }
    }

    // PUT request (update)
    public void putRequest() throws IOException {
        String json = "{\"name\": \"Jane Doe\", \"email\": \"[email protected]\"}";
        
        RequestBody body = RequestBody.create(json, MediaType.parse("application/json"));
        Request request = new Request.Builder()
                .url("https://api.example.com/users/123")
                .put(body)
                .addHeader("Authorization", "Bearer your-token")
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                System.out.println("User updated successfully");
            }
        }
    }

    // DELETE request
    public void deleteRequest() throws IOException {
        Request request = new Request.Builder()
                .url("https://api.example.com/users/123")
                .delete()
                .addHeader("Authorization", "Bearer your-token")
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (response.code() == 204) {
                System.out.println("User deleted successfully");
            }
        }
    }

    // Form data submission
    public void submitFormData() throws IOException {
        RequestBody formBody = new FormBody.Builder()
                .add("username", "testuser")
                .add("password", "secret123")
                .add("remember", "true")
                .build();

        Request request = new Request.Builder()
                .url("https://api.example.com/login")
                .post(formBody)
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                String responseBody = response.body().string();
                System.out.println("Login response: " + responseBody);
            }
        }
    }
}

Advanced Configuration and Customization (Headers, Authentication, Timeout, etc.)

import okhttp3.*;
import okhttp3.logging.HttpLoggingInterceptor;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class AdvancedOkHttpExample {
    
    // Custom OkHttpClient configuration
    public OkHttpClient createCustomClient() {
        // Logging interceptor setup
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        return new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)  // Connection timeout
                .readTimeout(60, TimeUnit.SECONDS)     // Read timeout
                .writeTimeout(60, TimeUnit.SECONDS)    // Write timeout
                .callTimeout(120, TimeUnit.SECONDS)    // Overall call timeout
                .retryOnConnectionFailure(true)        // Enable automatic retry
                .followRedirects(true)                 // Follow redirects
                .followSslRedirects(true)              // Follow SSL redirects
                .addInterceptor(loggingInterceptor)    // Add logging
                .addInterceptor(new AuthInterceptor()) // Custom authentication
                .connectionPool(new ConnectionPool(5, 10, TimeUnit.MINUTES)) // Connection pool
                .build();
    }

    // Custom authentication interceptor
    public static class AuthInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request originalRequest = chain.request();
            
            // Add authentication header to all requests
            Request authenticatedRequest = originalRequest.newBuilder()
                    .addHeader("Authorization", "Bearer " + getAuthToken())
                    .addHeader("User-Agent", "MyApp/1.0 (OkHttp)")
                    .addHeader("Accept", "application/json")
                    .build();

            return chain.proceed(authenticatedRequest);
        }
        
        private String getAuthToken() {
            // Get token from secure storage (SharedPreferences, Keystore, etc.)
            return "your-jwt-token";
        }
    }

    // Custom header configuration
    public void requestWithCustomHeaders() throws IOException {
        OkHttpClient client = createCustomClient();
        
        Request request = new Request.Builder()
                .url("https://api.example.com/protected")
                .addHeader("X-API-Version", "v2")
                .addHeader("X-Client-ID", "mobile-app")
                .addHeader("Accept-Language", "en-US,ja-JP")
                .addHeader("Cache-Control", "no-cache")
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                System.out.println("Protected resource: " + response.body().string());
            }
        }
    }

    // Cookie handling
    public void handleCookies() throws IOException {
        CookieJar cookieJar = new JavaNetCookieJar(java.net.CookieManager.getDefault());
        
        OkHttpClient client = new OkHttpClient.Builder()
                .cookieJar(cookieJar)
                .build();

        // First request (establishes cookies)
        Request loginRequest = new Request.Builder()
                .url("https://api.example.com/login")
                .post(RequestBody.create("{\"username\":\"user\",\"password\":\"pass\"}", 
                      MediaType.parse("application/json")))
                .build();

        try (Response loginResponse = client.newCall(loginRequest).execute()) {
            if (loginResponse.isSuccessful()) {
                System.out.println("Login successful");
                
                // Subsequent request (automatically includes cookies)
                Request protectedRequest = new Request.Builder()
                        .url("https://api.example.com/profile")
                        .build();

                try (Response profileResponse = client.newCall(protectedRequest).execute()) {
                    System.out.println("Profile: " + profileResponse.body().string());
                }
            }
        }
    }

    // HTTP/2 configuration
    public void http2Example() throws IOException {
        OkHttpClient client = new OkHttpClient.Builder()
                .protocols(Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1))
                .build();

        Request request = new Request.Builder()
                .url("https://api.example.com/http2-endpoint")
                .build();

        try (Response response = client.newCall(request).execute()) {
            System.out.println("Protocol: " + response.protocol());
            System.out.println("Response: " + response.body().string());
        }
    }

    // Proxy configuration
    public void proxyExample() throws IOException {
        Proxy proxy = new Proxy(Proxy.Type.HTTP, 
                               new InetSocketAddress("proxy.example.com", 8080));

        OkHttpClient client = new OkHttpClient.Builder()
                .proxy(proxy)
                .proxyAuthenticator(new Authenticator() {
                    @Override
                    public Request authenticate(Route route, Response response) throws IOException {
                        String credential = Credentials.basic("proxy-user", "proxy-pass");
                        return response.request().newBuilder()
                                .header("Proxy-Authorization", credential)
                                .build();
                    }
                })
                .build();

        Request request = new Request.Builder()
                .url("https://api.example.com/data")
                .build();

        try (Response response = client.newCall(request).execute()) {
            System.out.println("Via proxy: " + response.body().string());
        }
    }
}

Error Handling and Retry Functionality

import okhttp3.*;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

public class ErrorHandlingExample {
    private final OkHttpClient client;

    public ErrorHandlingExample() {
        this.client = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .addInterceptor(new RetryInterceptor(3)) // Custom retry interceptor
                .build();
    }

    // Comprehensive error handling
    public String safeRequest(String url) {
        Request request = new Request.Builder()
                .url(url)
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                handleHttpError(response);
                return null;
            }

            return response.body().string();

        } catch (SocketTimeoutException e) {
            System.err.println("Request timeout: " + e.getMessage());
            System.err.println("Please check your network connection or increase timeout");
        } catch (UnknownHostException e) {
            System.err.println("Host not found: " + e.getMessage());
            System.err.println("Please check the URL or your internet connection");
        } catch (IOException e) {
            System.err.println("Network error: " + e.getMessage());
            System.err.println("Please try again later");
        }

        return null;
    }

    private void handleHttpError(Response response) throws IOException {
        int statusCode = response.code();
        String errorBody = response.body() != null ? response.body().string() : "No error details";

        switch (statusCode) {
            case 400:
                System.err.println("Bad Request (400): Invalid request parameters");
                System.err.println("Error details: " + errorBody);
                break;
            case 401:
                System.err.println("Unauthorized (401): Authentication required");
                // Trigger token refresh or re-login
                refreshAuthToken();
                break;
            case 403:
                System.err.println("Forbidden (403): Access denied");
                System.err.println("Check your permissions");
                break;
            case 404:
                System.err.println("Not Found (404): Resource not found");
                break;
            case 429:
                String retryAfter = response.header("Retry-After");
                System.err.println("Rate Limited (429): Too many requests");
                if (retryAfter != null) {
                    System.err.println("Retry after: " + retryAfter + " seconds");
                }
                break;
            case 500:
                System.err.println("Internal Server Error (500): Server problem");
                break;
            case 502:
                System.err.println("Bad Gateway (502): Server temporarily unavailable");
                break;
            case 503:
                System.err.println("Service Unavailable (503): Server overloaded");
                break;
            default:
                System.err.println("HTTP Error " + statusCode + ": " + response.message());
                System.err.println("Error details: " + errorBody);
        }
    }

    // Custom retry interceptor
    public static class RetryInterceptor implements Interceptor {
        private final int maxRetries;

        public RetryInterceptor(int maxRetries) {
            this.maxRetries = maxRetries;
        }

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response = null;
            IOException exception = null;

            for (int attempt = 0; attempt <= maxRetries; attempt++) {
                try {
                    response = chain.proceed(request);
                    
                    // Retry on specific status codes
                    if (response.isSuccessful() || !shouldRetry(response.code())) {
                        return response;
                    }
                    
                    response.close();
                    
                    if (attempt < maxRetries) {
                        long delay = calculateDelay(attempt);
                        System.out.println("Retrying request in " + delay + "ms (attempt " + (attempt + 1) + ")");
                        Thread.sleep(delay);
                    }
                    
                } catch (IOException e) {
                    exception = e;
                    if (attempt < maxRetries) {
                        long delay = calculateDelay(attempt);
                        System.out.println("Network error, retrying in " + delay + "ms: " + e.getMessage());
                        try {
                            Thread.sleep(delay);
                        } catch (InterruptedException ie) {
                            Thread.currentThread().interrupt();
                            throw new IOException("Interrupted during retry delay", ie);
                        }
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new IOException("Interrupted during retry", e);
                }
            }

            if (response != null) {
                return response;
            } else {
                throw new IOException("Request failed after " + maxRetries + " retries", exception);
            }
        }

        private boolean shouldRetry(int statusCode) {
            return statusCode == 408 || // Request Timeout
                   statusCode == 429 || // Too Many Requests
                   statusCode == 500 || // Internal Server Error
                   statusCode == 502 || // Bad Gateway
                   statusCode == 503 || // Service Unavailable
                   statusCode == 504;   // Gateway Timeout
        }

        private long calculateDelay(int attempt) {
            // Exponential backoff: 1s, 2s, 4s, 8s...
            return Math.min(1000L * (1L << attempt), 10000L);
        }
    }

    // Asynchronous error handling
    public void asyncRequestWithErrorHandling(String url) {
        Request request = new Request.Builder()
                .url(url)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                if (call.isCanceled()) {
                    System.out.println("Request was cancelled");
                } else if (e instanceof SocketTimeoutException) {
                    System.err.println("Request timeout: " + e.getMessage());
                } else if (e instanceof UnknownHostException) {
                    System.err.println("Network unavailable: " + e.getMessage());
                } else {
                    System.err.println("Network error: " + e.getMessage());
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                try {
                    if (response.isSuccessful()) {
                        String responseBody = response.body().string();
                        System.out.println("Success: " + responseBody);
                    } else {
                        handleHttpError(response);
                    }
                } finally {
                    response.close();
                }
            }
        });
    }

    private void refreshAuthToken() {
        // Implement token refresh logic
        System.out.println("Refreshing authentication token...");
    }

    // Circuit breaker pattern implementation
    public static class CircuitBreaker {
        private int failureCount = 0;
        private long lastFailureTime = 0;
        private final int failureThreshold;
        private final long timeout;

        public CircuitBreaker(int failureThreshold, long timeoutMillis) {
            this.failureThreshold = failureThreshold;
            this.timeout = timeoutMillis;
        }

        public boolean allowRequest() {
            if (failureCount < failureThreshold) {
                return true;
            }

            return System.currentTimeMillis() - lastFailureTime >= timeout;
        }

        public void recordSuccess() {
            this.failureCount = 0;
        }

        public void recordFailure() {
            this.failureCount++;
            this.lastFailureTime = System.currentTimeMillis();
        }
    }
}

Concurrent Processing and Asynchronous Requests

import okhttp3.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class ConcurrentRequestsExample {
    private final OkHttpClient client;
    private final ExecutorService executor;

    public ConcurrentRequestsExample() {
        this.client = new OkHttpClient.Builder()
                .connectionPool(new ConnectionPool(10, 10, TimeUnit.MINUTES))
                .dispatcher(new Dispatcher(Executors.newFixedThreadPool(10)))
                .build();
        this.executor = Executors.newFixedThreadPool(20);
    }

    // Parallel request execution
    public List<String> fetchMultipleUrls(List<String> urls) throws InterruptedException {
        List<Future<String>> futures = new ArrayList<>();
        List<String> results = new ArrayList<>();

        // Submit all requests
        for (String url : urls) {
            Future<String> future = executor.submit(() -> {
                try {
                    Request request = new Request.Builder().url(url).build();
                    try (Response response = client.newCall(request).execute()) {
                        if (response.isSuccessful()) {
                            return response.body().string();
                        } else {
                            return "Error: " + response.code();
                        }
                    }
                } catch (IOException e) {
                    return "Exception: " + e.getMessage();
                }
            });
            futures.add(future);
        }

        // Collect results
        for (Future<String> future : futures) {
            try {
                String result = future.get(30, TimeUnit.SECONDS);
                results.add(result);
            } catch (ExecutionException | TimeoutException e) {
                results.add("Failed: " + e.getMessage());
            }
        }

        return results;
    }

    // Asynchronous parallel requests with callbacks
    public void fetchMultipleAsync(List<String> urls, ResponseCallback callback) {
        CountDownLatch latch = new CountDownLatch(urls.size());
        List<String> results = Collections.synchronizedList(new ArrayList<>());

        for (String url : urls) {
            Request request = new Request.Builder().url(url).build();
            
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    results.add("Failed: " + e.getMessage());
                    latch.countDown();
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    try {
                        if (response.isSuccessful()) {
                            results.add(response.body().string());
                        } else {
                            results.add("Error: " + response.code());
                        }
                    } finally {
                        response.close();
                        latch.countDown();
                    }
                }
            });
        }

        // Wait for all requests to complete in background thread
        executor.submit(() -> {
            try {
                latch.await(60, TimeUnit.SECONDS);
                callback.onComplete(results);
            } catch (InterruptedException e) {
                callback.onError(e);
            }
        });
    }

    // Pagination with concurrent processing
    public List<String> fetchAllPages(String baseUrl, int maxPages) throws InterruptedException {
        List<Future<String>> futures = new ArrayList<>();
        
        for (int page = 1; page <= maxPages; page++) {
            final int currentPage = page;
            Future<String> future = executor.submit(() -> {
                try {
                    String url = baseUrl + "?page=" + currentPage + "&limit=20";
                    Request request = new Request.Builder().url(url).build();
                    
                    try (Response response = client.newCall(request).execute()) {
                        if (response.isSuccessful()) {
                            String responseBody = response.body().string();
                            System.out.println("Page " + currentPage + " completed");
                            return responseBody;
                        } else {
                            return null;
                        }
                    }
                } catch (IOException e) {
                    System.err.println("Page " + currentPage + " failed: " + e.getMessage());
                    return null;
                }
            });
            futures.add(future);
        }

        List<String> allData = new ArrayList<>();
        for (Future<String> future : futures) {
            try {
                String pageData = future.get(30, TimeUnit.SECONDS);
                if (pageData != null) {
                    allData.add(pageData);
                }
            } catch (ExecutionException | TimeoutException e) {
                System.err.println("Page fetch failed: " + e.getMessage());
            }
        }

        return allData;
    }

    // Rate limiting with semaphore
    public void fetchWithRateLimit(List<String> urls, int maxConcurrent) {
        Semaphore semaphore = new Semaphore(maxConcurrent);
        CountDownLatch latch = new CountDownLatch(urls.size());

        for (String url : urls) {
            executor.submit(() -> {
                try {
                    semaphore.acquire(); // Wait for permit
                    
                    Request request = new Request.Builder().url(url).build();
                    client.newCall(request).enqueue(new Callback() {
                        @Override
                        public void onFailure(Call call, IOException e) {
                            System.err.println("Request failed: " + e.getMessage());
                            semaphore.release();
                            latch.countDown();
                        }

                        @Override
                        public void onResponse(Call call, Response response) throws IOException {
                            try {
                                if (response.isSuccessful()) {
                                    String body = response.body().string();
                                    System.out.println("Response received: " + body.length() + " chars");
                                }
                            } finally {
                                response.close();
                                semaphore.release();
                                latch.countDown();
                            }
                        }
                    });
                    
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    latch.countDown();
                }
            });
        }

        try {
            latch.await(120, TimeUnit.SECONDS);
            System.out.println("All requests completed");
        } catch (InterruptedException e) {
            System.err.println("Interrupted while waiting for completion");
        }
    }

    // Streaming download with progress
    public void downloadLargeFile(String url, String filename) throws IOException {
        Request request = new Request.Builder().url(url).build();
        
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Download failed: " + response.code());
            }

            long contentLength = response.body().contentLength();
            System.out.println("File size: " + contentLength + " bytes");

            try (InputStream inputStream = response.body().byteStream();
                 FileOutputStream outputStream = new FileOutputStream(filename)) {
                
                byte[] buffer = new byte[8192];
                long downloaded = 0;
                int bytesRead;

                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                    downloaded += bytesRead;

                    if (contentLength > 0) {
                        int progress = (int) ((downloaded * 100) / contentLength);
                        System.out.print("\rDownload progress: " + progress + "%");
                    }
                }
                
                System.out.println("\nDownload completed: " + filename);
            }
        }
    }

    public interface ResponseCallback {
        void onComplete(List<String> results);
        void onError(Exception error);
    }

    public void shutdown() {
        executor.shutdown();
        client.dispatcher().executorService().shutdown();
        client.connectionPool().evictAll();
    }
}

Framework Integration and Practical Examples

// Android integration with Retrofit
public interface ApiService {
    @GET("users/{id}")
    Call<User> getUser(@Path("id") int userId);
    
    @POST("users")
    Call<User> createUser(@Body CreateUserRequest request);
}

public class AndroidHttpExample {
    private final ApiService apiService;
    private final OkHttpClient okHttpClient;

    public AndroidHttpExample() {
        // Custom OkHttpClient for Retrofit
        this.okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(new AuthInterceptor())
                .addInterceptor(new LoggingInterceptor())
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .build();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.example.com/v1/")
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        this.apiService = retrofit.create(ApiService.class);
    }

    // Android-specific authentication interceptor
    public class AuthInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request originalRequest = chain.request();
            
            // Get token from Android SharedPreferences
            SharedPreferences prefs = context.getSharedPreferences("auth", Context.MODE_PRIVATE);
            String token = prefs.getString("access_token", null);
            
            if (token != null) {
                Request authenticatedRequest = originalRequest.newBuilder()
                        .addHeader("Authorization", "Bearer " + token)
                        .build();
                return chain.proceed(authenticatedRequest);
            }
            
            return chain.proceed(originalRequest);
        }
    }

    // File upload with progress (Android)
    public void uploadFileWithProgress(File file, ProgressCallback callback) {
        RequestBody fileBody = RequestBody.create(file, MediaType.parse("image/*"));
        
        // Progress tracking request body
        ProgressRequestBody progressRequestBody = new ProgressRequestBody(fileBody, callback);
        
        MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), progressRequestBody);
        
        Request request = new Request.Builder()
                .url("https://api.example.com/upload")
                .post(new MultipartBody.Builder()
                        .setType(MultipartBody.FORM)
                        .addPart(filePart)
                        .addFormDataPart("description", "Uploaded from Android")
                        .build())
                .build();

        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callback.onError(e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    callback.onSuccess(response.body().string());
                } else {
                    callback.onError(new IOException("Upload failed: " + response.code()));
                }
                response.close();
            }
        });
    }

    // Progress tracking RequestBody
    public static class ProgressRequestBody extends RequestBody {
        private final RequestBody delegate;
        private final ProgressCallback callback;

        public ProgressRequestBody(RequestBody delegate, ProgressCallback callback) {
            this.delegate = delegate;
            this.callback = callback;
        }

        @Override
        public MediaType contentType() {
            return delegate.contentType();
        }

        @Override
        public long contentLength() throws IOException {
            return delegate.contentLength();
        }

        @Override
        public void writeTo(BufferedSink sink) throws IOException {
            CountingSink countingSink = new CountingSink(sink);
            BufferedSink bufferedSink = Okio.buffer(countingSink);
            
            delegate.writeTo(bufferedSink);
            bufferedSink.flush();
        }

        private class CountingSink extends ForwardingSink {
            private long bytesWritten = 0;

            public CountingSink(Sink delegate) {
                super(delegate);
            }

            @Override
            public void write(Buffer source, long byteCount) throws IOException {
                super.write(source, byteCount);
                bytesWritten += byteCount;
                
                if (callback != null) {
                    callback.onProgress(bytesWritten, contentLength());
                }
            }
        }
    }

    public interface ProgressCallback {
        void onProgress(long bytesWritten, long contentLength);
        void onSuccess(String response);
        void onError(Exception error);
    }

    // WebSocket implementation
    public void establishWebSocketConnection() {
        Request request = new Request.Builder()
                .url("wss://api.example.com/websocket")
                .build();

        WebSocketListener listener = new WebSocketListener() {
            @Override
            public void onOpen(WebSocket webSocket, Response response) {
                System.out.println("WebSocket connected");
                webSocket.send("Hello, Server!");
            }

            @Override
            public void onMessage(WebSocket webSocket, String text) {
                System.out.println("Received: " + text);
                // Handle incoming message
            }

            @Override
            public void onFailure(WebSocket webSocket, Throwable t, Response response) {
                System.err.println("WebSocket error: " + t.getMessage());
            }

            @Override
            public void onClosing(WebSocket webSocket, int code, String reason) {
                webSocket.close(1000, null);
                System.out.println("WebSocket closing: " + reason);
            }
        };

        WebSocket webSocket = okHttpClient.newWebSocket(request, listener);
    }

    // Certificate pinning for enhanced security
    public OkHttpClient createSecureClient() {
        CertificatePinner certificatePinner = new CertificatePinner.Builder()
                .add("api.example.com", "sha256/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=")
                .build();

        return new OkHttpClient.Builder()
                .certificatePinner(certificatePinner)
                .build();
    }
}