Android16 应用代码新特性

Android16 应用代码新特性

文章目录

Android16应用代码对比Android15、14有啥代码差异?

Android 16 相对于 Android 15 和 14,在系统行为、API 接口、权限模型、性能优化等方面存在多处代码级差异,这些差异直接影响应用的兼容性和功能实现。

以下从核心场景对比具体代码变化,有兴趣的看看:

一、系统行为强制变更(代码适配差异)

1. 全屏布局机制
  • Android 14/15:可通过windowOptOutEdgeToEdgeEnforcement

    禁用全屏布局:xml

    xml 复制代码
    <!-- Android 14/15 可选配置 -->
    <style name="AppTheme">
        <item name="windowOptOutEdgeToEdgeEnforcement">true</item>
    </style>
    • Android 16:彻底移除该属性,所有应用默认强制全屏,需显式处理状态栏 / 导航栏遮挡:
kotlin/Java 复制代码
kotlin:
  // Android 16 必须添加的适配代码
val windowInsetsController = ViewCompat.getWindowInsetsController(window.decorView)
  windowInsetsController?.systemBarsBehavior = 
    WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
  
// 布局中设置 padding 避免内容被遮挡
  ViewCompat.setOnApplyWindowInsetsListener(yourView) { view, insets ->
    val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
      view.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
    insets
  }

  Java:
  // Android 16 窗口布局适配
  import androidx.core.view.WindowInsetsControllerCompat;
  import androidx.core.view.ViewCompat;
  import androidx.core.graphics.Insets;
  import androidx.core.view.WindowInsetsCompat;
  // 配置系统栏行为
  WindowInsetsControllerCompat windowInsetsController = new WindowInsetsControllerCompat(
      getWindow(), 
      getWindow().getDecorView()
  );
  windowInsetsController.setSystemBarsBehavior(
      WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
);
  windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());
  
  // 处理布局内边距
  View rootView = findViewById(R.id.root_view);
  ViewCompat.setOnApplyWindowInsetsListener(rootView, (view, insets) -> {
      Insets bars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
      view.setPadding(
          bars.left,
          bars.top,
          bars.right,
          bars.bottom
      );
      return insets;
  });
2. 预测返回导航
  • Android 14:仅手势导航支持预测返回,可通过onBackPressed() 兼容:

    kotlin 复制代码
    kotlin
    // Android 14 旧逻辑
    override fun onBackPressed() {
        super.onBackPressed() // 直接触发返回
    }
  • Android 15 :扩展至三键导航,但仍支持 onBackPressed() 降级;

  • Android 16:完全废弃onBackPressed() 和 KEYCODE_BACK

    强制使用新回调:

    kotlin 复制代码
    kotlin:
    // Android 16 必须使用的新逻辑
    onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
          // 处理返回逻辑(如弹窗确认)
            if (shouldFinish) finish()
          else isEnabled = false // 交给父级处理
        }
    })
    
    Java:
      // Android 16 返回导航
      import androidx.activity.OnBackPressedCallback;
      import androidx.lifecycle.LifecycleOwner;
    
      getOnBackPressedDispatcher().addCallback((LifecycleOwner) this, new OnBackPressedCallback(true) {
        @Override
    	public void handleOnBackPressed() {
            if (canGoBack()) {
                  finish(); // 处理返回
            } else {
                  showExitDialog(() -> setEnabled(false)); // 禁用回调,让系统处理
            }
          }
    	private boolean canGoBack() {
        // 判断是否可返回的逻辑
          return false;
    	}
      
          private void showExitDialog(Runnable onConfirm) {
         	 // 显示退出对话框,确认后调用 onConfirm
              onConfirm.run();
    		}
    });

在Android16 demo和手机上测试了一下,onBackPressed()回调还是可以在Activity监听,但是左滑退出没有回调了;

getOnBackPressedDispatcher().addCallback 左滑退出是有回调的,说明之前的onBackPressed()已经废弃了。

二、权限模型重构(代码声明差异)

