blob: e5b9e7b90507fefcae20ce3e50b48391c96cfcd1 [file] [log] [blame] [view]
## Classes [CL] <a name="classes"></a>
These are rules about classes, interfaces, and inheritance.
### Inherit new public classes from the appropriate base class <a name="classes-inheritance"></a>
Inheritance exposes API in your subclass which may not be appropriate. For
example, a new public subclass of `FrameLayout` will look like a `FrameLayout`
(plus the new functionality/API). If that inherited API is not appropriate for
your use case, inherit from something further up the tree (for example,
`ViewGroup` or even `View`, instead of `FrameLayout`).
If you are tempted to override methods from the base class to throw
`UnsupportedOperationException`, reconsider which base class you are using.
### Use the base collections classes <a name="classes-collections"></a>
Whether taking a collection as an argument or returning it as a value, always
prefer the base class over the specific implementation (e.g. return `List<Foo>`
rather than `ArrayList<Foo>`).
Use a base class that expresses appropriate constraints for the API. For
example, an API whose collection must be ordered should use `List` and an API
whose collection must consist of unique elements should use `Set`.
In Kotlin, prefer immutable collections. See
[Collection mutability](#methods-collections-mutability) for more details.
### Abstract classes versus interfaces <a name="classes-interfaces"></a>
Java 8 adds support for default interface methods, which allows API designers to
add methods to interfaces while maintaining binary compatibility. Platform code
and all Jetpack libraries should target Java 8 or later.
In cases where the default implementation is stateless, API designers *should*
prefer interfaces over abstract classes -- that is, default interface methods
can be implemented as calls to other interface methods.
In cases where a constructor or internal state is required by the default
implementation, abstract classes *must* be used.
In both cases, API designers may choose to leave a single method abstract to
simplify usage as a lambda.
```java {.good .no-copy}
public interface AnimationEndCallback {
// Always called, must be implemented.
public void onFinished(Animation anim);
// Optional callbacks.
public default void onStopped(Animation anim) { }
public default void onCanceled(Animation anim) { }
}
```
### Class names should reflect what they extend <a name="classes-subclass-naming"></a>
For example, classes which extend `Service` should be named `FooService` for
clarity.
```java {.bad .no-copy}
public class IntentHelper extends Service {}
```
```java {.good .no-copy}
public class IntentService extends Service {}
```
#### Generic suffixes (`Helper`, `Util`, etc.) <a name="classes-generic-naming"></a>
Avoid using generic class name suffixes like `Helper` and `Util` for collections
of utility methods. Instead, put the methods directly in the associated classes
or into Kotlin extension functions.
In cases where methods are bridging multiple classes, give the containing class
a meaningful name that explains what it does.
In *very* limited cases, using the `Helper` suffix may be appropriate:
- Used for composition of default behavior
- May involve delegation of existing behavior to new classes
- May require persisted state
- Typically involves `View`
For example, if backporting tooltips requires persisting state associated with a
`View` and calling several methods on the `View` to install the backport,
`TooltipHelper` would be an acceptable class name.
### Do not expose AIDL-generated code as public APIs directly <a name="classes-wrap-aidl"></a>
Keep AIDL-generated code as implementation details. Generated AIDL classes do
not meet the API style guide requirements (for example, they cannot use
overloading) and are not guaranteed to maintain language API compatibility, so
we can't embed them in a public API.
Instead, add a public API layer on top of the AIDL interface, even if it
initially is a shallow wrapper.
#### `Binder` interfaces <a name="classes-wrap-binder"></a>
If the `Binder` interface is an implementation detail, it can be changed freely
in the future, with the public layer allowing for the required backward
compatibility to be maintained. For example, you may find you need to add new
arguments to the internal calls, or optimize IPC traffic via batching/streaming,
using shared memory, or similar. None of these can currently be done if your
AIDL interface is also the public API.
For example, instead of exposing `FooService` as a public API directly:
```java {.bad .no-copy}
// BAD: Public API generated from IFooService.aidl
public class IFooService {
public void doFoo(String foo);
}
```
instead wrap the `Binder` interface inside a manager or other class:
```java {.good .no-copy}
/**
* @hide
*/
public class IFooService {
public void doFoo(String foo);
}
public IFooManager {
public void doFoo(String foo) {
mFooService.doFoo(foo);
}
}
```
and if later a new argument is needed for this call, the internal interface can
be kept simple and convenient overloads added to the public API. And the
wrapping layer can be used to handle other backwards-compatibility concerns as
the implementation evolves, as well:
```java {.good .no-copy}
/**
* @hide
*/
public class IFooService {
public void doFoo(String foo, int flags);
}
public IFooManager {
public void doFoo(String foo) {
if (mAppTargetSdkLevel < 26) {
useOldFooLogic(); // Apps targeting API before 26 are broken otherwise
mFooService.doFoo(foo, FLAG_THAT_ONE_WEIRD_HACK);
} else {
mFooService.doFoo(foo, 0);
}
}
public void doFoo(String foo, int flags) {
mFooService.doFoo(foo, flags);
}
}
```
For `Binder` interfaces that are not part of the Android platform (for example,
a service interface exported by Google Play Services for applications to use),
the requirement for a stable, published, and versioned IPC interface means that
it is much harder to evolve the interface itself. However, it is still
worthwhile to have a wrapper layer around it, to match other API guidelines and
to make it easier to use the same public API for a new version of the IPC
interface, if that ever becomes necessary.
#### Do not use raw `Binder` objects in public API <a name="classes-wrap-binder"></a>
A `Binder` object does not have any meaning on its own and thus should not be
used in public API. One common use-case is to use a `Binder` or `IBinder` as a
token because it has identity semantics. Instead of using a raw `Binder` object
use a wrapper token class instead.
```java {.bad .no-copy}
public final class IdentifiableObject {
public Binder getToken() {...}
}
```
```java {.good .no-copy}
public final class IdentifiableObjectToken {
/**
* @hide
*/
public Binder getRawValue() {...}
/**
* @hide
*/
public static IdentifiableObjectToken wrapToken(Binder rawValue) {...}
}
public final class IdentifiableObject {
public IdentifiableObjectToken getToken() {...}
}
```
### `Manager` classes must be `final`.
Manager classes should be declared as `final`. Manager classes talk to system
services and are the single point of interaction. There is no need for
customization so declare it as `final`.
### Do not use `CompletableFuture` or `Future` <a name="classes-avoid-future"></a>
`java.util.concurrent.CompletableFuture` has a large API surface that permits
arbitrary mutation of the future's value and has error-prone defaults
.
Conversely, `java.util.concurrent.Future` is missing non-blocking listening,
making it hard to use with asynchronous code.
In **platform code**, prefer a combination of a completion callback, `Executor`,
and if the API supports cancellation `CancellationSignal`.
```java {.good .no-copy}
public void asyncLoadFoo(android.os.CancellationSignal cancellationSignal,
Executor callbackExecutor,
android.os.OutcomeReceiver<FooResult, Throwable> callback);
```
In **libraries and apps**, prefer Guava's `ListenableFuture`.
```java {.good .no-copy}
public com.google.common.util.concurrent.ListenableFuture<Foo> asyncLoadFoo();
```
If you are **targeting Kotlin**, prefer `suspend` functions.
```kotlin {.good .no-copy}
suspend fun asyncLoadFoo(): Foo
```
### Do not use `Optional` <a name="classes-avoid-optional"></a>
While `Optional` can have advantages in some API surfaces, it is inconsistent
with the existing Android API surface area. `@Nullable` and `@NonNull` provide
tooling assistance for `null` safety and Kotlin enforces nullability contracts
at the compiler level, making `Optional` unnecessary.
For optional primitives, use paired `has` and `get` methods. If the value isn't
set (i.e., `has` returns `false`), the `get` method should throw an
`IllegalStateException`.
```java {.good .no-copy}
public boolean hasAzimuth() { ... }
public int getAzimuth() {
if (!hasAzimuth()) {
throw new IllegalStateException("azimuth is not set");
}
return azimuth;
}
```
### Use private constructors for non-instantiable classes <a name="classes-non-instantiable"></a>
Classes that can only be created by `Builder`s, classes containing only
constants or static methods, or otherwise non-instantiable classes should
include at least one private constructor to prevent instantiation via the
default no-arg constructor.
```java {.good .no-copy}
public final class Log {
// Not instantiable.
private Log() {}
}
```
### Singletons <a name="classes-singleton"></a>
Singleton are discouraged because they have the following testing-related
drawbacks:
1. Construction is managed by the class, preventing the use of fakes
1. Tests cannot be hermetic due to the static nature of a singleton
1. To work around these issues, developers either have to know the internal
details of the singleton or create a wrapper around it
Prefer the [single instance](#classes-single-instance) pattern, which relies on
an abstract base class to address these issues.
### Single instance {#classes-single-instance}
Single instance classes use an abstract base class with a `private` or
`internal` constructor and provide a static `getInstance()` method to obtain an
instance. The `getInstance()` method **must** return the same object on
subsequent calls.
The object returned by `getInstance()` should be a private implementation of the
abstract base class.
```kotlin {.bad .no-copy}
class Singleton private constructor(...) {
companion object {
private val _instance: Singleton by lazy { Singleton(...) }
fun getInstance(): Singleton {
return _instance
}
}
}
```
```kotlin {.good .no-copy}
abstract class SingleInstance private constructor(...) {
companion object {
private val _instance: SingleInstance by lazy { SingleInstanceImp(...) }
fun getInstance(): SingleInstance {
return _instance
}
}
}
```
Single instance differs from [singleton](#classes-singleton) in that developers
can create a fake version of `SingleInstance` and use their own Dependency
Injection framework to manage the implementation without having to create a
wrapper, or the library can provide its own fake in a `-testing` artifact.
### Classes that release resources should implement `AutoCloseable` <a name="classes-autocloseable"></a>
Classes that release resources through `close`, `release`, `destroy` or similar
methods should implement `java.lang.AutoCloseable` to allow developers to
automatically clean up these resources when using a `try-with-resources` block.
### Avoid introducing new View subclasses in android.* <a name="classes-no-new-framework-views"></a>
Do not introduce new classes that inherit directly or indirectly from
`android.view.View` in the platform public API (i.e. in `android.*`).
Android's UI toolkit is now [Compose-first](https://d.android.com/compose). New
UI functionality exposed by the platform should be exposed as lower-level APIs
that can be used to implement Jetpack Compose and optionally View-based UI
components for developers in [androidx](http://go/androidx) libraries. Offering
these components in androidx libraries affords opportunities for backported
implementations when platform functionality is not available.
## Fields [F] <a name="fields"></a>
These rules are about public fields on classes.
### Do not expose raw fields <a name="fields-avoid-raw"></a>
Java classes should not expose fields directly. Fields should be private and
accessible only via public getters and setters regardless of whether these
fields are final or non-final.
Rare exceptions include simple data structures where there will never be a need
to enhance the functionality of specifying or retrieving a field. In such cases,
the fields should be named using standard variable naming conventions, ex.
`Point.x` and `Point.y`.
Kotlin classes may expose properties.
### Exposed fields should be marked final <a name="fields-mutable-bare"></a>
Raw fields are strongly discouraged (@see
[Do not expose raw fields](#fields-avoid-raw)). But in the rare situation where
a field is exposed as a public field, mark that field `final`.
### Internal fields should not be exposed <a name="fields-internal"></a>
Do not reference internal field names in public API.
```java {.bad .no-copy}
public int mFlags;
```
### Use `public` instead of `protected` <a name="fields-public"></a>
@see [Use public instead of protected](#avoid-protected)
## Constants [C] <a name="constants"></a>
These are rules about public constants.
### Flag constants should be non-overlapping `int` or `long` values <a name="constants-flags"></a>
“Flags” implies bits that can be combined into some union value. If this is not
the case, do not call the variable/constant `flag`.
```java {.bad .no-copy}
public static final int FLAG_SOMETHING = 2;
public static final int FLAG_SOMETHING = 3;
```
```java {.good .no-copy}
public static final int FLAG_PRIVATE = 1 << 2;
public static final int FLAG_PRESENTATION = 1 << 3;
```
See [`@IntDef` for bitmask flags](#annotations-intdef-bitmask) for more
information on defining public flag constants.
### `static final` constants should use all-cap, underscore-separated naming convention <a name="constants-naming"></a>
All words in the constant should be capitalized and multiple words should be
separated by `_`. For example:
```java {.bad .no-copy}
public static final int fooThing = 5
```
```java {.good .no-copy}
public static final int FOO_THING = 5
```
### Use standard prefixes for constants <a name="constants-prefixes"></a>
Many of the constants used in Android are for standard things, such as flags,
keys, and actions. These constants should have standard prefixes to make them
more identifiable as these things.
For example, intent extras should start with `EXTRA_`. Intent actions should
start with `ACTION_`. Constants used with `Context.bindService()` should start
with `BIND_`.
### Naming and scoping of key constants <a name="constants-keys"></a>
String constant values should be consistent with the constant name itself, and
should generally be scoped to the package or domain. For example:
```java {.bad .no-copy}
public static final String FOO_THING = “foo”
```
is neither named consistently nor appropriately scoped. Instead, consider:
```java {.good .no-copy}
public static final String FOO_THING = “android.fooservice.FOO_THING”
```
Prefixes of `android` in scoped string constants are reserved for the Android
Open Source Project.
Intent actions and extras, as well as Bundle entries, should be namespaced using
the package name they are defined within.
```java {.good .no-copy}
package android.foo.bar {
public static final String ACTION_BAZ = “android.foo.bar.action.BAZ”
public static final String EXTRA_BAZ = “android.foo.bar.extra.BAZ”
}
```
### Use `public` instead of `protected` <a name="constants-visibility"></a>
@see [Use public instead of protected](#avoid-protected)
### Use consistent prefixes <a name="constants-consistency"></a>
Related constants should all start with the same prefix. For example, for a set
of constants to use with flag values:
```java {.bad .no-copy}
public static final int SOME_VALUE = 0x01;
public static final int SOME_OTHER_VALUE = 0x10;
public static final int SOME_THIRD_VALUE = 0x100;
```
```java {.good .no-copy}
public static final int FLAG_SOME_VALUE = 0x01;
public static final int FLAG_SOME_OTHER_VALUE = 0x10;
public static final int FLAG_SOME_THIRD_VALUE = 0x100;
```
@see [Use standard prefixes for constants](#constants-prefixes)
### Use consistent resource names <a name="constants-resource-names"></a>
Public identifiers, attributes, and values *must* be named using the camelCase
naming convention, e.g. `@id/accessibilityActionPageUp` or
`@attr/textAppearance`, similar to public fields in Java.
In some cases, a public identifier or attribute may include a common prefix
separated by an underscore:
* Platform config values such as `@string/config_recentsComponentName` in
[config.xml](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/res/res/values/config.xml;l=2721;drc=60faefffe98cb30abad690ccd183ef858bb7d3eb)
* Layout-specific view attributes such as `@attr/layout_marginStart` in
[attrs.xml](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/res/res/values/attrs.xml;l=3446;drc=60faefffe98cb30abad690ccd183ef858bb7d3eb)
Public themes and styles *must* follow the hierarchical PascalCase naming
convention, e.g. `@style/Theme.Material.Light.DarkActionBar` or
`@style/Widget.Material.SearchView.ActionBar`, similar to nested classes in
Java.
Layout and drawable resources *should not* be exposed as public APIs. If they
must be exposed, however, then public layouts and drawables *must* be named
using the under_score naming convention, e.g. `layout/simple_list_item_1.xml` or
`drawable/title_bar_tall.xml`.
### When constants could change, make them dynamic <a name="constants-min-max"></a>
Constant values may be inlined at compile time, so keeping values the same is
considered part of the API contract. If the value of a `MIN_FOO` or `MAX_FOO`
constant could change in the future, consider making them dynamic methods
instead.
```java {.bad .no-copy}
CameraManager.MAX_CAMERAS
```
```java {.good .no-copy}
CameraManager.getMaxCameras()
```
### Consider forward-compatibility for callbacks <a name="constants-callbacks-compatibility"></a>
Constants defined in future API versions are not known to apps that target older
APIs. For this reason, constants delivered to apps should take into
consideration that app’s target API version and map newer constants to a
consistent value. Consider the following scenario:
Hypothetical SDK source:
```java {.no-copy}
// Added in API level 22
public static final int STATUS_SUCCESS = 1;
public static final int STATUS_FAILURE = 2;
// Added in API level 23
public static final int STATUS_FAILURE_RETRY = 3;
// Added in API level 26
public static final int STATUS_FAILURE_ABORT = 4;
```
Hypothetical app with `targetSdkVersion="22"`:
```java {.no-copy}
if (result == STATUS_FAILURE) {
// Oh no!
} else {
// Success!
}
```
In this case, the app was designed within the constraints of API level 22 and
made a (somewhat) reasonable assumption that there were only two possible
states. If the app receives the newly-added `STATUS_FAILURE_RETRY`, however, it
will interpret this as success.
Methods that return constants can safely handle cases like this by constraining
their output to match the API level targeted by the app:
```java {.good .no-copy}
private int mapResultForTargetSdk(Context context, int result) {
int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
if (targetSdkVersion < 26) {
if (result == STATUS_FAILURE_ABORT) {
return STATUS_FAILURE;
}
if (targetSdkVersion < 23) {
if (result == STATUS_FAILURE_RETRY) {
return STATUS_FAILURE;
}
}
}
return result;
}
```
It’s unreasonable to expect developers and their published applications to be
clairvoyant. If you define an API with an `UNKNOWN` or `UNSPECIFIED` constant
that looks like a catch-all, developers will assume that the published constants
when they wrote their app are exhaustive. If you’re unwilling to set this
expectation, reconsider whether a catch-all constant is a good idea for your
API.
Consider also that libraries cannot specify their own `targetSdkVersion`
separate from the app, and that handling `targetSdkVersion` behavior changes
from library code is exceedingly complicated and error-prone.
### Integer or `String` constant? <a name="constants-integer-or-string"></a>
Use integer constants and `@IntDef` if the namespace for values is not
extensible outside of your package. Use string constants if the namespace is
shared or can be extended by code outside of your package.
### Data classes <a name="data-class"></a>
Data classes represent a set of immutable properties and provide a small and
well-defined set of utility functions for interacting with that data.
**Do not** use `data class` in public Kotlin APIs, as the Kotlin compiler does
not guarantee language API or binary compatibility for generated code. Instead,
manually implement the required functions.
#### Instantiation <a name="data-class-new"></a>
In Java, data classes should provide a constructor when there are few properties
or use the [`Builder`](#builders) pattern when there are many properties.
In Kotlin, data classes should provide a constructor with default arguments
regardless of the number of properties. Data classes defined in Kotlin may also
benefit from providing a builder when targeting Java clients.
#### Modification and copying <a name="data-class-copy"></a>
In cases where data needs to be modified, provide either a
[`Builder`](#builders) with a copy constructor (Java) or a `copy()` member
function (Kotlin) that returns a new object.
When providing a `copy()` function in Kotlin, arguments must match the class's
constructor and defaults must be populated using the object's current values.
```kotlin {.good .no-copy}
class Typography(
val labelMedium: TextStyle = TypographyTokens.LabelMedium,
val labelSmall: TextStyle = TypographyTokens.LabelSmall
) {
fun copy(
labelMedium: TextStyle = this.labelMedium,
labelSmall: TextStyle = this.labelSmall
): Typography = Typography(
labelMedium = labelMedium,
labelSmall = labelSmall
)
}
```
#### Additional functionality <a name="data-class-misc"></a>
Data classes should implement both
[`equals()` and `hashCode()`](#equals-and-hashcode), and every property must be
accounted for in the implementations of these methods.
Data classes may implement [`toString()`](#toString) with a recommended format
matching [Kotlin's data class](https://kotlinlang.org/docs/data-classes.html)
implementation, e.g. `User(var1=Alex, var2=42)`.