Android 10系统拍照功能异常问题排查与修复求助
看起来你的问题核心是Android 10的Scoped Storage限制加上Activity因系统回收重启导致状态丢失,这两个因素共同引发了崩溃和WebView页面重置的问题。下面分步骤给出具体解决方案:
1. 解决Activity重启导致的状态丢失
当你启动相机后,系统可能因为内存不足销毁你的MainActivity,拍照返回时会重建Activity,这时候你之前保存的elementId、imageUri都会变成null,后续处理必然出错。必须通过onSaveInstanceState和onRestoreInstanceState保存/恢复这些关键数据,同时保存WebView的状态避免页面重载:
保存状态
在你的MainActivity中添加:
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // 保存相机相关的关键数据 outState.putString("elementId", elementId); if (imageUri != null) { outState.putParcelable("imageUri", imageUri); } // 保存WebView的加载状态,避免页面重启 webView.saveState(outState); }
恢复状态
在onCreate方法中恢复数据:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); webView = findViewById(R.id.webview); // 初始化WebView的基础配置(比如启用JS、添加JavascriptInterface等) if (savedInstanceState != null) { // 恢复之前的elementId和imageUri elementId = savedInstanceState.getString("elementId"); imageUri = savedInstanceState.getParcelable("imageUri"); // 恢复WebView的历史状态,无需重新加载网页 webView.restoreState(savedInstanceState); } else { // 首次启动时加载网页 webView.loadUrl("你的网页地址"); } }
2. 适配Android 10的Scoped Storage
Android 10引入了Scoped Storage,原有的MediaStore.Images.Media.getBitmap方法已经过时,且在Scoped Storage环境下可能无法正确读取图片,导致Bitmap为null。同时直接删除媒体文件的逻辑也需要调整,建议改用ContentResolver.openInputStream读取图片:
替换Bitmap获取逻辑
把你AsyncTask中doInBackground里的Bitmap获取代码替换为:
try { InputStream inputStream = context.getContentResolver().openInputStream(imageUri); bitmap = BitmapFactory.decodeStream(inputStream); if (inputStream != null) { inputStream.close(); } // 删除自己插入的图片(Android 10+下有权限操作) context.getContentResolver().delete(imageUri, null, null); } catch (IOException e) { e.printStackTrace(); }
临时兼容过渡(可选)
如果暂时不想完全适配Scoped Storage,可以在AndroidManifest.xml的<application>标签中添加以下属性,强制使用旧的存储模型:
<application ... android:requestLegacyExternalStorage="true"> ... </application>
注意:这只是过渡方案,Android 11及以上建议完全适配Scoped Storage。
3. 替换已弃用的AsyncTask(可选)
AsyncTask在Android 11已经被正式弃用,建议改用Coroutine或者ExecutorService来处理异步任务,代码更简洁可靠:
使用Coroutine示例
// 在你的Activity中调用 CoroutineScope(Dispatchers.IO).launch { Bitmap bitmap = null; try { InputStream inputStream = getContentResolver().openInputStream(imageUri); bitmap = BitmapFactory.decodeStream(inputStream); if (inputStream != null) { inputStream.close(); } getContentResolver().delete(imageUri, null, null); } catch (IOException e) { e.printStackTrace(); } // 切回主线程处理UI和JS调用 final Bitmap finalBitmap = bitmap; runOnUiThread(() -> { if (finalBitmap != null) { int width = Math.round((float) 0.2 * finalBitmap.getWidth()); int height = Math.round((float) 0.2 * finalBitmap.getHeight()); Bitmap newBitmap = Bitmap.createScaledBitmap(finalBitmap, width, height, false); String base64Image = imageHandler.convertBase64(newBitmap); base64Image = base64Image.replace("\n", ""); String s1 = "url('data:image/jpeg;base64," + base64Image + "') no-repeat 0% 0% / 100% 100% white"; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { webView.evaluateJavascript("javascript:" + "$('[data-key=\"" + elementId + "\"] .Preview').css('background',\"" + s1 + "\");", null); webView.evaluateJavascript("$('[data-key=\"" + elementId + "\"] input').val(\"" + base64Image + "\")", null); } } else { Log.d("kiki", "null bitmap"); } }); }
总结
你的崩溃大概率是因为Activity重启后imageUri/elementId为空,加上Android 10下旧的Bitmap读取方法失效导致的。按照上面的步骤,先解决状态保存问题,再适配Scoped Storage,应该就能解决崩溃和WebView重启的问题了。如果还有问题,可以尝试连接调试获取详细的崩溃日志(比如用Logcat过滤你的包名),这样能更精准定位问题。
内容的提问来源于stack exchange,提问作者kikicoder




