前言:为什么要了解每个版本特性?
作为 Android 开发者,我们经常遇到这样的问题:
-
"这个 API 为什么需要特定版本?"
-
"这个特性到底解决了什么实际问题?"
-
"我应该在什么场景下使用它?"
本文将深入解析每个 Android 版本的核心特性,告诉你它们是什么 、为什么需要 以及怎么用。
一、Android 6.0 (API 23) - 用户隐私觉醒
特性1:运行时权限 (Runtime Permissions)
是什么 :应用在运行时向用户请求权限,而不是在安装时一次性授予所有权限。
为什么要用:
-
用户可控:用户可以按需授予权限,用哪个功能给哪个权限
-
透明化:用户清楚知道应用什么时候需要什么权限
-
安全:恶意应用无法在用户不知情时获取敏感权限
实际用法:
// 传统方式(已废弃):安装时一次性获得所有权限
// 新方式:使用时按需请求
class CameraActivity : AppCompatActivity() {
// 步骤1:检查是否已有权限
private fun checkCameraPermission(): Boolean {
return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) ==
PackageManager.PERMISSION_GRANTED
}
// 步骤2:请求权限
private fun requestCameraPermission() {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
REQUEST_CODE_CAMERA
)
}
// 步骤3:处理用户选择
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
if (requestCode == REQUEST_CODE_CAMERA && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 用户同意了,可以打开相机
openCamera()
} else {
// 用户拒绝了,显示解释或禁用功能
showPermissionDeniedMessage()
}
}
fun openCamera() {
if (checkCameraPermission()) {
// 有权限,直接打开相机
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(intent, REQUEST_CAMERA)
} else {
// 没有权限,先请求权限
requestCameraPermission()
}
}
}
现实场景:微信扫码支付时,只有当你点击"扫码"时才请求相机权限,而不是安装时就要求相机权限。
二、Android 7.0 (API 24) - 多任务处理进化
特性1:多窗口模式 (Multi-Window)
是什么:允许两个应用同时在一个屏幕上运行,分为分屏、画中画、自由窗口三种模式。
为什么要用:
-
提升效率:用户可以边看视频边回消息
-
更好的用户体验:应用需要适配不同尺寸和比例
实际用法:
class VideoPlayerActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 声明支持多窗口
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// 启用画中画模式
if (!isInPictureInPictureMode) {
// 配置多窗口属性
enterPictureInPictureModeIfSupported()
}
}
}
// 处理配置变化(窗口尺寸改变时调用)
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// 根据新配置重新布局
when {
isInMultiWindowMode -> layoutForMultiWindow()
isInPictureInPictureMode -> layoutForPipMode()
else -> layoutForFullScreen()
}
}
private fun layoutForPipMode() {
// 画中画模式:简化UI,只保留核心内容
binding.controlPanel.visibility = View.GONE
binding.videoView.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
}
private fun layoutForMultiWindow() {
// 分屏模式:适配窄屏布局
binding.controlPanel.visibility = View.VISIBLE
binding.videoView.layoutParams.height = resources.getDimensionPixelSize(R.dimen.multi_window_height)
}
}
现实场景:YouTube 视频在切换到其他应用时自动进入画中画模式,让你可以边看视频边做其他事情。
三、Android 8.0 (API 26) - 通知与后台管理
特性1:通知渠道 (Notification Channels)
是什么:将通知按类别分组,用户可以对不同类别的通知进行精细化管理。
为什么要用:
-
用户可控:用户可以关闭营销通知但保留重要消息
-
分类明确:不同用途的通知分开管理
-
提升体验:减少无关通知对用户的打扰
实际用法:
class NotificationManager {
fun setupNotificationChannels() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// 创建重要消息渠道(高优先级)
val importantChannel = NotificationChannel(
"important_messages", // 渠道ID
"重要消息", // 用户看到的名称
NotificationManager.IMPORTANCE_HIGH // 高重要性(有声音和弹出)
).apply {
description = "订单状态、支付提醒等重要消息"
enableLights(true)
lightColor = Color.RED
}
// 创建营销消息渠道(低优先级)
val promotionChannel = NotificationChannel(
"promotions",
"促销活动",
NotificationManager.IMPORTANCE_LOW // 低重要性(只在通知栏显示)
).apply {
description = "优惠活动、新品推荐等消息"
}
// 注册渠道
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannels(listOf(importantChannel, promotionChannel))
}
}
fun sendOrderNotification(orderId: String) {
// 使用重要消息渠道发送通知
val notification = NotificationCompat.Builder(this, "important_messages")
.setContentTitle("订单更新")
.setContentText("订单 $orderId 已发货")
.setSmallIcon(R.drawable.ic_shipping)
.setAutoCancel(true)
.build()
NotificationManagerCompat.from(this).notify(orderId.hashCode(), notification)
}
fun sendPromotionNotification() {
// 使用营销渠道发送通知
val notification = NotificationCompat.Builder(this, "promotions")
.setContentTitle("限时优惠")
.setContentText("全场商品8折优惠")
.setSmallIcon(R.drawable.ic_promotion)
.setAutoCancel(true)
.build()
NotificationManagerCompat.from(this).notify("promotion".hashCode(), notification)
}
}
现实场景:淘宝App中,订单物流通知会响铃提醒,而商品推荐通知只静默显示在通知栏。
四、Android 10 (API 29) - 隐私保护重大升级
特性1:分区存储 (Scoped Storage)
是什么:应用只能访问自己的专属目录和特定类型的公共文件(如照片、音乐),不能随意访问整个存储空间。
为什么要用:
-
隐私保护:防止应用偷偷读取用户的私人文件
-
数据安全:每个应用的数据相互隔离
-
文件管理:用户清楚知道每个应用存储了什么
实际用法:
class FileManager {
// 错误做法:直接访问任意路径(Android 10+ 已禁止)
fun saveFileWrongWay(): Boolean {
// 这行代码在 Android 10+ 会报错!
val file = File("/sdcard/Download/myfile.txt")
return file.writeText("hello")
}
// 正确做法:使用 MediaStore API
fun saveImageToGallery(bitmap: Bitmap): Boolean {
val contentValues = ContentValues().apply {
// 文件信息
put(MediaStore.Images.Media.DISPLAY_NAME, "my_photo_${System.currentTimeMillis()}.jpg")
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
put(MediaStore.Images.Media.IS_PENDING, 1) // 标记为处理中
}
// 获取图片集合的URI
val collection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
} else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
// 插入新图片记录
val uri = contentResolver.insert(collection, contentValues) ?: return false
return try {
// 写入图片数据
contentResolver.openOutputStream(uri).use { outputStream ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
}
// 标记为完成
contentValues.clear()
contentValues.put(MediaStore.Images.Media.IS_PENDING, 0)
contentResolver.update(uri, contentValues, null, null)
true
} catch (e: Exception) {
// 失败时删除记录
contentResolver.delete(uri, null, null)
false
}
}
// 读取图片(需要权限)
fun loadImagesFromGallery(): List<Bitmap> {
val images = mutableListOf<Bitmap>()
val projection = arrayOf(MediaStore.Images.Media._ID)
val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC"
contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
null,
null,
sortOrder
)?.use { cursor ->
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
while (cursor.moveToNext()) {
val id = cursor.getLong(idColumn)
val contentUri = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id
)
try {
contentResolver.openInputStream(contentUri)?.use { inputStream ->
BitmapFactory.decodeStream(inputStream)?.let { bitmap ->
images.add(bitmap)
}
}
} catch (e: SecurityException) {
// 没有权限访问这个文件
Log.w("FileManager", "No permission to access image: $contentUri")
}
}
}
return images
}
}
现实场景:微信保存图片到相册时,使用系统提供的保存接口,而不是直接往SD卡写文件。
五、Android 12 (API 31) - 用户体验革新
特性1:Material You 动态色彩
是什么:系统从壁纸中提取颜色主题,并应用到所有支持的应用上。
为什么要用:
-
个性化:每个用户的手机都有独特的色彩主题
-
一致性:所有应用保持统一的视觉风格
-
沉浸感:应用与系统界面完美融合
实际用法:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 应用动态色彩主题
applyDynamicColors()
setContentView(R.layout.activity_main)
}
private fun applyDynamicColors() {
// Android 12+ 支持动态色彩
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// 使用动态色彩主题
setTheme(R.style.Theme_MyApp_Dynamic)
// 监听动态色彩变化
val dynamicColors = DynamicColors()
dynamicColors.applyIfAvailable(this)
} else {
// 旧版本使用静态主题
setTheme(R.style.Theme_MyApp_Static)
}
}
}
// styles.xml 中的主题配置
<!-- 动态色彩主题(Android 12+) -->
<style name="Theme.MyApp.Dynamic" parent="Theme.Material3.DynamicColors.DayNight">
<!-- 系统会自动应用动态色彩 -->
</style>
<!-- 静态主题(Android 11及以下) -->
<style name="Theme.MyApp.Static" parent="Theme.MaterialComponents.DayNight">
<item name="colorPrimary">@color/static_primary</item>
<item name="colorSecondary">@color/static_secondary</item>
<item name="colorSurface">@color/static_surface</item>
</style>
现实场景:当用户更换手机壁纸时,Google 应用、Messages 等系统应用的颜色会自动匹配壁纸色调。
六、Android 13 (API 33) - 精细化权限控制
特性1:通知权限 (POST_NOTIFICATIONS)
是什么:应用发送通知需要用户显式授权,而不仅仅是创建通知渠道。
为什么要用:
-
用户控制:用户可以完全阻止某个应用发送任何通知
-
减少骚扰:避免应用滥用通知功能
-
透明化:用户清楚知道哪个应用想要发送通知
实际用法:
class NotificationPermissionHelper {
fun checkAndRequestNotificationPermission(activity: Activity) {
// Android 13+ 需要单独的通知权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
when {
// 已经有权限
isNotificationPermissionGranted(activity) -> {
setupNotificationChannels()
startNotificationService()
}
// 应该显示解释
shouldShowRequestPermissionRationale(activity) -> {
showPermissionExplanation(activity) {
requestNotificationPermission(activity)
}
}
// 第一次请求
else -> {
requestNotificationPermission(activity)
}
}
} else {
// Android 12及以下不需要单独权限
setupNotificationChannels()
startNotificationService()
}
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun isNotificationPermissionGranted(context: Context): Boolean {
return NotificationManagerCompat.from(context).areNotificationsEnabled()
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun requestNotificationPermission(activity: Activity) {
val requestPermissionLauncher = activity.registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
// 用户允许通知,设置渠道并启动服务
setupNotificationChannels()
startNotificationService()
} else {
// 用户拒绝通知,禁用相关功能
disableNotificationFeatures()
showNotificationDisabledMessage()
}
}
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
private fun showPermissionExplanation(activity: Activity, onContinue: () -> Unit) {
AlertDialog.Builder(activity)
.setTitle("需要通知权限")
.setMessage("为了及时向您推送订单状态、物流信息等重要消息,需要您允许通知权限。")
.setPositiveButton("允许") { _, _ -> onContinue() }
.setNegativeButton("拒绝", null)
.show()
}
}
现实场景:新安装的银行App第一次启动时,会弹窗解释为什么需要通知权限(交易提醒、安全通知等),然后请求授权。
七、Android 14 (API 34) - 国际化与可访问性
特性1:语法性别支持 (Grammatical Gender)
是什么:根据语言语法性别(阳性、阴性、中性)显示不同的文本格式。
为什么要用:
-
语言准确性:在某些语言中,形容词、动词需要与主语性别一致
-
本地化质量:提升非英语用户的体验
-
文化适配:尊重不同语言的语法规则
实际用法:
class InternationalizationHelper {
fun getLocalizedMessage(context: Context, userName: String, productCount: Int): String {
val resources = context.resources
val configuration = resources.configuration
// Android 14+ 支持语法性别
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
when (configuration.grammaticalGender) {
Configuration.GRAMMATICAL_GENDER_FEMININE -> {
resources.getQuantityString(R.plurals.message_female, productCount, userName, productCount)
}
Configuration.GRAMMATICAL_GENDER_MASCULINE -> {
resources.getQuantityString(R.plurals.message_male, productCount, userName, productCount)
}
Configuration.GRAMMATICAL_GENDER_NEUTER -> {
resources.getQuantityString(R.plurals.message_neuter, productCount, userName, productCount)
}
else -> {
resources.getQuantityString(R.plurals.message_unknown, productCount, userName, productCount)
}
}
} else {
// 旧版本使用通用格式
resources.getQuantityString(R.plurals.message_generic, productCount, userName, productCount)
}
}
}
// strings.xml 中的多性别支持
<resources>
<!-- 阴性(如法语、西班牙语中的女性用户) -->
<plurals name="message_female">
<item quantity="one">%1$s a acheté un produit. Elle est satisfaite.</item>
<item quantity="other">%1$s a acheté %2$d produits. Elle est satisfaite.</item>
</plurals>
<!-- 阳性(男性用户) -->
<plurals name="message_male">
<item quantity="one">%1$s a acheté un produit. Il est satisfait.</item>
<item quantity="other">%1$s a acheté %2$d produits. Il est satisfait.</item>
</plurals>
<!-- 中性(英语等不需要性别的语言) -->
<plurals name="message_neuter">
<item quantity="one">%1$s bought one product. They are satisfied.</item>
<item quantity="other">%1$s bought %2$d products. They are satisfied.</item>
</plurals>
</resources>
现实场景:在法语中,如果用户是女性,需要说"Elle est satisfaite"(她满意),而男性则是"Il est satisfait"(他满意)。
八、Android 15+ - 未来特性展望
特性1:性能等级 API (Performance Class)
是什么:系统告诉应用当前设备的性能等级,应用可以根据设备能力调整功能。
为什么要用:
-
性能优化:低端设备使用简化功能,高端设备使用高级功能
-
省电:避免在低端设备上运行耗电的功能
-
体验适配:不同设备提供最适合的体验
实际用法:
class PerformanceOptimizer {
fun optimizeForDevice(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val performanceManager = context.getSystemService(Context.PERFORMANCE_SERVICE) as PerformanceManager
val performanceClass = performanceManager.performanceLevel
when (performanceClass) {
PerformanceManager.PERFORMANCE_LEVEL_LOW -> {
// 低端设备:启用简化模式
enableLiteMode()
disableHeavyAnimations()
useLowResolutionAssets()
}
PerformanceManager.PERFORMANCE_LEVEL_MEDIUM -> {
// 中端设备:平衡模式
enableStandardFeatures()
useMediumAnimations()
}
PerformanceManager.PERFORMANCE_LEVEL_HIGH -> {
// 高端设备:全功能模式
enableAllFeatures()
useHighEndGraphics()
enableAIFeatures()
}
else -> {
// 未知设备:使用默认配置
enableStandardFeatures()
}
}
} else {
// 旧版本:基于内存和CPU手动检测
optimizeManually()
}
}
private fun enableLiteMode() {
// 简化UI,减少动画,使用缓存策略
binding.animationsEnabled = false
binding.imageQuality = ImageQuality.LOW
CacheStrategy.enableAggressiveCaching()
}
private fun enableAllFeatures() {
// 启用所有高级功能
binding.animationsEnabled = true
binding.imageQuality = ImageQuality.HIGH
AIManager.enableRealtimeProcessing()
}
}
现实场景:游戏在高性能手机上开启120帧模式和高级光影效果,在低端手机上锁定30帧并降低画质。
总结:Android 版本演进的核心逻辑
版本 | 核心目标 | 开发者需要做的 |
---|---|---|
6.0 | 用户隐私控制 | 适配运行时权限请求 |
7.0 | 多任务效率 | 支持多窗口布局适配 |
8.0 | 通知管理 | 实现通知渠道分类 |
10 | 数据隐私 | 使用分区存储API |
12 | 个性化体验 | 支持动态色彩主题 |
13 | 权限精细化 | 请求通知权限 |
14 | 国际化 | 适配语法性别 |