惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Privacy & Cybersecurity Law Blog
Engineering at Meta
Engineering at Meta
Forbes - Security
Forbes - Security
MongoDB | Blog
MongoDB | Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
A
About on SuperTechFans
量子位
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
雷峰网
雷峰网
腾讯CDC
P
Proofpoint News Feed
S
Schneier on Security
S
Secure Thoughts
V
Visual Studio Blog
Help Net Security
Help Net Security
The Hacker News
The Hacker News
C
Cyber Attacks, Cyber Crime and Cyber Security
P
Privacy International News Feed
SecWiki News
SecWiki News
S
SegmentFault 最新的问题
T
Threatpost
小众软件
小众软件
MyScale Blog
MyScale Blog
F
Fortinet All Blogs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
P
Proofpoint News Feed
T
Tailwind CSS Blog
I
Intezer
C
CERT Recently Published Vulnerability Notes
U
Unit 42
V
V2EX
Cyberwarzone
Cyberwarzone
Recorded Future
Recorded Future
O
OpenAI News
Project Zero
Project Zero
有赞技术团队
有赞技术团队
Google DeepMind News
Google DeepMind News
Last Week in AI
Last Week in AI
Hugging Face - Blog
Hugging Face - Blog
Know Your Adversary
Know Your Adversary
C
Cybersecurity and Infrastructure Security Agency CISA
Scott Helme
Scott Helme
V2EX - 技术
V2EX - 技术
博客园 - 叶小钗
S
Securelist
A
Arctic Wolf
The Cloudflare Blog
W
WeLiveSecurity
T
Threat Research - Cisco Blogs
博客园 - Franky

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
CLAUDE.md for Android and Jetpack Compose: 13 Rules That Make AI Write Modern, Production-Ready Android Code
Olivia Craft · 2026-05-20 · via DEV Community

CLAUDE.md for Android and Jetpack Compose: 13 Rules That Make AI Write Modern, Production-Ready Android Code

Android development has two eras of AI output quality.

The first era: AI that reaches for XML layouts, AsyncTask, SharedPreferences, and findViewById. Code that compiles on Android 14 but was written for Android 4. Code that passes lint but violates every modern architecture guideline.

The second era: AI that defaults to Compose, coroutines, ViewModel, StateFlow, Hilt, and the patterns from the Now in Android reference project.

The difference between these outcomes is a CLAUDE.md that specifies which Android you're building.

These 13 rules cover the patterns that matter most — the ones where AI drifts to legacy APIs without explicit instruction.


Rule 1: Jetpack Compose only — no XML layouts

UI: Jetpack Compose exclusively. No XML layouts, no View system.
Forbidden: ConstraintLayout XML, LinearLayout, RelativeLayout, findViewById.
Composables: stateless where possible. State hoisted to ViewModel.
Preview: @Preview annotation on every composable component.
Material3 only — not Material2.

Enter fullscreen mode Exit fullscreen mode

AI has seen enormous volumes of XML-based Android code. Without a rule, it will generate setContentView(R.layout.activity_main) and ViewBinding for new screens in a Compose project.

// Banned — XML/View system
class UserFragment : Fragment() {
    private lateinit var binding: FragmentUserBinding
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        binding.nameText.text = viewModel.userName
    }
}

// Required — Jetpack Compose
@Composable
fun UserScreen(
    uiState: UserUiState,
    onAction: (UserAction) -> Unit
) {
    Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
        Text(text = uiState.userName, style = MaterialTheme.typography.headlineMedium)
    }
}

Enter fullscreen mode Exit fullscreen mode


Rule 2: ViewModel + UiState — no logic in Composables

Architecture:
- ViewModel: holds UI state, handles user actions, calls use cases.
- UiState: sealed class or data class representing screen state.
- Composables: render UiState. No business logic. No direct repository calls.
- Events: one-time events (navigation, toasts) via Channel<UiEvent>.
- StateFlow<UiState> exposed from ViewModel. Collected with collectAsStateWithLifecycle().

Enter fullscreen mode Exit fullscreen mode

AI generates Composables that call repositories directly, fetch data in LaunchedEffect without a ViewModel, and hold mutable state locally for things that should survive rotation.

// Wrong — business logic and state in Composable
@Composable
fun UserScreen(repository: UserRepository) {
    var userName by remember { mutableStateOf("") }
    LaunchedEffect(Unit) {
        userName = repository.getUser().name  // Direct repo call, no ViewModel
    }
    Text(text = userName)
}

// Right — ViewModel owns state
@HiltViewModel
class UserViewModel @Inject constructor(
    private val getUserUseCase: GetUserUseCase
) : ViewModel() {
    private val _uiState = MutableStateFlow<UserUiState>(UserUiState.Loading)
    val uiState: StateFlow<UserUiState> = _uiState.asStateFlow()

    init { loadUser() }

    private fun loadUser() = viewModelScope.launch {
        _uiState.value = getUserUseCase().fold(
            onSuccess = { UserUiState.Content(it) },
            onFailure = { UserUiState.Error(it.message) }
        )
    }
}

