Android Team Coding Standards
These guidelines should be followed when writing Java and Kotlin code for the Android platform. Patches and additions to any code base will be checked for adherence to these guidelines. If code is in violation, you will be asked to reformat it. For Android Studio you can import the this code style scheme: Vokal.xml (Preferences > Editor > Code Style > Config Icon > Import Scheme...)
There are separate documents for Java Code Standards, Kotlin Code Standards, and Android Resource Formatting Standards
Naming Guidelines
- Names should be descriptive and it is best to avoid abbreviations and acronyms. You should be able to read the code out loud, over the phone.
- If an abbreviation or acronym is used, it should be in the form of an accepted name that is generally well-known.
- If an acronym is two characters long, it should be all caps:
vokalApi[‘IO’] and not vokalApi[‘Io’]
- If an acronym is three or more characters long, only its first letter should be capitalized
vokalApi[‘Api’]
- Avoid “temp” variables. Be as descriptive as possible even if the variable does something very simple. If you have to use a non-descriptive variable name, then provide comments that explain what that specific block of code is doing. Especially avoid generic variable names like “tmp”, “data”, “obj”, “res”, etc.
Coding Style
- Use 4 space characters for indention, not tabs.
- Try to observe a 120 character wrap margin. If your lines are over 120 characters, break and indent them logically.
- Break lines only after a punctuator:
, . ; : { } ( [ = < > ? ! + - * / % ~ ^ | & == != <= >= += -= *= /= %= ^= |= &= << >> || && === !== <<= >>= >>> >>>=
- Long ternary operations can be broken as follows:
String someMessage = (conditional) ? "This is the message when some thing is true"
: "This is the message when some thing is false!";
- Leave a space before conditional parenthesis and the opening brace:
if (condition) {
callSomeFunction(args);
}
- When type casting, follow the casted type with a space:
adLayout = (RelativeLayout) findViewById(R.id.ad);
- Braces should start on the same line unless otherwise noted in this document:
public void foo() {
if (condition) {
...
} else if (condition) {
...
}
while (condition) {
...
}
}
- Arithmetic and assignment operations should be properly spaced:
int total = x + 2;
String someString = otherString + anotherString;
- Avoid magic constants
if(variable == 14.76) {
...
}
- Import statements should be listed alphabetically
- Wildcard imports (of any type) are not allowed
- Group common imports together with Android packages first, followed by Java SDK packages, non-SDK packages, and finally your own packages (this can be configured in Android Studio in Preferences > Editor > Code Style > Imports > Import Layout):
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import java.util.ArrayList;
import java.util.HashMap;
import org.json.JSONObject;
import com.vokal.myapp.MyClass;
MVVM
- Views should only have code written for configuration and their logic is only based on their own context
- Views can call their ViewModels directly for lifecycle events purposes, but should try to keep those calls to a minimum
- Instead make use of binding calls from UI elements to their ViewModel such as
onClickListener
events - Custom binding adapters can be of good practice when used in multiple places and keeps the View logic to a minimum
- Names of the ViewModel request methods should be direct commands:
showLoadingDialog()
- Business logic should be contained in ViewModels and tested
- Names of ViewModels methods should reflect the action taken in the view:
onLoginButtonClick()
- ViewModels should be injected with Dagger when possible, read more
- ViewModels dependencies should be injected into the constructor so they can be mocked
- Fragments should observe
LiveData
based onviewLifecycleOwner
- ViewModels should not contain any Android framework dependencies
- A ViewModel should never reference the View's context nor its views to avoid memory leaks.
- Avoid using AndroidViewModel instead provide to the ViewModel an object represented by an interface and whose context is based on the application similar approach for Android framework dependencies.
interface ResProvider {
fun getString(@StringRes resId: Int): String
}
class MyResProvider(private val app: Application) {
override fun getString(@StringRes resId: Int): String {
return app.getString(resId)
}
}
@Module
class AppModule(private val app: Application) {
@Provides
fun getResProvider(): ResProvider {
return MyResProvider(app)
}
}
class FeatureViewModel @Inject constructor(resProvider: ResProvider): ViewModel
See our Databinding Coding Standards for code-related info.
MVP
- Views should be "passive", meaning they contain as little decision logic as possible
- Names of View interface methods should be direct commands:
showLoadingDialog()
- Business logic should be contained in Presenters and tested
- Names of Presenter interface methods should reflect the action taken in the view:
onLoginButtonClick()
- Presenters should be injected with Dagger
- Presenters should not contain any Android framework dependencies
- Presenter dependencies should be injected into the constructor so they can be mocked
Navigation Component
Implementation Guidelines
- Do not change an API that is already in place without discussing with the team and receiving approval from all team members. When changing the API, the change must be consistent throughout the entire code base.
- All program design should stick strictly to the method used within the given project. Be consistent within the project you are working, even if it contradicts other guidelines in this document.
- Create private helper methods if a class method is becoming too long. At most, a method should be one “screen” long.
- Minimize exit points of a function. Ideally, there should only be one
- Design your code for architecture, not speed. Optimizations can be applied to well-constructed code and should be left for the later part of development.
Commenting
- Don't comment bad code- rewrite it. -- Clean Code Your code should speak for itself, and not require a lot of commenting. Your method names and variables should use meaniful names so the logic is clear. Don't make the logic so convoluted it would require commenting.
- If it is ultimately useful to leave information that will be read at a later time by people (possibly yourself) who will need to understand what you have done, then by all means, leave a comment. Comments should be well-written and clear, just like the code they are annotating.
- Make comments meaningful. Focus on what is not immediately visible. Don't waste the reader's time with stuff like
i = 0; // Set i to zero.
- Generally use line comments. Save block comments for formal documentation and for commenting out.
- It is important that comments be kept up-to-date. Erroneous comments can make programs even harder to read and understand. Remove comments that are no longer relevant.
- There is no need to initial areas of code. The version control system handles this on a line-by-line basis.
Additional Information
Architecture Components pitfalls
5 common mistakes when using Architecture Components