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.