Enter fullscreen mode Exit fullscreen mode


Rule 3: Coroutines and Flow — no callbacks, no RxJava

Async: Kotlin coroutines everywhere. No callbacks. No RxJava. No AsyncTask.
Repositories: return Flow<T> for streams, suspend fun for one-shot operations.
Dispatchers: IO for network/disk, Default for CPU-intensive. Never Main for background work.
viewModelScope: use for ViewModel coroutines. Never GlobalScope.
Cancellation: coroutines are cooperative — check cancellation in long loops.

Enter fullscreen mode Exit fullscreen mode

AI generates callback-style code and sometimes RxJava (from older training data). Both are banned in modern Android.

// Banned — callback style
fun getUser(id: String, callback: (User) -> Unit) {
    thread { callback(api.getUser(id)) }  // No cancellation, no error handling
}

// Required — coroutines
suspend fun getUser(id: String): Result<User> = withContext(Dispatchers.IO) {
    runCatching { api.getUser(id) }
}

// Repository stream
fun observeMessages(): Flow<List<Message>> = messageDao.observeAll()
    .flowOn(Dispatchers.IO)
    .catch { emit(emptyList()) }

Enter fullscreen mode Exit fullscreen mode


Rule 4: Hilt for dependency injection — no manual DI, no Koin

DI: Hilt exclusively.
Modules: @InstallIn with appropriate component scope.
ViewModel: @HiltViewModel + @Inject constructor.
Application: @HiltAndroidApp on Application class.
No: manual object graphs, service locators, companion object getInstance().

Enter fullscreen mode Exit fullscreen mode

AI generates singleton patterns and manual DI because they're simpler to write inline. Hilt makes dependencies explicit, scoped, and testable.

// Banned — manual singleton
object NetworkClient {
    val api: ApiService by lazy { Retrofit.Builder()... }
}

// Required — Hilt module
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @Provides @Singleton
    fun provideApiService(client: OkHttpClient): ApiService =
        Retrofit.Builder().client(client).baseUrl(BASE_URL).build()
            .create(ApiService::class.java)
}

Enter fullscreen mode Exit fullscreen mode


Rule 5: Repository pattern — data layer is abstract

Data layer:
- Repository interface in domain layer. Implementation in data layer.
- Repositories return domain models — never network DTOs or Room entities.
- Mapping: explicit mappers between layers (DTO → Domain, Entity → Domain).
- Local-first: Room as source of truth. Network syncs to Room. UI observes Room.
- No direct Retrofit calls from ViewModel or use cases.

Enter fullscreen mode Exit fullscreen mode

// Domain layer — interface
interface UserRepository {
    fun observeUser(id: String): Flow<User>
    suspend fun syncUser(id: String): Result<Unit>
}

// Data layer — implementation
class UserRepositoryImpl @Inject constructor(
    private val api: UserApi,
    private val dao: UserDao,
    private val mapper: UserMapper
) : UserRepository {
    override fun observeUser(id: String): Flow<User> =
        dao.observeById(id).map(mapper::toDomain)

    override suspend fun syncUser(id: String): Result<Unit> = runCatching {
        val dto = api.getUser(id)
        dao.upsert(mapper.toEntity(dto))
    }
}

Enter fullscreen mode Exit fullscreen mode


Rule 6: Room for local persistence — no SharedPreferences for structured data

Local data:
- Room for all structured data. No raw SQLite.
- SharedPreferences / DataStore: only for simple key-value preferences (theme, onboarding flag).
- DataStore (Proto or Preferences): replace SharedPreferences for new code.
- Room DAOs: return Flow<T> for observed queries, suspend fun for mutations.
- Migrations: explicit RoomDatabase.Migration — never destructive migration in production.

Enter fullscreen mode Exit fullscreen mode

@Dao
interface UserDao {
    @Query("SELECT * FROM users WHERE id = :id")
    fun observeById(id: String): Flow<UserEntity?>

    @Upsert
    suspend fun upsert(user: UserEntity)

    @Query("DELETE FROM users WHERE id = :id")
    suspend fun deleteById(id: String)
}

Enter fullscreen mode Exit fullscreen mode


Rule 7: Navigation — Jetpack Navigation Compose with typed routes

Navigation:
- Jetpack Navigation Compose with type-safe routes (Navigation 2.8+).
- Routes: sealed class or @Serializable data class — no string literals.
- Single NavHost per feature graph. Nested graphs for feature modules.
- Navigate from ViewModel via UiEvent channel — not directly from Composable.
- Deep links: declared in NavGraph, not hardcoded in AndroidManifest.

Enter fullscreen mode Exit fullscreen mode


Rule 8: State management — immutable UiState, unidirectional data flow