1. 健康数据权限精细化
  • Android 14/15:通过BODY_SENSORS

    统一申请健康传感器权限:

    复制代码
    xml
    <!-- Android 14/15 权限声明 -->
    <uses-permission android:name="android.permission.BODY_SENSORS" />
  • Android 16:拆分为 12 个细分权限,需按需声明:

    xml 复制代码
    xml
    <!-- Android 16 权限声明 -->
    <uses-permission android:name="android.permission.READ_HEART_RATE" />
    <uses-permission android:name="android.permission.READ_BLOOD_PRESSURE" />
    <uses-permission android:name="android.permission.READ_HEALTH_DATA_IN_BACKGROUND" /> <!-- 后台访问需额外声明 -->

    代码中请求权限时也需对应调整:

    kotlin 复制代码
    kotlin
    // Android 16 权限请求
    registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        if (permissions[Manifest.permission.READ_HEART_RATE] == true) {
            // 访问心率传感器
      }
    }.launch(arrayOf(Manifest.permission.READ_HEART_RATE))
    
    Java
    // Android 16 健康权限请求
    import androidx.activity.result.ActivityResultLauncher;
    import androidx.activity.result.contract.ActivityResultContracts;
    import android.Manifest;
    import android.content.pm.PackageManager;
    // 注册权限请求回调
      private final ActivityResultLauncher<String[]> requestHealthPermissions =
        registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), permissions -> {
              if (permissions.getOrDefault(Manifest.permission.READ_HEART_RATE, false)) {
                startHeartRateMonitoring();
              }
        });
    
      // 发起权限请求
      public void requestHeartRatePermission() {
          if (checkSelfPermission(Manifest.permission.READ_HEART_RATE) 
                  != PackageManager.PERMISSION_GRANTED) {
              requestHealthPermissions.launch(new String[]{
                  Manifest.permission.READ_HEART_RATE
              });
        } else {
              startHeartRateMonitoring();
          }
      }
    
      private void startHeartRateMonitoring() {
          // 开始心率监测
      }
2. 剪贴板访问权限
  • Android 14/15:访问剪贴板无需特殊权限;

  • Android 16:必须申请READ_CLIPBOARD权限:

    复制代码
    xml
    <!-- Android 16 新增权限 -->
    <uses-permission android:name="android.permission.READ_CLIPBOARD" />

    代码中需先检查权限:

    kotlin
    // Android 16 剪贴板访问逻辑
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CLIPBOARD)
    == PackageManager.PERMISSION_GRANTED) {
    val clipboard = getSystemService(ClipboardManager::class.java)
    val text = clipboard.primaryClip?.getItemAt(0)?.text
    }

    Java
    // Android 16 剪贴板访问
    import android.content.ClipboardManager;
    import android.content.pm.PackageManager;
    import android.Manifest;
    import androidx.core.content.ContextCompat;

    public String getClipboardText() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CLIPBOARD)
    != PackageManager.PERMISSION_GRANTED) {
    // 未获得权限,请求权限或提示用户
    return null;
    }

    复制代码
       ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
     if (clipboard != null && clipboard.getPrimaryClip() != null 
               && clipboard.getPrimaryClip().getItemCount() > 0) {
         return clipboard.getPrimaryClip().getItemAt(0).getText().toString();
       }
     return null;

    }

三、API 接口重大变更(方法 / 类替换)

1. 生物识别认证分级
  • Android 14/15:通过 BIOMETRIC_STRONG

    标识强认证:

    kotlin
    // Android 14/15 生物识别
    val promptInfo = BiometricPrompt.PromptInfo.Builder()
    .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG)
    .build()

  • Android 16:引入 L1-L3 分级,支付场景强制 L3 级:

    kotlin 复制代码
    kotlin
    // Android 16 生物识别分级
    val promptInfo = BiometricPrompt.PromptInfo.Builder()
        .setAuthenticationLevel(BiometricManager.Authenticators.BIOMETRIC_LEVEL_3) // L3 活体检测
      .build()
    
    Java
      // Android 16 生物识别分级
    import androidx.biometric.BiometricPrompt;
      import androidx.core.content.ContextCompat;
    import java.util.concurrent.Executor;
    
    private void showBiometricPrompt() {
          Executor executor = ContextCompat.getMainExecutor(this);
          BiometricPrompt biometricPrompt = new BiometricPrompt(this, executor,
              new BiometricPrompt.AuthenticationCallback() {
                  @Override
                  public void onAuthenticationSucceeded(
                          BiometricPrompt.AuthenticationResult result) {
                    super.onAuthenticationSucceeded(result);
                      // 认证成功处理
                  }
              });
      BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
          .setTitle("确认支付")
          // 设置 L3 级认证(最高安全级)
          .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_LEVEL_3)
          .build();
      
      biometricPrompt.authenticate(promptInfo);
    }
2. Nearby Share 传输升级
  • Android 14/15:使用旧版 API 单设备传输:

    // Android 14/15 传输文件
    Nearby.getShareClient(context)
    .send(uri, deviceId)
    .addOnSuccessListener { /* 处理成功 */ }

  • Android 16:新增多设备并行传输 API(需 Wi-Fi 7 支持):

    复制代码
    kotlin
    // Android 16 多设备传输
    val transfer = Nearby.getShareClient(context)
        .createMultiDeviceTransfer(listOf(uri1, uri2), listOf(device1, device2))
    transfer.start().addOnSuccessListener { /* 处理成功 */ }
