All Products
Search
Document Center

Managed Service for OpenTelemetry:Instrument an Android application with OpenTelemetry

Last Updated:Jun 21, 2026

After you instrument an application with OpenTelemetry and report trace data to Managed Service for OpenTelemetry, Managed Service for OpenTelemetry starts to monitor the application. You can view various monitoring data, such as application topology, traces, abnormal transactions, slow transactions, and SQL analysis. This topic describes how to instrument an Android application with OpenTelemetry and report data.

Prerequisites

Obtain an endpoint

New console

  1. Log on to the Managed Service for OpenTelemetry console. In the left-side navigation pane, click Integration Center.

  2. On the Integration Center page, click the OpenTelemetry card in the Open Source Frameworks section.

  3. In the OpenTelemetry panel, click the Start Integration tab, and then select a region in which you want to report data.

    Note

    When you access a region for the first time, resources are automatically initialized there.

  4. Configure the Connection Type and Export Protocol parameters and copy an endpoint.

    • Connection Type: If your service is deployed on Alibaba Cloud and resides in the region that you selected, we recommend that you set this parameter to Alibaba Cloud VPC Network. Otherwise, set this parameter to Public Network.

    • Export Protocol: Set this parameter to HTTP (recommended) or gRPC based on the protocol that is supported by the client.

    75.jpg

Old console

  1. Log on to the Managed Service for OpenTelemetry console.

  2. In the left-side navigation pane, click Cluster Configurations. On the page that appears, click the Access point information tab.

  3. In the top navigation bar, select a region in which you want to report data. In the Cluster Information section, turn on Show Token.

  4. Set the Client parameter to OpenTelemetry.

    In the Related Information column of the table, copy an endpoint.ot旧版中.jpg

    Note

    If your application is deployed in an Alibaba Cloud production environment, use a virtual private cloud (VPC) endpoint. Otherwise, use a public endpoint.

Sample application

This topic uses a sample application to show how to report trace data from an Android application with OpenTelemetry. The procedure applies to applications written in both Java and Kotlin.

Sample code repository: opentelemetry-android-demo

Step 1: Create and configure the application

  1. Create an application.

    1. In Android Studio, create a new application. Select the Basic Views Activity template and click Next.

    2. Select Java or Kotlin as the language, select API 24: Android 7.0 (Nougat) as the minimum SDK version, and then click Finish.

  2. Add dependencies.

    In the module-level or project-level build.gradle file, add the following dependencies.

    This example uses version 1.25.0 of the OpenTelemetry SDK for Java. For other versions, see Opentelemetry Java Releases. For the complete build.gradle file, see build.gradle.

    implementation platform('io.opentelemetry:opentelemetry-bom:1.25.0')
    implementation "io.opentelemetry:opentelemetry-api"
    implementation "io.opentelemetry:opentelemetry-context"
    implementation 'io.opentelemetry:opentelemetry-exporter-otlp'
    implementation 'io.opentelemetry:opentelemetry-exporter-logging'
    implementation 'io.opentelemetry:opentelemetry-extension-kotlin'
    implementation 'io.opentelemetry:opentelemetry-sdk'
    implementation 'io.opentelemetry:opentelemetry-semconv'
  3. Add network configuration.

    1. In the app/res/xml directory, create a file named network_security_config.xml and add the following content.

      <!-- For the complete file content, see https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/res/xml/network_security_config.xml -->
      <?xml version="1.0" encoding="utf-8"?>
      <network-security-config>
        <domain-config cleartextTrafficPermitted="true">
          <!-- Replace the following domain name with the endpoint you obtained in the Prerequisites section. Do not include "http://", the port number, or the URL path. -->
          <domain includeSubdomains="true">tracing-analysis-dc-hz.aliyuncs.com</domain>
        </domain-config>
      </network-security-config>
    2. Modify the app/src/main/AndroidManifest.xml file. Add the following two lines to grant the application network permission.

      <!-- For the complete file content, see https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/AndroidManifest.xml -->
      <?xml version="1.0" encoding="utf-8"?>
      <manifest ...>
        <!-- Add the following line to grant network permission. -->
        <uses-permission android:name="android.permission.INTERNET" />
        <application
          ...
          <!-- Add the following line to configure network settings for the domain to which you want to report data. -->
          android:networkSecurityConfig="@xml/network_security_config"
          ...>
          ...
        </application>
      </manifest>