State rules:
- UiState: immutable data class. Use copy() for updates.
- MutableStateFlow inside ViewModel, exposed as StateFlow (read-only).
- No mutableStateOf in ViewModel — use MutableStateFlow.
- Composables: collect with collectAsStateWithLifecycle() (lifecycle-aware).
- No shared mutable state between ViewModels.

Enter fullscreen mode Exit fullscreen mode

data class SearchUiState(
    val query: String = "",
    val results: List<SearchResult> = emptyList(),
    val isLoading: Boolean = false,
    val error: String? = null
)

// In ViewModel
_uiState.update { it.copy(isLoading = true) }

Enter fullscreen mode Exit fullscreen mode


Rule 9: Testing — ViewModel unit tests, Composable screenshot tests

Testing:
- ViewModel: JUnit 5 + MockK + Turbine (for Flow testing). No Android dependencies.
- Repository: JUnit 5 + MockK for unit tests. Room in-memory DB for integration.
- Composables: Compose UI test (composeTestRule) or Paparazzi for screenshot tests.
- No Robolectric for new tests — prefer pure JVM or instrumented tests.
- coroutinesTestRule: StandardTestDispatcher for deterministic coroutine tests.

Enter fullscreen mode Exit fullscreen mode

@Test
fun `search query updates state`() = runTest {
    val viewModel = SearchViewModel(mockRepository)
    viewModel.uiState.test {
        assertThat(awaitItem().query).isEmpty()
        viewModel.onQueryChanged("kotlin")
        assertThat(awaitItem().query).isEqualTo("kotlin")
    }
}

Enter fullscreen mode Exit fullscreen mode


Rule 10: Permissions — request at point of use, handle denial gracefully

Permissions:
- Request via rememberLauncherForActivityResult — never startActivityForResult.
- Check permission before use: ContextCompat.checkSelfPermission.
- Handle denial: show rationale UI, offer settings redirect after permanent denial.
- Never crash or silently fail on permission denial.
- Dangerous permissions: request only when the user triggers the action.

Enter fullscreen mode Exit fullscreen mode


Rule 11: API communication — Retrofit + OkHttp + kotlinx.serialization

Network:
- Retrofit for REST. OkHttp with logging interceptor (debug builds only).
- Serialization: kotlinx.serialization. No Gson, no Moshi.
- Response wrapper: Result<T> or sealed class — never nullable responses.
- Timeouts: explicit connect (10s), read (30s), write (30s) timeouts.
- Certificate pinning for production builds.

Enter fullscreen mode Exit fullscreen mode


Rule 12: Build config — Gradle Kotlin DSL, version catalog

Build:
- Gradle Kotlin DSL (.kts) only — no Groovy.
- Version catalog (libs.versions.toml) for all dependencies.
- Build variants: debug (logging, mock data) / release (ProGuard, no logging).
- No hardcoded API keys or secrets in BuildConfig — use local.properties + secrets-gradle-plugin.
- Baseline profiles for startup performance.

Enter fullscreen mode Exit fullscreen mode


Rule 13: The CLAUDE.md block for Android

## Android Standards

**Min SDK:** 26 | **Target SDK:** 35 | **Language:** Kotlin 2.x
**UI:** Jetpack Compose + Material3 only (no XML layouts)
**Architecture:** MVVM + Clean Architecture (presentation / domain / data)

### UI Layer
- Composables: stateless. State hoisted to ViewModel.
- UiState: immutable data class, exposed as StateFlow<UiState>
- Collect with collectAsStateWithLifecycle() — not collectAsState()
- One-time events: Channel<UiEvent> in ViewModel

### Data Layer
- Repository pattern: interface in domain, impl in data
- Room as source of truth. Network syncs to Room.
- Coroutines: suspend fun for one-shot, Flow for streams
- No callbacks, no RxJava, no AsyncTask

### DI
- Hilt exclusively. @HiltViewModel on all ViewModels.
- No manual DI, no Koin, no service locators.

### Testing
- ViewModel: JUnit 5 + MockK + Turbine
- No Robolectric. Pure JVM unit tests preferred.

### Build
- Gradle Kotlin DSL + version catalog (libs.versions.toml)
- No secrets in source code or BuildConfig

Enter fullscreen mode Exit fullscreen mode


Why Android specifically needs this

Android's API surface has been evolving continuously for 15 years. AI models have absorbed code from every era — from AsyncTask through RxJava to coroutines, from XML inflation through DataBinding to Compose.

Without explicit rules, the model defaults to the mean of that training distribution. That mean includes a lot of code that works on current Android but violates current best practices, creates maintenance debt, and will break when APIs are deprecated.

The rules above aren't a style guide. They're the line between code that a senior Android engineer would merge and code that gets sent back for a full rewrite.

The CLAUDE.md block at the end is what you add to your repo. The AI reads it at the start of every session, and every Composable, ViewModel, and repository it generates starts from those constraints rather than from the average of all Android code ever written.