package com.example.myapp.utils
import android.os.Build
import android.os.StrictMode
import android.os.Trace
import timber.log.Timber
object PerformanceUtils {
fun enableStrictMode() {
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build()
)
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build()
)
}
}
inline fun <T> trace(sectionName: String, block: () -> T): T {
Trace.beginSection(sectionName)
return try {
block()
} finally {
Trace.endSection()
}
}
inline fun <T> measureTime(tag: String, block: () -> T): T {
val start = System.currentTimeMillis()
return try {
block()
} finally {
val duration = System.currentTimeMillis() - start
Timber.d("$tag took ${duration}ms")
}
}
fun logMemoryUsage() {
val runtime = Runtime.getRuntime()
val usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024
val maxMemory = runtime.maxMemory() / 1024 / 1024
val availableMemory = maxMemory - usedMemory
Timber.d("Memory: Used=${usedMemory}MB, Max=${maxMemory}MB, Available=${availableMemory}MB")
}
}
// Usage in Application class:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
PerformanceUtils.enableStrictMode()
// Setup LeakCanary (automatically enabled in debug)
}
}
}
// Usage in code:
// PerformanceUtils.trace("LoadPosts") {
// repository.loadPosts()
// }
//
// PerformanceUtils.measureTime("Database Query") {
// database.postDao().getAllPosts()
// }
package com.example.myapp.ui.optimized
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.myapp.databinding.ItemPostBinding
// Efficient adapter with ViewBinding and DiffUtil
class OptimizedPostsAdapter(
private val onPostClick: (Post) -> Unit
) : ListAdapter<Post, OptimizedPostsAdapter.ViewHolder>(PostDiffCallback()) {
// ViewHolder with ViewBinding - no findViewById
class ViewHolder(
private val binding: ItemPostBinding,
private val onPostClick: (Post) -> Unit
) : RecyclerView.ViewHolder(binding.root) {
private var currentPost: Post? = null
init {
binding.root.setOnClickListener {
currentPost?.let(onPostClick)
}
}
fun bind(post: Post) {
currentPost = post
binding.apply {
titleText.text = post.title
bodyText.text = post.body
authorText.text = post.author
// Load image efficiently with Glide
GlideApp.with(itemView.context)
.load(post.imageUrl)
.placeholder(R.drawable.placeholder)
.into(postImage)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemPostBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return ViewHolder(binding, onPostClick)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
// Efficient DiffUtil callback
private class PostDiffCallback : DiffUtil.ItemCallback<Post>() {
override fun areItemsTheSame(oldItem: Post, newItem: Post): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Post, newItem: Post): Boolean {
return oldItem == newItem
}
// Optional: for partial updates
override fun getChangePayload(oldItem: Post, newItem: Post): Any? {
return when {
oldItem.likesCount != newItem.likesCount -> "LIKES"
else -> null
}
}
}
// Partial binding for better performance
override fun onBindViewHolder(
holder: ViewHolder,
position: Int,
payloads: MutableList<Any>
) {
if (payloads.isEmpty()) {
super.onBindViewHolder(holder, position, payloads)
} else {
// Handle partial update
val post = getItem(position)
for (payload in payloads) {
when (payload) {
"LIKES" -> {
// Update only likes count
holder.itemView.findViewById<TextView>(R.id.likesText)
?.text = "${post.likesCount} likes"
}
}
}
}
}
}
Android performance optimization ensures smooth 60fps UI and efficient resource usage. I use Android Profiler to monitor CPU, memory, network, and energy. Layout Inspector identifies overdraw and deep view hierarchies. Systrace captures system-level traces. LeakCanary detects memory leaks. Optimize layouts—use ConstraintLayout, avoid nested weights, flatten hierarchies. RecyclerView with DiffUtil minimizes list updates. Image loading uses appropriate sizes and caching. Background work uses WorkManager instead of constant services. Database queries use indices and batch operations. Avoid work on main thread—use coroutines for async operations. Strict mode catches common mistakes. APK Analyzer shows size breakdown. Benchmarking libraries measure performance regressions. Profile regularly to maintain responsive apps.
Related snips
require "csv"
class PeopleCsvStream
include Enumerable
HEADERS = %w[id full_name email signed_up_at plan].freeze
Resilient CSV Export as a Streamed Response
package com.example.myapp
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
Dependency injection with Hilt
Rails.application.configure do
config.after_initialize do
Bullet.enable = true
Bullet.alert = false
Bullet.bullet_logger = true
Bullet.console = true
N+1 query detection with Bullet gem
package com.example.myapp.ui
import androidx.lifecycle.*
import kotlinx.coroutines.launch
class UserViewModel(
LiveData transformations and mediators
# BAD: N+1 query problem
@users = User.all
@users.each do |user|
puts user.posts.count # Fires query for each user!
end
ActiveRecord query optimization and N+1 prevention
json.array! @posts do |post|
json.cache! ['v1', post], expires_in: 1.hour do
json.id post.id
json.title post.title
json.excerpt post.excerpt
json.published_at post.published_at
Fragment caching for expensive JSON serialization
Share this code
Here's the card — post it anywhere.