compileSdkVersion26+下FragmentTransaction.add崩溃,求适配33的解决办法
适配compileSdkVersion 33的动态权限请求修复方案
崩溃原因分析
在API 26及以上版本中,Android对Fragment事务管理做了严格限制:直接添加无布局的匿名Fragment到事务且不指定容器ID会触发崩溃,这就是你在fragmentTransaction.add(0, request)处报错的核心原因。另外原代码依赖的android-support-v4.jar已被废弃,SDK33需使用AndroidX库替代,同时Android 13(SDK33)的存储权限规则也有更新。
修复步骤与代码示例
1. 迁移到AndroidX(必须操作)
将项目中的android-support-v4.jar替换为AndroidX依赖,在Module级别的build.gradle中添加:
dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.fragment:fragment:1.6.1' }
同时确保gradle.properties中开启AndroidX兼容:
android.useAndroidX=true android.enableJetifier=true
2. 重构权限请求逻辑(两种可选方案)
方案一:直接在Activity中请求权限(新手友好,最简单)
无需借助匿名Fragment,直接在Activity中调用权限API,彻底避免Fragment事务问题:
import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import android.Manifest; import android.content.pm.PackageManager; import android.os.Build; import java.util.ArrayList; import java.util.List; public class YourActivity extends AppCompatActivity { private static final int REQUEST_CODE_PERMISSIONS = 100; private String responseStateStr; public void askPermissions() { List<String> permissionsList = new ArrayList<>(); // 适配Android 13+存储权限规则 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) { permissionsList.add(Manifest.permission.READ_MEDIA_IMAGES); } // Android 13+针对媒体文件无需单独申请写权限 } else { if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { permissionsList.add(Manifest.permission.READ_EXTERNAL_STORAGE); } if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { permissionsList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); } } if (!permissionsList.isEmpty()) { ActivityCompat.requestPermissions(this, permissionsList.toArray(new String[0]), REQUEST_CODE_PERMISSIONS); } else { responseStateStr = "Granted"; } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_CODE_PERMISSIONS) { boolean allGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allGranted = false; break; } } responseStateStr = allGranted ? "Granted" : "Denied"; // 这里可添加权限结果后的业务逻辑 } } }
方案二:使用DialogFragment(保留Fragment请求方式)
如果必须基于Fragment实现,改用DialogFragment(无需指定容器ID):
import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.DialogFragment; import androidx.core.content.ContextCompat; import android.Manifest; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import java.util.ArrayList; import java.util.List; public class YourActivity extends AppCompatActivity { private String responseStateStr; public void askPermissions() { List<String> permissionsList = new ArrayList<>(); // 权限检查逻辑同方案一... if (permissionsList.isEmpty()) { responseStateStr = "Granted"; return; } PermissionDialogFragment dialogFragment = PermissionDialogFragment.newInstance(permissionsList); dialogFragment.show(getSupportFragmentManager(), "PermissionDialog"); } // 自定义无UI的DialogFragment public static class PermissionDialogFragment extends DialogFragment { private static final String ARG_PERMISSIONS = "permissions"; private static final int REQUEST_CODE_PERMISSIONS = 100; public static PermissionDialogFragment newInstance(List<String> permissions) { PermissionDialogFragment fragment = new PermissionDialogFragment(); Bundle args = new Bundle(); args.putStringArrayList(ARG_PERMISSIONS, new ArrayList<>(permissions)); fragment.setArguments(args); return fragment; } @Override public void onStart() { super.onStart(); List<String> permissions = getArguments().getStringArrayList(ARG_PERMISSIONS); requestPermissions(permissions.toArray(new String[0]), REQUEST_CODE_PERMISSIONS); // 隐藏对话框,不需要显示UI getDialog().hide(); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_CODE_PERMISSIONS) { boolean allGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allGranted = false; break; } } // 通知外部权限结果 ((YourActivity) getActivity()).responseStateStr = allGranted ? "Granted" : "Denied"; dismiss(); } } } }
额外注意事项
- Android 13(SDK33)中,
READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE已被废弃,针对媒体文件需使用READ_MEDIA_IMAGES、READ_MEDIA_VIDEO等细分权限;针对非媒体文件的读写,需使用MANAGE_EXTERNAL_STORAGE权限(需引导用户到设置页开启)。 - 如果用户拒绝权限并勾选「不再询问」,需引导用户进入应用设置页手动开启权限。
内容的提问来源于stack exchange,提问作者danka
相关产品推荐
相关产品推荐