Step 2: Initialize OpenTelemetry

  1. Create an OpenTelemetry utility class.

    In the same directory as MainActivity, create a file named OpenTelemetryUtil and add the following content.

    • Option 1: Report trace data using gRPC

      /**
       For the complete code, visit the following link:
       https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/OpenTelemetryUtil.java
      */
      Resource otelResource = Resource.getDefault().merge(
          Resource.create(
              Attributes.of(
                  // Replace <your-service-name> with your application name.
              	ResourceAttributes.SERVICE_NAME, "<your-service-name>",
                  // Replace <your-host-name> with your host name.
              	ResourceAttributes.HOST_NAME, "<your-host-name>"
              )
          )
      );
      SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
          .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // Optional: Prints trace data to the console. Comment out this line to disable this feature.
          // Replace <gRPC-endpoint> with the endpoint you obtained in the Prerequisites section and replace <gRPC-token> with your authentication token.
          .addSpanProcessor(BatchSpanProcessor.builder(
              OtlpGrpcSpanExporter.builder()
                   .setEndpoint("<gRPC-endpoint>") // Example: http://tracing-analysis-dc-hz.aliyuncs.com:8090
                   .addHeader("Authentication", "<gRPC-token>") // Example: xxxx@xxxx_xxxx@xxxx
                   .build()).build()
          )
          .setResource(otelResource)
          .build();
      OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
          .setTracerProvider(sdkTracerProvider)
          .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
          .buildAndRegisterGlobal();
      // Obtain a tracer to create spans.
      tracer = openTelemetry.getTracer("android-tracer", "1.0.0");
      /**
       For the complete code, visit the following link:
       https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/OpenTelemetryUtil.kt
      */
      val otelResource = Resource.getDefault().merge(
          Resource.create(
              Attributes.of(
                  ResourceAttributes.SERVICE_NAME, "<your-service-name>", // Replace <your-service-name> with your application name.
                  ResourceAttributes.HOST_NAME, "<your-host-name>"    // Replace <your-host-name> with your host name.
              )
          )
      )
      /* Report trace data over gRPC. */
      val sdkTracerProvider = SdkTracerProvider.builder()
          .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // Optional: Prints trace data to the console. Comment out this line to disable this feature.
      	// Replace <gRPC-endpoint> with the endpoint you obtained in the Prerequisites section and replace <gRPC-token> with your authentication token.
          .addSpanProcessor(
              BatchSpanProcessor.builder(
                  OtlpGrpcSpanExporter.builder()
                      .setEndpoint("<gRPC-endpoint>") // Example: http://tracing-analysis-dc-hz.aliyuncs.com:8090
                      .addHeader("Authentication", "<gRPC-token>") // Example: xxxx@xxxx_xxxx@xxxx
                      .build()
              ).build()
          )
          .setResource(otelResource)
          .build()
      val openTelemetry: OpenTelemetry = OpenTelemetrySdk.builder()
          .setTracerProvider(sdkTracerProvider)
          .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
          .buildAndRegisterGlobal()
      // Obtain a tracer to create spans.
      tracer = openTelemetry.getTracer("android-tracer", "1.0.0")
    • Option 2: Report trace data using HTTP

      /**
       For the complete code, visit the following link:
       https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/OpenTelemetryUtil.java
      */
      Resource otelResource = Resource.getDefault().merge(
          Resource.create(
              Attributes.of(
                  // Replace <your-service-name> with your application name.
                  ResourceAttributes.SERVICE_NAME, "<your-service-name>",
                  // Replace <your-host-name> with your host name.
                  ResourceAttributes.HOST_NAME, "<your-host-name>"
              )
          )
      );
      SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
          .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // Optional: Prints trace data to the console. Comment out this line to disable this feature.
          // Replace <HTTP-endpoint> with the endpoint you obtained in the Prerequisites section.
          .addSpanProcessor(BatchSpanProcessor.builder(
              OtlpHttpSpanExporter.builder()
                   .setEndpoint("<HTTP-endpoint>") // Example: http://tracing-analysis-dc-hz.aliyuncs.com/adapt_xxxx@xxxx_xxxx@xxxx/api/otlp/traces
                   .build()).build()
          )
          .setResource(otelResource)
          .build();
      OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
          .setTracerProvider(sdkTracerProvider)
          .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
          .buildAndRegisterGlobal();
      // Obtain a tracer to create spans.
      tracer = openTelemetry.getTracer("android-tracer", "1.0.0");
      /**
       For the complete code, visit the following link:
       https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/OpenTelemetryUtil.kt
      */
      val otelResource = Resource.getDefault().merge(
          Resource.create(
              Attributes.of(
                  ResourceAttributes.SERVICE_NAME, "<your-service-name>", // Replace <your-service-name> with your application name.
                  ResourceAttributes.HOST_NAME, "<your-host-name>"    // Replace <your-host-name> with your host name.
              )
          )
      )
      /* Report trace data over HTTP. */
      val sdkTracerProvider = SdkTracerProvider.builder()
          .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // Optional: Prints trace data to the console. Comment out this line to disable this feature.
      	// Replace <HTTP-endpoint> with the endpoint you obtained in the Prerequisites section.
          .addSpanProcessor(BatchSpanProcessor.builder(
              OtlpHttpSpanExporter.builder()
                  .setEndpoint("<HTTP-endpoint>") // Example: http://tracing-analysis-dc-hz.aliyuncs.com/adapt_xxxx@xxxx_xxxx@xxxx/api/otlp/traces
                  .build()).build()
                           )
          .setResource(otelResource)
          .build();
      val openTelemetry: OpenTelemetry = OpenTelemetrySdk.builder()
          .setTracerProvider(sdkTracerProvider)
          .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
          .buildAndRegisterGlobal()
      // Obtain a tracer to create spans.
      tracer = openTelemetry.getTracer("android-tracer", "1.0.0")
  2. Initialize OpenTelemetry when the application starts.

    In the onCreate method of MainActivity, call the OpenTelemetryUtil.init() method.

    /**
     For the complete code, visit the following link:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/MainActivity.java
    */
    ...
    public class MainActivity extends AppCompatActivity {
    	...
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // Add this line to initialize OpenTelemetry.
            OpenTelemetryUtil.init();
            ...
        }
        ...
    }
    /**
     For the complete code, visit the following link:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/MainActivity.kt
    */
    ...
    class MainActivity : AppCompatActivity() {
        ...
        override fun onCreate(savedInstanceState: Bundle?) {
            WindowCompat.setDecorFitsSystemWindows(window, false)
            super.onCreate(savedInstanceState)
            // Add this line to initialize OpenTelemetry.
            OpenTelemetryUtil.init()
                ...
        }
    }

