零基础如何入门安卓开发?安卓开发博客从入门到精通
打造一款精致的安卓天气应用是掌握现代安卓开发核心技术的绝佳实践,本教程将引导你使用最新的Jetpack组件和Kotlin协程,构建一个功能完整、架构清晰的应用。
开发环境与基础配置
-
工具准备:
- 安装最新AndroidStudioHedgehog(2026.1.1)或更高版本。
- 确保AndroidSDK包含API级别34(Android14)及常用低版本(如API28)。
- 使用Kotlin1.9.0或更高版本。
-
项目初始化:
- 新建项目,选择“EmptyActivity”模板。
- 项目命名:
WeatherWise,包名自定义(如com.yourdomain.weatherwise)。 - 语言选择Kotlin。
- MinimumSDK:建议API23(Android6.0Marshmallow)以平衡功能和覆盖率。
-
核心依赖添加(
build.gradle.kts(Module:app)):dependencies{//AndroidXCoreimplementation("androidx.core:core-ktx:1.12.0")implementation("androidx.appcompat:appcompat:1.6.1")implementation("com.google.android.material:material:1.11.0")implementation("androidx.constraintlayout:constraintlayout:2.1.4")//Lifecycle(ViewModel&LiveData)implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.2")implementation("androidx.activity:activity-ktx:1.8.2")//Coroutinesimplementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")//Retrofit&Moshi(网络请求&JSON解析)implementation("com.squareup.retrofit2:retrofit:2.9.0")implementation("com.squareup.retrofit2:converter-moshi:2.9.0")implementation("com.squareup.moshi:moshi-kotlin:1.15.0")implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")//网络日志//Coil(图片加载)implementation("io.coil-kt:coil:2.5.0")//LocationServices(PlayServices)implementation("com.google.android.gms:play-services-location:21.0.1")//Hilt(依赖注入-可选但强烈推荐)implementation("com.google.dagger:hilt-android:2.48.1")kapt("com.google.dagger:hilt-android-compiler:2.48.1")}
- 同步Gradle。
核心功能实现(MVVM架构)
-
数据层(Repository&DataSource)
- API接口(
WeatherApiService.kt):interfaceWeatherApiService{@GET("data/2.5/weather")suspendfungetCurrentWeather(@Query("lat")latitude:Double,@Query("lon")longitude:Double,@Query("units")units:String="metric",//公制单位@Query("appid")apiKey:String=YOUR_API_KEY//替换为真实Key):Response<WeatherResponse>} - 数据模型(
WeatherResponse.kt,WeatherData.kt等):根据API返回的JSON结构定义Kotlin数据类(使用@JsonClass(generateAdapter=true)配合Moshi)。 - Repository(
WeatherRepository.kt):classWeatherRepository@Injectconstructor(privatevalapiService:WeatherApiService){suspendfungetCurrentWeather(lat:Double,lon:Double):Result<WeatherData>{returntry{valresponse=apiService.getCurrentWeather(lat,lon)if(response.isSuccessful&&response.body()!=null){Result.Success(response.body()!!.toWeatherData())//转换API模型为领域模型}else{Result.Error(Exception("APIerror:${response.code()}${response.message()}"))}}catch(e:Exception){Result.Error(e)}}sealedclassResult<outT>{dataclassSuccess<outT>(valdata:T):Result<T>()dataclassError(valexception:Exception):Result<Nothing>()}}
- API接口(
-
领域层(UseCases–可选但推荐)
- 封装特定业务逻辑。
GetCurrentWeatherUseCase调用Repository。
- 封装特定业务逻辑。
-
ViewModel层(
WeatherViewModel.kt)@HiltViewModelclassWeatherViewModel@Injectconstructor(privatevalgetWeatherUseCase:GetCurrentWeatherUseCase,privatevallocationClient:LocationClient//自定义位置服务封装):ViewModel(){privateval_weatherState=MutableStateFlow<WeatherUiState>(WeatherUiState.Loading)valweatherState:StateFlow<WeatherUiState>=_weatherStateinit{fetchLocationAndWeather()}privatefunfetchLocationAndWeather(){viewModelScope.launch{locationClient.getCurrentLocation().collect{locationResult->when(locationResult){isLocationResult.Success->{fetchWeather(locationResult.location.latitude,locationResult.location.longitude)}isLocationResult.Error->{_weatherState.value=WeatherUiState.Error(locationResult.exception.message?:"Unknownlocationerror")}}}}}privatesuspendfunfetchWeather(lat:Double,lon:Double){_weatherState.value=WeatherUiState.Loadingwhen(valresult=getWeatherUseCase(lat,lon)){isWeatherRepository.Result.Success->{_weatherState.value=WeatherUiState.Success(result.data)}isWeatherRepository.Result.Error->{_weatherState.value=WeatherUiState.Error(result.exception.message?:"Unknownweathererror")}}}funretry(){fetchLocationAndWeather()}sealedclassWeatherUiState{objectLoading:WeatherUiState()dataclassSuccess(valdata:WeatherData):WeatherUiState()dataclassError(valmessage:String?):WeatherUiState()}} -
UI层(Compose或ViewBinding)
-
使用JetpackCompose(
WeatherScreen.kt–推荐):@ComposablefunWeatherScreen(viewModel:WeatherViewModel=hiltViewModel()){valweatherStatebyviewModel.weatherState.collectAsStateWithLifecycle()Column(modifier=Modifier.fillMaxSize().padding(16.dp),horizontalAlignment=Alignment.CenterHorizontally){when(valstate=weatherState){isWeatherViewModel.WeatherUiState.Loading->CircularProgressIndicator()isWeatherViewModel.WeatherUiState.Success->{WeatherInfoDisplay(state.data)}isWeatherViewModel.WeatherUiState.Error->{Text(text="Error:${state.message}",color=Color.Red)Button(onClick={viewModel.retry()}){Text("Retry")}}}}}
@Composable
funWeatherInfoDisplay(weatherData:WeatherData){
//使用Coil加载天气图标
AsyncImage(
model=“https://openweathermap.org/img/wn/${weatherData.iconCode}@4x.png”,
contentDescription=weatherData.description,
modifier=Modifier.size(120.dp)
)
Text(text=“${weatherData.temperature}°C”,style=MaterialTheme.typography.displayMedium)
Text(text=weatherData.description,style=MaterialTheme.typography.titleMedium)
Text(text=weatherData.locationName,style=MaterialTheme.typography.bodyLarge)
//显示更多数据:湿度、风速、气压等…
}使用ViewBinding(XML):在`Activity`/`Fragment`中观察`ViewModel`的`LiveData`/`StateFlow`并更新UI。 -
-
位置服务(
LocationClient.kt):- 封装
FusedLocationProviderClient,处理权限请求和位置获取回调,返回Flow<LocationResult>。关键点:妥善处理ACCESS_FINE_LOCATION/ACCESS_COARSE_LOCATION权限的动态申请。
- 封装
架构优化与进阶技巧
-
依赖注入(Hilt):
- 使用Hilt管理
ApiService,Repository,UseCase,ViewModel,LocationClient等依赖项的生命周期和注入,大幅提升代码可测试性和可维护性,在Application类上添加@HiltAndroidApp。
- 使用Hilt管理
-
响应式UI&状态管理:
- Compose:充分利用
StateFlow/State和remember/derivedStateOf管理UI状态,保证UI与数据源同步。 - ViewSystem:使用
LiveData或StateFlow配合LifecycleOwner安全更新UI。
- Compose:充分利用
-
错误处理与用户体验:
- 在
Repository和ViewModel中捕获异常,转换为用户友好的错误状态(WeatherUiState.Error)。 - 提供明确的加载状态(
WeatherUiState.Loading)和重试机制(retry()函数)。 - 处理网络不可用情况(利用
ConnectivityManager或OkHttp拦截器检查网络状态)。
- 在
-
离线支持(可选):
- 引入Room数据库缓存最近的天气数据和位置信息。
- Repository优先从本地缓存读取数据,同时发起网络请求更新缓存,ViewModel可展示缓存数据作为占位或离线状态。
-
测试:
- UnitTests(JUnit):测试
ViewModel逻辑(使用TestCoroutineDispatcher)、Repository方法、数据转换、UseCases。 - InstrumentedTests(Espresso/ComposeTest):测试UI交互和状态变化,Mock网络层和位置服务。
- UnitTests(JUnit):测试
发布准备
-
代码混淆(R8):
- 在
build.gradle.kts(Module:app)中启用minifyEnabledtrue。 - 配置ProGuard/Rules(
proguard-rules.pro)保留必要的类(如Retrofit接口、数据模型、Hilt组件),使用@Keep注解。
- 在
-
应用签名:
- 使用AndroidStudio生成或导入签名密钥库(Keystore)。
- 在
build.gradle.kts中配置签名信息(避免将密码硬编码在版本控制中)。
-
资源优化:
- 移除未使用的资源(
shrinkResourcestrue)。 - 为不同屏幕密度提供合适的图片资源。
- 移除未使用的资源(
-
持续集成/持续部署(CI/CD):使用GitHubActions、GitLabCI或Jenkins自动化构建、测试和发布流程。
通过这个项目,你实践了现代安卓开发的精髓:Kotlin协程处理异步、Jetpack组件构建健壮架构、Retrofit进行网络通信、依赖注入管理复杂度,以及Compose构建声明式UI,持续关注AndroidDevelopers官方文档和Kotlin协程指南是保持技术领先的关键。
你的挑战:在实现基础功能后,你会优先添加哪个进阶特性来提升应用价值?是更详细的多天预报、城市搜索收藏功能、天气预警通知,还是深度集成系统主题的动态换肤?分享你的想法在评论区,一起探讨最优解!