Changes for R8 Configuration analyzer example

ioc-workshop
Ajesh R 4 days ago
parent edbd6f7cb7
commit c2d884b7c5
No known key found for this signature in database

@ -56,6 +56,15 @@ android {
// Ensure Baseline Profile is fresh for release builds.
baselineProfile.automaticGenerationDuringBuild = true
}
create("benchmark") {
initWith(getByName("release"))
matchingFallbacks += listOf("release")
applicationIdSuffix = NiaBuildType.BENCHMARK.applicationIdSuffix
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
packaging {
@ -79,6 +88,7 @@ dependencies {
implementation(projects.feature.search.api)
implementation(projects.feature.search.impl)
implementation(projects.feature.settings.impl)
implementation(projects.mylibrary)
implementation(projects.core.common)
implementation(projects.core.ui)

@ -17,6 +17,7 @@
package com.google.samples.apps.nowinandroid
import android.app.Application
import android.content.ComponentCallbacks2
import android.content.pm.ApplicationInfo
import android.os.StrictMode
import android.os.StrictMode.ThreadPolicy.Builder
@ -26,12 +27,21 @@ import com.google.samples.apps.nowinandroid.sync.initializers.Sync
import com.google.samples.apps.nowinandroid.util.ProfileVerifierLogger
import dagger.hilt.android.HiltAndroidApp
import javax.inject.Inject
import com.example.mylibrary.StartupTask
import com.example.mylibrary.TaskRunner
import android.util.Log
class NiaStartupTask : StartupTask {
override fun run() {
Log.d("NiaStartupTask", "Running startup task from mylibrary")
}
}
/**
* [Application] class for NiA
*/
@HiltAndroidApp
class NiaApplication : Application(), ImageLoaderFactory {
class NiaApplication : Application(), ImageLoaderFactory, ComponentCallbacks2 {
@Inject
lateinit var imageLoader: dagger.Lazy<ImageLoader>
@ -41,11 +51,10 @@ class NiaApplication : Application(), ImageLoaderFactory {
override fun onCreate() {
super.onCreate()
setStrictModePolicy()
// Initialize Sync; the system responsible for keeping data in the app up to date.
Sync.initialize(context = this)
profileVerifierLogger()
TaskRunner.execute(NiaStartupTask::class.java)
}
override fun newImageLoader(): ImageLoader = imageLoader.get()
@ -57,6 +66,27 @@ class NiaApplication : Application(), ImageLoaderFactory {
return 0 != applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE
}
override fun onTrimMemory(level: Int) {
super<Application>.onTrimMemory(level)
// 1. Explicitly clear or trim our ImageLoader's memory cache
// (Note: Coil automatically listens to ComponentCallbacks2, but this serves as a good
// example of how to manually trim caches based on system memory signals).
if (level == TRIM_MEMORY_UI_HIDDEN){
// The user has navigated away from the app and the UI is no longer visible.
// This is a good place to release large UI-related resources that you
// won't need while in the background
imageLoader.get().memoryCache?.trimMemory(level)
}
if(level == TRIM_MEMORY_BACKGROUND) {
// The app is in the background and the system is running low on memory.
// As the level increases to COMPLETE, the likelihood of the app process
// being killed increases. Aggressively clear caches here.
imageLoader.get().memoryCache?.clear()
}
}
/**
* Set a thread policy that detects all potential problems on the main thread, such as network
* and disk access.

@ -22,4 +22,5 @@ package com.google.samples.apps.nowinandroid
enum class NiaBuildType(val applicationIdSuffix: String? = null) {
DEBUG(".debug"),
RELEASE,
BENCHMARK(".benchmark")
}

@ -81,7 +81,11 @@ internal object NetworkModule {
): ImageLoader = trace("NiaImageLoader") {
ImageLoader.Builder(application)
.callFactory { okHttpCallFactory.get() }
.components { add(SvgDecoder.Factory()) }
.memoryCache(null) // ❌ Bug 1: Memory cache disabled
.diskCache(null)
// ❌ Bug 2: Disk cache disabled
.allowHardware(false) // ❌ Bug 3: Forces bitmaps onto Java heap
.bitmapConfig(android.graphics.Bitmap.Config.ARGB_8888)
// Assume most content images are versioned urls
// but some problematic images are fetching each time
.respectCacheHeaders(false)

@ -17,6 +17,7 @@
package com.google.samples.apps.nowinandroid.core.ui
import android.content.ClipData
import android.graphics.Bitmap
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.view.View
@ -53,7 +54,10 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draganddrop.DragAndDropTransferData
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
@ -64,6 +68,7 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import coil.compose.AsyncImagePainter
import coil.compose.rememberAsyncImagePainter
import com.google.samples.apps.nowinandroid.core.designsystem.R.drawable
@ -189,10 +194,29 @@ fun NewsResourceHeaderImage(
},
)
val isLocalInspection = LocalInspectionMode.current
val context = LocalContext.current
val perRowBitmap = remember {
Bitmap.createBitmap(
2000, 2000, Bitmap.Config.ARGB_8888
).apply {
val canvas = android.graphics.Canvas(this)
// Now you can use 'context' here to load the drawable
val drawable = ContextCompat.getDrawable(
context,
drawable.core_designsystem_ic_placeholder_default
)
drawable?.setBounds(0, 0, width, height)
drawable?.draw(canvas)
}.asImageBitmap()
}
Box(
modifier = Modifier
.fillMaxWidth()
.height(180.dp),
.height(320.dp),
contentAlignment = Alignment.Center,
) {
if (isLoading) {
@ -205,15 +229,16 @@ fun NewsResourceHeaderImage(
)
}
Image(
modifier = Modifier
.fillMaxWidth()
.height(180.dp),
.height(320.dp),
contentScale = ContentScale.Crop,
painter = if (isError.not() && !isLocalInspection) {
imageLoader
} else {
painterResource(drawable.core_designsystem_ic_placeholder_default)
BitmapPainter(perRowBitmap)
},
// TODO b/226661685: Investigate using alt text of image to populate content description
// decorative image,

@ -0,0 +1,37 @@
plugins {
alias(libs.plugins.android.library)
}
android {
namespace = "com.example.mylibrary"
compileSdk = 36
defaultConfig {
minSdk = 21
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.test.ext)
androidTestImplementation(libs.androidx.test.espresso.core)
}

@ -0,0 +1,12 @@
# Declare that the default constructor is called reflectively.
-keep class * implements com.example.mylibrary.StartupTask { <init>(); }
-keep class * {
public *;
}
-dontwarn com.example.mylibrary.StartupTask
-dontwarn com.example.mylibrary.TaskRunner

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

@ -0,0 +1,24 @@
package com.example.mylibrary
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.mylibrary.test", appContext.packageName)
}
}

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

@ -0,0 +1,17 @@
package com.example.mylibrary
interface StartupTask {
fun run()
}
// The library object that loads and executes the task.
object TaskRunner {
fun execute(taskClassFromApp: Class<out StartupTask>) {
// R8 will remove the class specified by this string.
val taskClassInstance =
taskClassFromApp.getDeclaredConstructor().newInstance() as StartupTask
taskClassInstance.run()
}
}

@ -0,0 +1,17 @@
package com.example.mylibrary
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

@ -15,6 +15,17 @@
*/
pluginManagement {
buildscript {
repositories {
mavenCentral()
maven {
url = uri("https://storage.googleapis.com/r8-releases/raw")
}
}
dependencies {
classpath("com.android.tools:r8:9.3.7-dev")
}
}
includeBuild("build-logic")
repositories {
google {
@ -81,6 +92,7 @@ include(":lint")
include(":sync:work")
include(":sync:sync-test")
include(":ui-test-hilt-manifest")
include(":mylibrary")
check(JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) {
"""

Loading…
Cancel
Save