3. 内存管理优化
  • Android 14/15:默认 4KB 内存页,无显式配置;

  • Android 16:支持 16KB 内存页,旧应用需兼容:

    xml 复制代码
    xml
    <!-- Android 16 如需保留 4KB 页(不推荐) -->
    <application android:pageSizeCompat="4k" />

    代码中可判断设备支持类型:

    kotlin 复制代码
    kotlin
    // Android 16 内存页适配
    if (Build.VERSION.SDK_INT >= 36) {
        val pageSize = ActivityManager.getMemoryPageSize()
        if (pageSize == 16384) { // 16KB
            // 启用优化逻辑
        }
    }
    
    Java
      // Android 16 内存页适配
    import android.app.ActivityManager;
      import android.content.Context;
    import android.os.Build;
      import androidx.annotation.RequiresApi;
    
      @RequiresApi(api = Build.VERSION_CODES.JAVA16)
    private void adaptToMemoryPageSize() {
          ActivityManager activityManager = 
            (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
          int pageSize = activityManager.getMemoryPageSize();
        
    
          if (pageSize == 16384) { // 16KB 内存页
            // 启用大内存块优化逻辑
              optimizeForLargePages();
          } else {
              // 兼容 4KB 内存页的逻辑
              compatibilityWithSmallPages();
          }
    
      }
    
      private void optimizeForLargePages() {
          // 针对 16KB 内存页的优化
    }
    
      private void compatibilityWithSmallPages() {
          // 兼容 4KB 内存页的逻辑
      }

四、AI 与本地模型集成(新增 API)

  • Android 14/15:无系统级本地大模型 API;

  • Android 16:新增 Gemini Nano 本地模型接口:

    kotlin
    // Android 16 调用本地 AI 生成图片描述
    val gemini = GeminiSession.getInstance(context)
    val image = ImageDecoder.decodeBitmap(...)
    gemini.generateAltText(image)
    .addOnSuccessListener { altText ->
    // 用于无障碍标签或图片搜索
    imageView.contentDescription = altText
    }

    Java
    // Android 16 本地 AI 集成
    import android.graphics.Bitmap;
    import android.net.Uri;
    import android.os.Build;
    import androidx.annotation.RequiresApi;
    import com.google.android.gms.gemini.GeminiSession;
    import com.google.android.gms.tasks.OnSuccessListener;

    复制代码
    @RequiresApi(api = Build.VERSION_CODES.JAVA16)
    private void generateImageDescription(Uri imageUri) {
        try {
            // 解码图片
          Bitmap image = ImageDecoder.decodeBitmap(
                ImageDecoder.createSource(getContentResolver(), imageUri)
            );
            
            // 获取 Gemini 实例
            GeminiSession gemini = GeminiSession.getInstance(getApplicationContext());
            
            // 生成图片描述
            gemini.generateAltText(image)
                .addOnSuccessListener(altText -> {
                    // 设置无障碍描述
                    ImageView imageView = findViewById(R.id.image_view);
                    imageView.setContentDescription(altText);
                });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

五、广播与事件机制(安全性增强)

1. 动态广播导出状态强制声明
  • Android 14:动态注册广播未指定导出状态时默认导出,无报错;

  • Android 15:未指定时抛出警告;

  • Android 16:未指定时直接抛出 IllegalArgumentException,必须显式声明:

    kotlin 复制代码
    kotlin
    // Android 16 动态广播注册(必须指定导出状态)
    registerReceiver(
        myReceiver,
        IntentFilter("com.example.ACTION"),
        Context.RECEIVER_EXPORTED // 或 RECEIVER_NOT_EXPORTED
    )
    
    Java
      // Android 16 动态广播注册
    import android.content.BroadcastReceiver;
      import android.content.IntentFilter;
    import android.content.Context;
    
    private void registerMyReceiver() {
          BroadcastReceiver myReceiver = new MyReceiver();
        IntentFilter filter = new IntentFilter("com.example.ACTION");
          
    
        // 必须显式指定导出状态
          registerReceiver(
            myReceiver,
              filter,
              Context.RECEIVER_EXPORTED // 或 Context.RECEIVER_NOT_EXPORTED
          );
    
      }
    
      private class MyReceiver extends BroadcastReceiver {
          @Override
          public void onReceive(Context context, Intent intent) {
            // 处理广播
          }
      }
2. 有序广播废弃
  • Android 14/15 :仍可使用 sendOrderedBroadcast()

  • Android 16:标记为废弃,建议改用WorkManager:

    kotlin
    // Android 16 替代有序广播的方案
    WorkManager.getInstance(context)
    .beginWith(FirstWorker::class.java)
    .then(SecondWorker::class.java) // 按顺序执行
    .enqueue()

    复制代码
    Java

    / Android 16 WorkManager 替代有序广播
    import androidx.work.OneTimeWorkRequest;
    import androidx.work.WorkManager;
    import java.util.Arrays;

    复制代码
    private void executeOrderedTasks() {
      // 第一步任务
        OneTimeWorkRequest firstWork = new OneTimeWorkRequest.Builder(FirstWorker.class).build();
      
        // 第二步任务(依赖第一步)
      OneTimeWorkRequest secondWork = new OneTimeWorkRequest.Builder(SecondWorker.class).build();
        
      // 按顺序执行
        WorkManager.getInstance(this)
            .beginWith(firstWork)
            .then(secondWork)
            .enqueue();
    }
    
    // 定义 Worker 类

    import androidx.work.Worker;
    import androidx.work.WorkerParameters;

    复制代码
    public class FirstWorker extends Worker {
        public FirstWorker(Context context, WorkerParameters params) {
            super(context, params);
        }
        
        @Override
        public Result doWork() {
            // 执行第一步任务
            return Result.success();
        }
    }
    
    public class SecondWorker extends Worker {
        public SecondWorker(Context context, WorkerParameters params) {
            super(context, params);
        }
        
        @Override
        public Result doWork() {
            // 执行第二步任务
            return Result.success();
        }
    }

六、开发者工具链(依赖与语法变更)

1. Jetpack Compose 版本强制升级
  • Android 14/15:支持 Compose 1.x/2.x;

  • Android 16:强制使用 Compose 3.0,部分 API 不兼容:

    kotlin 复制代码
    kotlin
    // Android 14/15 旧列表组件
    LazyColumn {
        items(dataList) { item -> Text(item) }
    }
    // Android 16 新列表组件(性能优化)
      LazyColumnV2 {
        items(dataList) { item -> Text(item) }
      }
2. 编译工具要求
  • Android 14/15:最低支持 AGP 7.0;

  • Android 16:最低要求 AGP 8.5,且必须使用 Java 17 编译:

    gradle
    // Android 16 模块级 build.gradle 配置
    android {
    compileSdk 36
    buildToolsVersion "36.0.0"
    compileOptions {
    sourceCompatibility JavaVersion.VERSION_17
    targetCompatibility JavaVersion.VERSION_17
    }
    }

七、总结:核心差异领域

维度 Android 14/15 状态 Android 16 变更点
系统行为 可禁用全屏、支持旧返回逻辑 强制全屏、废弃 onBackPressed()
权限模型 健康数据 / 剪贴板无细分权限 权限精细化、新增 READ_CLIPBOARD
核心 API 生物识别单级、单设备传输 生物识别分级、多设备传输 API
性能优化 4KB 内存页、传统调度 16KB 内存页、Project Quantum 引擎
AI 集成 无系统级本地模型 新增 Gemini Nano 接口
开发工具 支持旧版 Compose/AGP 强制 Compose 3.0、AGP 8.5、Java 17

适配时需重点关注权限声明更新系统行为强制变更废弃 API 迁移

建议结合官方迁移工具(如 Android Studio 的 lint 检查)批量定位代码差异点。

总的来说感觉变更Android16后,需要适配的实际代码很少,

因为很多功能基本没啥用过,比如AI集成,性能优化,生物识别等,都是不常用的;

返回按键那个功能是要适配一下的,毕竟之前的回调方法没用了,要用新的api方法了。

Android16还有另外的差异吗,肯定是有的,比如系统HIDL在Android16不支持了!那咋搞?

要用AIDL。 Android11新增了可以绑定底层的AIDL (C++ 绑定) 功能适配。

这个算是系统代码实现差异;另外说明。

本文的主要内容,算是应用代码功能使用差异。

相关推荐
车载测试工程师14 小时前
CAPL学习-SOME/IP交互层-符号数据库访问类函数
学习·tcp/ip·以太网·capl·canoe
BD_Marathon14 小时前
Vue3_简介和快速体验
开发语言·javascript·ecmascript
摇滚侠14 小时前
面试实战 问题三十四 对称加密 和 非对称加密 spring 拦截器 spring 过滤器
java·spring·面试
xqqxqxxq14 小时前
Java 集合框架之线性表(List)实现技术笔记
java·笔记·python
L0CK15 小时前
RESTful风格解析
java
程序员小假15 小时前
我们来说说 ThreadLocal 的原理,使用场景及内存泄漏问题
java·后端
何中应15 小时前
LinkedHashMap使用
java·后端·缓存
tryxr15 小时前
Java 多线程标志位的使用
java·开发语言·volatile·内存可见性·标志位
暗然而日章15 小时前
C++基础:Stanford CS106L学习笔记 13 特殊成员函数(SMFs)
c++·笔记·学习
talenteddriver15 小时前
java: Java8以后hashmap扩容后根据高位确定元素新位置
java·算法·哈希算法