Step 3: Create spans to trace data

  1. Create a span.

    In the FirstFragment file, create a span named First Fragment Button onClick in the button click handler.

    /**
     For the complete code, visit the following link:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java
    */
    public void onClick(View view) {
        // Get the tracer.
        Tracer tracer = OpenTelemetryUtil.getTracer();
    	// Create a span.
        Span span = tracer.spanBuilder("First Fragment Button onClick").startSpan();
    	try (Scope scope = span.makeCurrent()) {
            // Get the trace ID.
            System.out.println(span.getSpanContext().getTraceId());
            ...
        } finally {
            span.end();
        }
    }
    /**
     For the complete code, visit the following link:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt
    */
    binding.buttonFirst.setOnClickListener {
        // Get the tracer.
        val tracer: Tracer = OpenTelemetryUtil.getTracer()!!
        // Create a span.
        val span = tracer.spanBuilder("First Fragment Button onClick").startSpan()
        try {
            span.makeCurrent().use { scope ->
                // Get the trace ID.
                println(span.spanContext.traceId)
                // Get the span ID.
                println(span.spanContext.spanId)
                findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
            }
        } catch (t: Throwable) {
            span.setStatus(StatusCode.ERROR, "Something wrong in onClick")
            throw t
        } finally {
            span.end()
        }
    }
  2. Set attributes and events for the span.

    /**
     For the complete code, visit the following link:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java
    */
    // Set an attribute.
    span.setAttribute("key", "value");
    Attributes eventAttributes = Attributes.of(
        AttributeKey.stringKey("key"), "value",
        AttributeKey.longKey("result"), 0L);
    // Add an event.
    span.addEvent("onClick", eventAttributes);
    /**
     For the complete code, visit the following link:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt
    */
    // Set an attribute.
    span.setAttribute("key", "value")
    val eventAttributes =
        Attributes.of(
            AttributeKey.stringKey("key"), "value",
            AttributeKey.longKey("result"), 0L
        )
    // Add an event.
    span.addEvent("onClick", eventAttributes)
  3. Set the status for the span.

    /**
     For the complete code, visit the following link:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java
    */
    ...
    try (Scope scope = span.makeCurrent()) {
        ...
    } catch (Throwable t) {
        // Set the span status.
        span.setStatus(StatusCode.ERROR, "Something wrong in onClick");
        throw t;
    } finally {
        span.end(); 
    }
    /**
     For the complete code, visit the following link:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt
    */
    ...
    try {
        ...
    } catch (t: Throwable) {
        // Set the span status.
        span.setStatus(StatusCode.ERROR, "Something wrong in onClick")
        throw t
    } finally {
        span.end()
    }
  4. Create a nested span.

    /**
     For the complete code, visit the following link:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java
    */
    public void parentSpan() {
        // Get the tracer.
        Tracer tracer = OpenTelemetryUtil.getTracer();
        // Create a span.
        Span span = tracer.spanBuilder("Parent Span").startSpan();
        try (Scope scope = span.makeCurrent()) {
            // Get the trace ID.
            System.out.println(span.getSpanContext().getTraceId());
            // Get the span ID.
            System.out.println(span.getSpanContext().getSpanId());
            childSpan();
        } finally {
            span.end();
        }
    }
    public void childSpan() {
        // Get the tracer.
        Tracer tracer = OpenTelemetryUtil.getTracer();
        // Create a span.
        Span span = tracer.spanBuilder("Child Span").startSpan();
        try (Scope scope = span.makeCurrent()) {
            // Get the trace ID.
            System.out.println(span.getSpanContext().getTraceId());
            // Get the span ID.
            System.out.println(span.getSpanContext().getSpanId());
        } finally {
            span.end();
        }
    }
    /**
     For the complete code, visit the following link:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt
    */
    // Nested span
    fun parentSpan() {
        // Get the tracer.
        val tracer: Tracer = OpenTelemetryUtil.getTracer()!!
        // Create a span.
        val span = tracer.spanBuilder("Parent Span").startSpan()
        try {
            span.makeCurrent().use { scope ->
                // Get the trace ID.
                println(span.spanContext.traceId)
                // Get the span ID.
                println(span.spanContext.spanId)
                childSpan()
            }
        } finally {
            span.end()
        }
    }
    // Nested span
    fun childSpan() {
        // Get the tracer.
        val tracer: Tracer = OpenTelemetryUtil.getTracer()!!
        // Create a span.
        val span = tracer.spanBuilder("Child Span").startSpan()
        try {
            span.makeCurrent().use { scope ->
                // Get the trace ID.
                println(span.spanContext.traceId)
                // Get the span ID.
                println(span.spanContext.spanId)
            }
        } finally {
            span.end()
        }
    }

