// dependencies.gradle
ext.versions = [
code : 1,
name : '1.0',
minSdk : 16,
targetSdk : 26,
compileSdk : 26,
buildTools : '26.0.2',
kotlin : '1.1.51',
androidGradlePlugin: '3.0.0-rc1',
supportLibs : '26.1.0',
constraintLayout : '1.0.2',
junit : '4.12',
espresso : '3.0.1',
supportTestRunner : '1.0.0',
]
// dependencies.gradle
ext.versions = [ … ]
ext.gradlePlugins = [
android: "com.android.tools.build:gradle:$versions.androidGradlePlugin",
kotlin : "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin",
]
ext.libraries = [
kotlin : "org.jetbrains.kotlin:kotlin-stdlib-jre7:$versions.kotlin",
supportAppCompat : "com.android.support:appcompat-v7:$versions.supportLibs",
constraintLayout :
"com.android.support.constraint:constraint-layout:$versions.constraintLayout",
junit : "junit:junit:$versions.junit",
supportTestRunner: "com.android.support.test:runner:$versions.supportTestRunner",
espressoCore :
"com.android.support.test.espresso:espresso-core:$versions.espresso",
]
apply from: 'dependencies.gradle'
buildscript {
// Gradle will not find vars defined in an external file when referring to them
// in the buildscript block, unless you link it from the buildscript block, too.
apply from: 'dependencies.gradle'
repositories {
google()
jcenter()
}
dependencies {
classpath gradlePlugins.android
classpath gradlePlugins.kotlin
}
}
apply from: 'dependencies.gradle'
buildscript {
// Gradle will not find vars defined in an external file when referring to them
// in the buildscript block, unless you link it from the buildscript block, too.
apply from: 'dependencies.gradle'
repositories {
google()
jcenter()
}
dependencies {
classpath gradlePlugins.android
classpath gradlePlugins.kotlin
}
}
// apply from: 'dependencies.gradle' automatically added
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
// the ext.versions in the dependencies.gradle is accessable
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
}
android {
defaultConfig {
applicationId "com.domain.appname"
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
versionCode versions.code
versionName versions.name
}
}
android {
defaultConfig {
applicationId "com.domain.appname"
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
versionCode versions.code
versionName versions.name
}
}
dependencies {
implementation libraries.kotlin
implementation libraries.supportAppCompat
implementation libraries.constraintLayout
}
dependencies {
testImplementation libraries.junit
}
dependencies {
androidTestImplementation libraries.supportTestRunner
androidTestImplementation libraries.espressoCore
}
packagingOptions {
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/services/javax.annotation.processing.Processor'
}
lintOptions {
warningsAsErrors true
abortOnError true // Fail early.
// Okio references java.nio that does not presented in Android SDK.
disable 'InvalidPackage'
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<lint>
<issue id="UnusedResources">
<ignore path="res/layout/activity_main.xml"/>
</issue>
</lint>
// dependencies.gradle
ext.versions = [
dexcountPlugin : '0.8.1',
]
ext.gradlePlugins = [
dexcount: "com.getkeepsafe.dexcount" +
":dexcount-gradle-plugin:$versions.dexcountPlugin",
]
dependencies {
classpath gradlePlugins.android
classpath gradlePlugins.kotlin
classpath gradlePlugins.dexcount
}
// dependencies.gradle
ext.versions = [
versionsGradlePlugin: '0.15.0',
]
ext.gradlePlugins = [
versions: "com.github.ben-manes:" +
"gradle-versions-plugin:$versions.versionsGradlePlugin",
]
// root/build.gradle
buildscript {
…
dependencies {
…
classpath gradlePlugins.versions
}
}
// root/build.gradle
buildscript {
…
dependencies {
…
classpath gradlePlugins.versions
}
}
./gradew dependencyUpdates
# The following dependencies are using the latest milestone version:
# - com.android.support:appcompat-v7:26.1.0
# - org.jetbrains.kotlin:kotlin-annotation-processing:1.1.51
# - org.jetbrains.kotlin:kotlin-stdlib-jre7:1.1.51
# The following dependencies have later milestone versions:
# - org.jacoco:org.jacoco.agent [0.7.4.201502262128 -> 0.7.9]
# - org.jacoco:org.jacoco.ant [0.7.4.201502262128 -> 0.7.9]
# - com.android.support.test:runner [1.0.0 -> 1.0.1]
https://github.com/friendlyrobotnyc/TinyDancer
class DebugApplication : Application() {
override fun onCreate() {
super.onCreate()
TinyDancer.create().show(this)
}
}
https://github.com/friendlyrobotnyc/TinyDancer
//alternatively
TinyDancer.create()
.redFlagPercentage(.1f) // set red indicator for 10%....different from default
.startingXPosition(200)
.startingYPosition(600)
.show(this)
// Or
TinyDancer.create()
.addFrameDataCallback { previousFrameNS, currentFrameNS, droppedFrames ->
//collect your stats here
}
.show(this)
The problem with performance is that it often decreases slowly so in day-by-day development it's hard to notice that our app (or Activity or any other view) launches 50ms longer. And another 150ms longer, and another 100ms…
https://github.com/frogermcs/AndroidDevMetrics
buildscript { // Root build.gradle
apply from: 'dependencies.gradle'
// Rest of plugins
classpath gradlePlugins.androidDevMetrics
}
// App build.gradle
apply plugin: 'com.android.application'
apply plugin: 'com.frogermcs.androiddevmetrics'
https://github.com/square/leakcanary
// Dev tools
dependencies {
debugImplementation libraries.leakCanary
releaseImplementation libraries.leakCanaryNoop
debugImplementation libraries.tinyDancer
releaseImplementation libraries.tinyDancerNoop
}
class App : Application() {
var refWatcher: RefWatcher? = null
private set
override fun onCreate() {
super.onCreate()
if (LeakCanary.isInAnalyzerProcess(this)) {
return
}
refWatcher = LeakCanary.install(this)
}
}
class App : Application() {
var refWatcher: RefWatcher? = null
private set
override fun onCreate() {
super.onCreate()
if (LeakCanary.isInAnalyzerProcess(this)) {
return
}
refWatcher = LeakCanary.install(this)
}
}
class App : Application() {
var refWatcher: RefWatcher? = null
private set
override fun onCreate() {
super.onCreate()
if (LeakCanary.isInAnalyzerProcess(this)) {
return
}
refWatcher = LeakCanary.install(this)
}
class App : Application() {
companion object {
fun getRefWatcher(context: Activity) =
((context.applicationContext) as App).refWatcher
}
var refWatcher: RefWatcher? = null
private set
override fun onCreate() {
…
}
}
class App : Application() {
override fun onCreate() {
super.onCreate()
Stetho.initializeWithDefaults(this)
// Rest of onCreate…
}
}
class Network {
// For OkHttp 3.x
OkHttpClient.Builder()
.addNetworkInterceptor(StethoInterceptor())
.build()
// For OkHttp 2.x
OkHttpClient().apply {
networkInterceptors().add(StethoInterceptor())
}
}
class Network {
// For OkHttp 3.x
OkHttpClient.Builder()
.addNetworkInterceptor(StethoInterceptor())
.build()
// For OkHttp 2.x
OkHttpClient().apply {
networkInterceptors().add(StethoInterceptor())
}
}
public class ExampleApp extends Application {
@Override public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
// Prints to log cat
Timber.plant(new DebugTree());
} else {
// Does not print to log cat
// Instead sends logs to Crash Reporting Tool
Timber.plant(new CrashReportingTree());
}
}
/** A tree which logs important information for crash reporting. */
private static class CrashReportingTree extends Timber.Tree {
@Override protected void log(int priority, String tag, String message, Throwable t) {
if (priority == Log.VERBOSE || priority == Log.DEBUG) {
return;
}
FakeCrashLibrary.log(priority, tag, message);
if (t != null) {
if (priority == Log.ERROR) {
FakeCrashLibrary.logError(t);
} else if (priority == Log.WARN) {
FakeCrashLibrary.logWarning(t);
}
}
}
}
}
// Application onCreate
val lynxShakeDetector
= LynxShakeDetector(this)
lynxShakeDetector.init()
class App : Application() {
companion object {
fun getRefWatcher(context: Activity) =
((context.applicationContext) as App).refWatcher
}
var refWatcher: RefWatcher? = null
private set
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
Stetho.initializeWithDefaults(this)
if (LeakCanary.isInAnalyzerProcess(this)) {
return
}
refWatcher = LeakCanary.install(this)
TinyDancer.create()
.redFlagPercentage(.1f) // set red indicator for 10%....different from default
.startingXPosition(200)
.startingYPosition(600)
.show(this)
}
}
}
interface Bootstrap {
fun init()
}
class TinyDancerBootstrap(private val app: Application) : Bootstrap {
override fun init() {
TinyDancer.create().show(app)
}
}
class DevMetrics(private val app: Application) : Bootstrap {
override fun init() {
AndroidDevMetrics.initWith(app)
}
}
@Module
object BootstrapModule {
@Provides @Singleton @JvmStatic
@IntoSet
fun provideTinyDancer(app: Application): Bootstrap
= TinyDancerBootstrap(app)
@Provides @Singleton @JvmStatic
@IntoSet
fun provideDevMetrics(app: Application): Bootstrap
= DevMetrics(app)
}
@Module
object BootstrapModule {
@Provides @Singleton @JvmStatic
@IntoSet
fun provideTinyDancer(app: Application): Bootstrap
= TinyDancerBootstrap(app)
@Provides @Singleton @JvmStatic
@IntoSet
fun provideDevMetrics(app: Application): Bootstrap
= DevMetrics(app)
}
class App : Application() {
@Inject
lateinit var bootstraps: MutableSet<Bootstrap>
override fun onCreate() {
super.onCreate()
DaggerComponent … inject(this)
if(BuildConfig.DEBUG) {}
bootstraps.forEach { it.init() }
}
}
}
Gradle Retrolambda PluginAndroid Studio 3 come with Java 8 support
- WIP Example Project
- Slides
- Gradle DexCount
- Gradle Versions Plugin
- Artem Quality Matters Android Project