The network traffic generated by an app can have a significant impact on the
battery life of the device. To optimize that traffic, you need to measure it
and identify its source. Network requests can come directly from a user action,
from your own app code, or from a server communicating with your app.

This topic shows you how to monitor and categorize your network traffic, and
provides guidance on identifying and resolving issues.

## Use the Network Profiler to monitor requests

Use the [Network Profiler](https://developer.android.com/studio/profile/network-profiler) to track your
application's network requests. You can monitor how and when your app transfers
data and optimize the underlying code appropriately.

<br />

![](https://developer.android.com/static/studio/images/profile/network_profiler_thread_view-2X.png)   

**Figure 1.** Tracking network traffic. The network traffic pattern suggests
that efficiency could be dramatically improved by prefetching requests or
bundling uploads.

By monitoring the frequency of your data transfers and the amount of data
transferred during each connection, you can identify areas of your application
that can be made more battery-efficient. Generally, you will be looking for
short spikes that can be delayed.

To better identify the cause of transfer spikes, the Traffic Stats API enables
you to tag the data transfers occurring from a socket within a given thread
using
[`TrafficStats.setThreadStatsTag()`](https://developer.android.com/reference/android/net/TrafficStats#setThreadStatsTag(int)).
Calling this function doesn't automatically tag all traffic for a particular
thread; the tags have to be applied to the sockets.

Once the thread tag is set, you can manually tag and untag individual sockets
using
[`TrafficStats.tagSocket()`](https://developer.android.com/reference/android/net/TrafficStats#tagSocket(java.net.Socket))
and
[`TrafficStats.untagSocket()`](https://developer.android.com/reference/android/net/TrafficStats#untagSocket(java.net.Socket)).
A tag is also applied if a socket is opened on the thread, or if a server socket
accepts a connection.

Concurrent access to the same socket by multiple threads will use whatever tag
the socket had when the network packets were sent or received (which may be
different from when the user wrote or read the data, due to buffering and
retransmits).
| **Note:** This technique for tagging network traffic from your app depends on how the APIs that you are using access and manage network sockets. Some networking libraries may not allow the [`TrafficStats`](https://developer.android.com/reference/android/net/TrafficStats) utilities to tag traffic from your app.

For example, you can define constants to represent different types of network
traffic, as shown in the following code sample:  

### Kotlin

```kotlin
const val USER_INITIATED = 0x1000
const val APP_INITIATED = 0x2000
const val SERVER_INITIATED = 0x3000
```

### Java

```java
public static final int USER_INITIATED = 0x1000;
public static final int APP_INITIATED = 0x2000;
public static final int SERVER_INITIATED = 0x3000;
```

You can then tag your network requests accordingly:  

### Kotlin

```kotlin
TrafficStats.setThreadStatsTag(USER_INITIATED)
TrafficStats.tagSocket(outputSocket)
// Transfer data using socket
TrafficStats.untagSocket(outputSocket)
```

### Java

```java
TrafficStats.setThreadStatsTag(USER_INITIATED);
TrafficStats.tagSocket(outputSocket);
// Transfer data using socket
TrafficStats.untagSocket(outputSocket);
```

The [`HttpURLConnection`](https://developer.android.com/reference/java/net/HttpURLConnection)
library automatically tags sockets based on the current
[`TrafficStats.getThreadStatsTag()`](https://developer.android.com/reference/android/net/TrafficStats#getThreadStatsTag())
value. The library also tags and untags sockets when recycled through
keep-alive pools as shown in the following code sample:  

### Kotlin

```kotlin
class IdentifyTransferSpikeTask {
    @WorkerThread
    fun request(url: String) {
        TrafficStats.setThreadStatsTag(APP_INITIATED)
        // Make network request using HttpURLConnection.connect()
        ...
        TrafficStats.clearThreadStatsTag()
    }
}
```

### Java

```java
public class IdentifyTransferSpikeTask {
    @WorkerThread
    public void request(String url) {
        TrafficStats.setThreadStatsTag(APP_INITIATED);
        // Make network request using HttpURLConnection.connect()
        ...
        TrafficStats.clearThreadStatsTag();
    }
}
```
| **Note:** When running performance tests, your APK should be as close as possible to the production build. You may want to create a new debuggable build type, separate from the debug build type, in order to achieve this. For more information on creating build types, see [Configure build
| types](https://developer.android.com/studio/build/build-variants#build-types).

## Analyze network traffic types

When you look at the network traffic generated by your app, you need to
understand the source of the traffic so you can optimize it appropriately.
Frequent network activity generated by your app may be entirely appropriate
if it is responding to user actions, but completely inappropriate if your app
is not in the foreground or if the device is in a pocket or purse.

### Analyze user-initiated traffic

User-initiated network traffic may be efficiently grouped together while a user
is performing a specific task within your app, or spread out unevenly as the
user requests additional information your app needs to get. Your goal in
analyzing user-initiated network traffic is to look for patterns of frequent
network use over time and attempt to decrease their frequency by grouping
requests together.

The unpredictability of user requests makes it challenging to optimize this
type of network use in your app. In addition, users expect fast responses when
they are actively using an app, so delaying requests for efficiency can lead to
poor user experiences. In general, you should prioritize a quick response to
the user over efficient use of the network while a user is directly interacting
with your app.

For recommendations to optimize user-initiated traffic, see [Optimize
user-initiated
requests](https://developer.android.com/develop/connectivity/minimize-effect-regular-updates#user-initiated).
| **Caution:** Beware of network activity grouping bias in your user activity test data. If you ran a set of user scenarios with your network testing plan, the graph of user-initiated network access may be unrealistically grouped together, potentially causing you to optimize for user behavior that does not actually occur. Make sure your user network test scenarios reflect realistic use of your app.

### Analyze app-initiated traffic

App-initiated network traffic is typically an area where you can have a
significant impact on the efficient use of network bandwidth. In analyzing the
network activity of your app, look for periods of inactivity and determine if
they can be increased. If you see patterns of consistent network access from
your app, try to batch this traffic to allow the device radio to switch back
into low-power mode between periods of activity.

For recommendations to optimize app-initiated traffic, see [Optimize
app-initiated
requests](https://developer.android.com/develop/connectivity/minimize-effect-regular-updates#app-initiated).

### Analyze server-initiated traffic

Network activity initiated by servers communicating with your app is also
typically an area where you can have a significant impact on the efficient use
of network bandwidth. [Firebase Cloud Messaging
(FCM)](https://firebase.google.com/docs/cloud-messaging/) is a lightweight
mechanism used to transmit data from a server to a particular app instance.
Using FCM, your server can notify your app running on a particular device that
there is new data available for it.

For recommendations to optimize server-initiated traffic, see [Optimize
server-initiated
requests](https://developer.android.com/develop/connectivity/minimize-effect-regular-updates#server-initiated).

## Use Battery Historian to visualize network traffic effects

[Battery Historian](https://developer.android.com/topic/performance/power/battery-historian)
is a tool that visualizes a device's battery consumption over a period of time.
You can use this tool to analyze how your network activity affects battery
consumption. For example, Battery Historian can show you whether your app is
using the cellular radio more frequently than you expect. For more information
about using the Battery Historian, see [Profile battery usage with Batterystats
and Battery Historian](https://developer.android.com/topic/performance/power/setup-battery-historian).