| ## 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)`. |