我的应用程序允许用户使用设备的默认相机应用程序拍照,如下所示:
private void takePhoto(Uri outputUri) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
startActivityForResult(intent, TAKE_PHOTO_REQUEST_CODE);
}
查看崩溃日志,我看到很多应用程序崩溃发生在应用程序似乎在拍照后恢复的情况下。
异常和堆栈跟踪:
Fatal Exception: android.view.ViewRootImpl$CalledFromWrongThreadException
Only the original thread that created a view hierarchy can touch its views.
android.view.ViewRootImpl.checkThread (ViewRootImpl.java:11379)
android.view.ViewRootImpl.requestLayout (ViewRootImpl.java:2562)
android.view.ViewRootImpl.updateConfiguration (ViewRootImpl.java:6324)
android.app.ActivityThread.handleActivityConfigurationChanged (ActivityThread.java:6925)
android.app.servertransaction.ActivityConfigurationChangeItem.execute (ActivityConfigurationChangeItem.java:53)
android.app.servertransaction.ActivityTransactionItem.execute (ActivityTransactionItem.java:45)
android.app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor.java:135)
android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:95)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2571)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:226)
android.os.Looper.loop (Looper.java:313)
android.app.ActivityThread.main (ActivityThread.java:8741)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:571)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)
堆栈跟踪有几个不同的变体,但它们都经历了一些配置更改,这让我相信用户必须在拍照时旋转设备,并且当它以不同的方向返回前台时应用程序崩溃.
我的应用程序的活动在其清单中有
android:configChanges="orientation|screenSize"
,因为它包含一个WebView,但它在onConfigurationChanged
期间没有做任何事情。onConfigurationChanged
。我发现 onConfigurationChanged
在应用程序崩溃之前在与 onCreate
调用相同的主线程上调用。 onStart
和 onResume
在崩溃前没有被调用。任何想法/建议将不胜感激!
编辑
添加更多堆栈跟踪变体:
Fatal Exception: android.view.ViewRootImpl$CalledFromWrongThreadException
Only the original thread that created a view hierarchy can touch its views.
android.view.ViewRootImpl.checkThread (ViewRootImpl.java:11586)
android.view.ViewRootImpl.requestLayout (ViewRootImpl.java:2648)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.widget.TextView.onConfigurationChanged (TextView.java:4706)
android.view.View.dispatchConfigurationChanged (View.java:16145)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewRootImpl.updateConfiguration (ViewRootImpl.java:6502)
android.app.ActivityThread.handleActivityConfigurationChanged (ActivityThread.java:6941)
android.app.servertransaction.ActivityConfigurationChangeItem.execute (ActivityConfigurationChangeItem.java:53)
android.app.servertransaction.ActivityTransactionItem.execute (ActivityTransactionItem.java:45)
android.app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor.java:135)
android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:95)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2574)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:226)
android.os.Looper.loop (Looper.java:313)
android.app.ActivityThread.main (ActivityThread.java:8757)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:571)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)
Fatal Exception: android.view.ViewRootImpl$CalledFromWrongThreadException
Only the original thread that created a view hierarchy can touch its views.
android.view.ViewRootImpl.checkThread (ViewRootImpl.java:11586)
android.view.ViewRootImpl.requestLayout (ViewRootImpl.java:2648)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.view.View.requestLayout (View.java:27612)
android.widget.TextView.onConfigurationChanged (TextView.java:4706)
android.view.View.dispatchConfigurationChanged (View.java:16145)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewGroup.dispatchConfigurationChanged (ViewGroup.java:1654)
android.view.ViewRootImpl.updateConfiguration (ViewRootImpl.java:6502)
android.app.ActivityThread.handleActivityConfigurationChanged (ActivityThread.java:6941)
android.app.ActivityThread$ActivityClientRecord$1.onConfigurationChanged (ActivityThread.java:797)
android.view.ViewRootImpl.performConfigurationChange (ViewRootImpl.java:6462)
android.view.ViewRootImpl.handleResized (ViewRootImpl.java:2424)
android.view.ViewRootImpl.-$$Nest$mhandleResized
android.view.ViewRootImpl$ViewRootHandler.handleMessageImpl (ViewRootImpl.java:6728)
android.view.ViewRootImpl$ViewRootHandler.handleMessage (ViewRootImpl.java:6697)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:226)
android.os.Looper.loop (Looper.java:313)
android.app.ActivityThread.main (ActivityThread.java:8757)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:571)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)
通常这个错误发生在网络处理等后台任务中,所以他们使用不同的线程。因此,要解决此问题,请使用
Activity.runOnUiThread
视图原始活动中的方法。
使用下面的代码。它应该工作正常。无论如何,startActivityForResult() 已被弃用。
ActivityResultLauncher<Intent> cameraActivityResultLauncher;
cameraActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
// There are no request codes
Intent data = result.getData();
Bitmap img = (Bitmap)data.getExtras().get("data");
imageView.setImageBitmap(img);
}
}
});
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
cameraActivityResultLauncher.launch(cameraIntent);
您可以尝试调试。由于某种原因,ViewRootImpl 实例中的 mThread 字段与通知配置更改的线程不同。这是抛出异常的方法:
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
可能是该字段被设置为空或更改,或者线程确实发生了更改。也许三星已经修改了上述课程。
也尝试在不离开应用程序的情况下触发配置更改,看看会发生什么。
是的。它确实只发生在三星设备上。我曾经遇到过这个问题。
这是您拍摄照片时发生的情况
Open a camara intent to capture a picture
Take picture
Return to your activity or fragment
Get captured image & use it
这是使用设备相机拍摄图像的通常生命周期。
现在运行在 android 13 上的三星设备(不知道低版本,我没有低版本的,所以)有一个问题,如果你使用 camera intent 纵向拍照,然后返回活动或具有横向方向的片段,然后它会在配置更改时破坏以前的对象。
即使您以纵向拍摄照片,然后在横向模式下旋转设备,然后再次将其旋转到纵向模式并返回活动,也会发生这种情况,因为如上所述配置更改。
所以,这是我对工作正常的看法。我现在将它应用于我所有包含此类功能的应用程序。
1。使用传统方法固定清单中的活动方向,根据您的需要提供固定屏幕方向
portrait
或landscape
<activity
android:name=".activity.MainActivity"
android:screenOrientation="portrait" />
2。如果您的响应式屏幕在设备方向更改时可以是纵向或横向,则将此
config
添加到Manifest中的activity tag
<activity
android:name=".activity.MainActivity"
android:configChanges="orientation|screenSize"/>
现在,当您在拍照后返回您的 Activity 时,您将在启动相机意图之前创建的对象不会被破坏。