Sample code for 30+ languages & platforms
Android™

HTTP Download in Parallel with Simultaneous Range Requests

See more HTTP Examples

Demonstrates how to download a large file with parallel simultaneous requests, where each request downloads a segment (range) of the remote file.

Chilkat Android™ Downloads

Android™
// Important: Don't forget to include the call to System.loadLibrary
// as shown at the bottom of this code sample.
package com.test;

import android.app.Activity;
import com.chilkatsoft.*;

import android.widget.TextView;
import android.os.Bundle;

public class SimpleActivity extends Activity {

  private static final String TAG = "Chilkat";

  // Called when the activity is first created.
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    boolean success = false;

    // This requires the Chilkat API to have been previously unlocked.
    // See Global Unlock Sample for sample code.

    CkHttp http = new CkHttp();

    // First get the size of the file to be downloaded.
    String url = "https://www.chilkatsoft.com/hamlet.xml";

    CkHttpResponse resp = new CkHttpResponse();
    success = http.HttpNoBody("HEAD",url,resp);
    if (success == false) {
        Log.i(TAG, http.lastErrorText());
        return;
        }

    int remoteFileSize = resp.get_ContentLength();

    Log.i(TAG, "Downloading " + String.valueOf(remoteFileSize) + " bytes...");

    // Let's download in 4 chunks.
    // (the last chunk will be whatever remains after the 1st 3 equal sized chunks)
    int chunkSize = remoteFileSize / 4;

    // The Range header is used to download a range from a resource
    // Range: bytes=<range-start>-<range-end>
    // or
    // Range: bytes=<range-start>-

    // We're writing code this way for clarity..
    CkHttp http1 = new CkHttp();
    CkHttp http2 = new CkHttp();
    CkHttp http3 = new CkHttp();
    CkHttp http4 = new CkHttp();

    CkStringBuilder sbRange = new CkStringBuilder();
    sbRange.SetString("bytes=<range-start>-<range-end>");
    int numReplaced = sbRange.ReplaceI("<range-start>",0);
    numReplaced = sbRange.ReplaceI("<range-end>",chunkSize - 1);
    Log.i(TAG, sbRange.getAsString());
    http1.SetRequestHeader("Range",sbRange.getAsString());

    sbRange.SetString("bytes=<range-start>-<range-end>");
    numReplaced = sbRange.ReplaceI("<range-start>",chunkSize);
    numReplaced = sbRange.ReplaceI("<range-end>",2 * chunkSize - 1);
    Log.i(TAG, sbRange.getAsString());
    http2.SetRequestHeader("Range",sbRange.getAsString());

    sbRange.SetString("bytes=<range-start>-<range-end>");
    numReplaced = sbRange.ReplaceI("<range-start>",2 * chunkSize);
    numReplaced = sbRange.ReplaceI("<range-end>",3 * chunkSize - 1);
    Log.i(TAG, sbRange.getAsString());
    http3.SetRequestHeader("Range",sbRange.getAsString());

    sbRange.SetString("bytes=<range-start>-");
    numReplaced = sbRange.ReplaceI("<range-start>",3 * chunkSize);
    Log.i(TAG, sbRange.getAsString());
    http4.SetRequestHeader("Range",sbRange.getAsString());

    // Start each range download
    CkTask task1 = http1.DownloadAsync(url,"qa_output/chunk1.dat");
    task1.Run();

    CkTask task2 = http2.DownloadAsync(url,"qa_output/chunk2.dat");
    task2.Run();

    CkTask task3 = http3.DownloadAsync(url,"qa_output/chunk3.dat");
    task3.Run();

    CkTask task4 = http4.DownloadAsync(url,"qa_output/chunk4.dat");
    task4.Run();

    // Wait for the downloads to complete.
    int numLive = 4;
    while (numLive > 0) {
        numLive = 0;
        if (task1.get_Live() == true) {
            numLive = numLive + 1;
            }

        if (task2.get_Live() == true) {
            numLive = numLive + 1;
            }

        if (task3.get_Live() == true) {
            numLive = numLive + 1;
            }

        if (task4.get_Live() == true) {
            numLive = numLive + 1;
            }

        if (numLive > 0) {
            // SleepMs is a convenience method to cause the caller to sleep for N millisec.
            // It does not cause the given task to sleep..
            task1.SleepMs(10);
            }

        }

    // All should be downloaded now..
    // Examine the result of each Download.
    int numErrors = 0;
    if (task1.GetResultBool() == false) {
        Log.i(TAG, task1.resultErrorText());
        numErrors = numErrors + 1;
        }

    if (task2.GetResultBool() == false) {
        Log.i(TAG, task2.resultErrorText());
        numErrors = numErrors + 1;
        }

    if (task3.GetResultBool() == false) {
        Log.i(TAG, task3.resultErrorText());
        numErrors = numErrors + 1;
        }

    if (task4.GetResultBool() == false) {
        Log.i(TAG, task4.resultErrorText());
        numErrors = numErrors + 1;
        }

    if (numErrors > 0) {

        return;
        }

    // All downloads were successful.
    // Compose the file from the parts.
    CkFileAccess fac = new CkFileAccess();
    success = fac.ReassembleFile("qa_output","chunk","dat","qa_output/hamlet.xml");
    if (success == false) {
        Log.i(TAG, fac.lastErrorText());
        }
    else {
        Log.i(TAG, "Success.");
        }

    // Let's download in the regular way, and then compare files..
    success = http.Download(url,"qa_output/hamletRegular.xml");

    // Compare files.
    boolean bSame = fac.FileContentsEqual("qa_output/hamlet.xml","qa_output/hamletRegular.xml");
    Log.i(TAG, "bSame = " + String.valueOf(bSame));

  }

  static {
      System.loadLibrary("chilkat");

      // Note: If the incorrect library name is passed to System.loadLibrary,
      // then you will see the following error message at application startup:
      //"The application <your-application-name> has stopped unexpectedly. Please try again."
  }
}