Step 4: Run the project and view trace data

  1. Run the project and tap the button on the demo application page. In the Running Devices panel of Android Studio, the emulator (for example, Pixel 3a API 33) successfully runs the AndroidJavaDemo application and displays the default First Fragment page.

    Check Logcat to view the span information exported by LoggingSpanExporter.

    System.out  I  0c8b92db3d8b038ea3eedd0ec25a4abb
    System.out  I  9ecd666297f5d8f6
    System.out  I  0c8b92db3d8b038ea3eedd0ec25a4abb
    System.out  I  7e7eaffe7bd23cb8
    System.out  I  0c8b92db3d8b038ea3eedd0ec25a4abb
    System.out  I  98ef17d962ecf4d1
    LoggingSpanExporter  I  'Child Span' : 0c8b92db3d8b038ea3eedd0ec25a4abb 98ef17d962ecf4d1 INTERNAL [tracer: android-tracer:1.0.0]
    LoggingSpanExporter  I  'Parent Span' : 0c8b92db3d8b038ea3eedd0ec25a4abb 7e7eaffe7bd23cb8 INTERNAL [tracer: android-tracer:1.0.0]
    LoggingSpanExporter  I  'First Fragment Button onClick' : 0c8b92db3d8b038ea3eedd0ec25a4abb 9ecd666297f5d8f6 INTERNAL [tracer: android-tracer:1.0.0]
    EGL_emulation  D  app_time_stats: avg=460.19ms min=2.23ms max=3653.05ms count=8
  2. On the Applications page of the Managed Service for OpenTelemetry console, click the name of the application. On the page that appears, view the trace data.

    The trace details page displays summary metrics (such as duration, number of applications, trace depth, and total number of spans) and a list of spans. The example includes a three-level span hierarchy: the root span First Fragment Button onClick (duration: 6.835 ms), the child span Parent Span (duration: 2.998 ms), and the grandchild span Child Span (duration: 0.14 ms). The application name for all spans is otel-android-demo. This shows the time breakdown and parent-child relationships.

