部分设备授予WRITE_EXTERNAL_STORAGE权限后App意外崩溃求助
我仔细看了你的代码,发现两个核心问题导致了点击"允许"后App崩溃、重启后正常的现象:
1. 权限检查与申请完全不匹配!
你在checkIfAlreadyhavePermission()里检查的是GET_ACCOUNTS权限,但实际申请的却是WRITE_EXTERNAL_STORAGE。这种逻辑错误会导致权限判断完全混乱——即使用户允许了存储权限,你的检查方法还是会认为权限未授予(因为它在验证账户权限)。重启后正常可能是因为设备上恰好已经有了GET_ACCOUNTS权限,或者重启时没有触发权限申请流程。
先把权限检查修正为和申请一致的类型:
private boolean checkIfAlreadyhavePermission() { int result = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE); return result == PackageManager.PERMISSION_GRANTED; }
2. 权限回调中直接执行UI操作时Activity状态不稳定
当系统弹出权限弹窗时,你的Activity可能会进入暂停甚至停止状态。用户点击允许后触发onRequestPermissionsResult,如果此时Activity已经被系统回收,直接调用createall()里的UI初始化代码(比如findViewById、setSupportActionBar)就会导致空指针崩溃。
修复方法是在执行UI操作前先判断Activity是否处于活跃状态:
@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { if (requestCode == 1) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 确保Activity没有被销毁或正在结束 if (!isFinishing() && !isDestroyed()) { createall(); } } else { Toast.makeText(MainActivity.this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show(); } } }
另外,你代码里的switch语句完全多余(已经判断了requestCode == 1),可以直接删掉简化代码。
额外的优化建议
为了更符合Android生命周期规范,建议把文件目录创建和UI初始化的逻辑拆分,让UI初始化更稳妥:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 确保你已经设置了布局文件 int currentVersion = Build.VERSION.SDK_INT; if (currentVersion >= Build.VERSION_CODES.M) { if (!checkIfAlreadyhavePermission()) { requestForSpecificPermission(); } else { // 权限已存在,直接初始化 setupApp(); } } else { // 低于Android 6.0,无需权限申请 setupApp(); } } // 拆分后的统一初始化方法 private void setupApp() { createStorageFolder(); initUIComponents(); } // 单独处理文件目录创建 private void createStorageFolder() { String mediaLocation = "/VApp"; String myFolder = Environment.getExternalStorageDirectory() + mediaLocation; File mediaDir = new File(myFolder); if (!mediaDir.exists()) { mediaDir.mkdir(); } } // 单独处理UI初始化 private void initUIComponents() { Toolbar toolBar = findViewById(R.id.toolBar); setSupportActionBar(toolBar); ViewPager viewPager = findViewById(R.id.pager); ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager()); adapter.addFragment(new RecentActivity(), "Recent"); adapter.addFragment(new SavedActivity(), "Saved"); viewPager.setAdapter(adapter); TabLayout tabLayout = findViewById(R.id.tabs); tabLayout.setupWithViewPager(viewPager); }
这样拆分后,代码逻辑更清晰,也能避免在不合适的时机执行UI操作。
另外提醒一下:从Android 10(API 29)开始,Environment.getExternalStorageDirectory()已经被废弃,建议使用getExternalFilesDir()来获取应用专属的外部存储目录,这种方式不需要申请WRITE_EXTERNAL_STORAGE权限(除非你需要访问公共目录)。
内容的提问来源于stack exchange,提问作者vinayak180696