Step 5: Connect client and server traces

  1. Modify the trace context propagation format in the headers.

    • Different protocols use different HTTP headers to pass the trace context to downstream services. For example, OpenTelemetry uses the W3C Trace Context format by default but also supports other formats. Zipkin uses the B3 or B3 Multi format. For more information about context propagation formats, see Specify the context propagation format for OpenTelemetry.

    • To connect client and server traces, configure the textPropagators on the client to match the protocol that the server uses:

      • If the server uses the default W3C Trace Context format of OpenTelemetry, you do not need to configure textPropagators on the client.

      • If the server uses the B3 or B3 Multi format of Zipkin, you must set textPropagators on the client to B3Propagator.

        // Set the B3 context propagation format.
        OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
                .setTracerProvider(sdkTracerProvider)
                .setPropagators(ContextPropagators.create(TextMapPropagator.composite(
                        B3Propagator.injectingMultiHeaders(),
                        B3Propagator.injectingSingleHeader())))
                .buildAndRegisterGlobal();
      • If the server uses the Jaeger protocol, you must set textPropagators on the client to JaegerPropagator.

        // Set the Jaeger context propagation format.
        OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
                .setTracerProvider(sdkTracerProvider)
                .setPropagators(ContextPropagators.create(TextMapPropagator.composite(
                        JaegerPropagator.getInstance())))
                .buildAndRegisterGlobal();
      • You can also set multiple trace context propagation formats.

        // Use W3C Trace Context, B3, and Jaeger as the trace context propagation formats.
        OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
                .setTracerProvider(sdkTracerProvider)
                .setPropagators(ContextPropagators.create(TextMapPropagator.composite(
                        W3CTraceContextPropagator.getInstance(),
                        B3Propagator.injectingMultiHeaders(),
                        B3Propagator.injectingSingleHeader(),
                        JaegerPropagator.getInstance())))
                .buildAndRegisterGlobal();
  2. Import okhttp3 and opentelemetry-okhttp.

    The opentelemetry-okhttp-3.0 plugin for OkHttp automatically instruments your application by intercepting all network requests sent through OkHttp3 and creating traces.

    • Add the following two dependencies to the build.gradle file.

      dependencies {
          ...
          implementation 'io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0:2.3.0-alpha'
          implementation 'com.squareup.okhttp3:okhttp:4.12.0'
      }
    • Create OkHttpConfiguration.

      import io.opentelemetry.api.OpenTelemetry;
      import io.opentelemetry.instrumentation.okhttp.v3_0.OkHttpTelemetry;
      import okhttp3.Call;
      import okhttp3.OkHttpClient;
      public class OkHttpConfiguration {
          //Use this Call.Factory implementation for making standard http client calls.
          public Call.Factory createTracedClient(OpenTelemetry openTelemetry) {
              return OkHttpTelemetry.builder(openTelemetry).build().newCallFactory(createClient());
          }
          //your configuration of the OkHttpClient goes here:
          private OkHttpClient createClient() {
              return new OkHttpClient.Builder().build();
          }
      }
  3. Use OkHttp3 to send a network request to the server.

    private void callHttpService() throws IOException {
        Tracer tracer = OpenTelemetryUtil.getTracer();
        // Create a span.
        Span span = tracer.spanBuilder("AsyncRequestZipkinServer").startSpan();
        System.out.println("AsyncRequestZipkinServer TraceID: " + span.getSpanContext().getTraceId());
        System.out.println("AsyncRequestZipkinServer SpanID: " + span.getSpanContext().getSpanId());
        try (Scope scope = span.makeCurrent()) {
            // Send a network request, for example, by using OkHttp.
            OkHttpConfiguration configuration = new OkHttpConfiguration();
            Call.Factory tracedClient = configuration.createTracedClient(GlobalOpenTelemetry.get());
            Request request = new Request.Builder().url("${ServerAddress}").get().build();
            Call call = tracedClient.newCall(request);
            try (Response response = call.execute()) {
                // Process the response.
                String responseBody = response.body().string();
                System.out.println(responseBody);
            } catch (IOException e) {
                // Handle the error.
                e.printStackTrace();
            }
        }  finally {
            span.end();
        }
    }

    Click to view the complete code for asynchronously calling the callHttpService method.

    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Looper;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import androidx.annotation.NonNull;
    import androidx.fragment.app.Fragment;
    import androidx.navigation.fragment.NavHostFragment;
    import com.example.androidjavademo.databinding.FragmentFirstBinding;
    import java.io.IOException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import io.opentelemetry.api.GlobalOpenTelemetry;
    import io.opentelemetry.api.common.AttributeKey;
    import io.opentelemetry.api.common.Attributes;
    import io.opentelemetry.api.trace.Span;
    import io.opentelemetry.api.trace.StatusCode;
    import io.opentelemetry.api.trace.Tracer;
    import io.opentelemetry.context.Scope;
    import okhttp3.Call;
    import okhttp3.Request;
    import okhttp3.Response;
    public class FirstFragment extends Fragment {
        private FragmentFirstBinding binding;
        @Override
        public View onCreateView(
                LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState
        ) {
            binding = FragmentFirstBinding.inflate(inflater, container, false);
            return binding.getRoot();
        }
        public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            binding.buttonFirst.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // Get the tracer.
                    Tracer tracer = OpenTelemetryUtil.getTracer();
                    // Create a span.
                    Span span = tracer.spanBuilder("First Fragment Button onClick").startSpan();
                    try (Scope scope = span.makeCurrent()) {
                        // Get the trace ID.
                        System.out.println(span.getSpanContext().getTraceId());
                        // Get the span ID.
                        System.out.println(span.getSpanContext().getSpanId());
                        // Set an attribute.
                        span.setAttribute("key", "value");
                        Attributes eventAttributes = Attributes.of(
                                AttributeKey.stringKey("key"), "value",
                                AttributeKey.longKey("result"), 0L);
                        // Add an event.
                        span.addEvent("onClick", eventAttributes);
                        parentSpan();
                        NavHostFragment.findNavController(FirstFragment.this)
                                .navigate(R.id.action_FirstFragment_to_SecondFragment);
                    } catch (Throwable t) {
                        span.setStatus(StatusCode.ERROR, "Something wrong in onClick");
                        throw t;
                    } finally {
                        span.end();
                    }
                }
            });
        }
        @Override
        public void onDestroyView() {
            super.onDestroyView();
            binding = null;
        }
        public void parentSpan() {
            ExecutorService executorService = Executors.newSingleThreadExecutor();
            Handler handler = new Handler(Looper.getMainLooper());
            // Get the tracer.
            Tracer tracer = OpenTelemetryUtil.getTracer();
            // Create a span.
            Span span = tracer.spanBuilder("Parent Span").startSpan();
            try (Scope scope = span.makeCurrent()) {
                // Get the trace ID.
                System.out.println(span.getSpanContext().getTraceId());
                // Get the span ID.
                System.out.println(span.getSpanContext().getSpanId());
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        // Send a network request.
                        try {
                            callHttpService();
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                        // After the execution is complete, switch to the main thread by using the handler to process the result.
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                // Update the UI or perform other tasks.
                                childSpan();
                            }
                        });
                    }
                });
                executorService.shutdown();
            } finally {
                span.end();
            }
        }
        public void childSpan() {
            // Get the tracer.
            Tracer tracer = OpenTelemetryUtil.getTracer();
            // Create a span.
            Span span = tracer.spanBuilder("Child Span").startSpan();
            try (Scope scope = span.makeCurrent()) {
                // Get the trace ID.
                System.out.println(span.getSpanContext().getTraceId());
                // Get the span ID.
                System.out.println(span.getSpanContext().getSpanId());
            } finally {
                span.end();
            }
        }
        private void callHttpService() throws IOException {
            Tracer tracer = OpenTelemetryUtil.getTracer();
            // Create a span.
            Span span = tracer.spanBuilder("AsyncRequestZipkinServer").startSpan();
            System.out.println("AsyncRequestZipkinServer TraceID: " + span.getSpanContext().getTraceId());
            System.out.println("AsyncRequestZipkinServer SpanID: " + span.getSpanContext().getSpanId());
            try (Scope scope = span.makeCurrent()) {
                // Send a network request, for example, by using OkHttp.
                OkHttpConfiguration configuration = new OkHttpConfiguration();
                Call.Factory tracedClient = configuration.createTracedClient(GlobalOpenTelemetry.get());
                Request request = new Request.Builder().url("${ServerAddress}").get().build();
                Call call = tracedClient.newCall(request);
                try (Response response = call.execute()) {
                    // Process the response.
                    String responseBody = response.body().string();
                    System.out.println(responseBody);
                } catch (IOException e) {
                    // Handle the error.
                    e.printStackTrace();
                }
            }  finally {
                span.end();
            }
        }
    }
  4. On the Trace Explorer page, view the end-to-end trace between the client and the server.

    AsyncRequestZipkinServer is the Android application and zipkin-demo-server is the server-side application.