问题描述
在我的 Android 应用程序中,我有一个初始屏幕,我可以在其中进行一些设置和加载.我的应用程序使用默认 explode
作为 windowEnterTransition
和 windowExitTransition
和 changeImageTransform
加上 changeBounds
> 转换设置为 windowSharedElementEnterTransition
和 windowSharedElementExitTransition
.为方便起见,我使用静态方法启动下一个 Activity
,其中我将当前 Activity
作为 Context
和共享元素传递.代码在本文的第二部分提供.
In my Android app, I have a splash screen where I do some setup and loading. My app uses default explode
as a windowEnterTransition
and a windowExitTransition
and a changeImageTransform
plus changeBounds
transition set as a windowSharedElementEnterTransition
and windowSharedElementExitTransition
. For convenience, I start the next Activity
using a static method where I pass the current Activity
as a Context
and a shared element. The code is provided in the second part of this post.
其中一个场景是没有任何东西可加载,因此应用几乎立即触发下一个 Activity
.问题是,在这种情况下,应用程序以某种方式在 ActivityTransitionCoordinator
中以某种方式神秘地崩溃,堆栈在本文的下一部分中给出.内部调试显示,实现的ViewRootImpl
为null,没有null检查,因此调用viewRoot.setPausedForTransition(false)
会抛出NullPointerException.你可以在下面的代码中找到这个不吉利的地方.
One of the scenarios is that there is nothing to load, so app almost immediately fires the next
Activity
. The problem is that in this case app somehow enigmatically crashes in an ActivityTransitionCoordinator
with a stack given in the next part of this post. Debugging of the internals shows that ViewRootImpl
that is achieved there is null and there is no null check, so invoking viewRoot.setPausedForTransition(false)
throws a NullPointerException
. You can find this unlucky spot marked in the code below.
为了关注这个失败的场景,让我们假设一个逻辑决定没有任何东西可以加载并且下一个
Activity
应该立即启动非常简单,它可以简化为开始提到的活动.
To focus on this failing scenario, let’s make an assumption that a logic deciding that there is nothing to load and the next
Activity
should be started immediately is so simple, that it could be simplified to just starting the mentioned activity.
如果在
onCreate()
、onResume()
或 中调用第二个
方法.我什至尝试在通过调用 Activity
的开始没有区别onEnterAnimationComplete()getWindow().getSharedElementEnterTransition()
和 getWindow().getEnterTransition()
获得的 Transition 上添加一个监听器,以允许开始下一个 Activity
当转换完成时.给定的Transitions
不为空,但应用程序永远不会进入附加侦听器的方法.
It makes no difference if a start of the second
Activity
is invoked in onCreate()
, onResume()
, or onEnterAnimationComplete()
method. I even tried adding a listener on a Transition acquired by calling getWindow().getSharedElementEnterTransition()
and getWindow().getEnterTransition()
to be allowed to start the next Activity
when transitions are finished. The given Transitions
are not null, but app never goes into methods of attached listeners.
我现在使用的解决方法只是安排一个
Runnable
来延迟下一个 Activity
的调用.
The workaround I use now is just to schedule a
Runnable
to make an invoking of the next Activity
delayed.
我想知道这是否是
Android
(更具体地说是 SupportLibrary
)问题,还是我遗漏了什么.有没有人遇到过类似的问题?
I’m wondering if this is an
Android
(a SupportLibrary
to be more specific) issue, or I missed something. Has anyone encountered a similar problem?
堆栈跟踪:
08-12 00:35:32.550 26453-26453/com.faver.mkoslacz.faverdemo E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.faver.mkoslacz.faverdemo, PID: 26453
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.ViewRootImpl.setPausedForTransition(boolean)' on a null object reference
at android.app.ActivityTransitionCoordinator.startInputWhenTransitionsComplete(ActivityTransitionCoordinator.java:897)
at android.app.ActivityTransitionCoordinator.viewsTransitionComplete(ActivityTransitionCoordinator.java:885)
at android.app.ExitTransitionCoordinator.getExitTransition(ExitTransitionCoordinator.java:318)
at android.app.ExitTransitionCoordinator.beginTransitions(ExitTransitionCoordinator.java:365)
at android.app.ExitTransitionCoordinator.-wrap0(ExitTransitionCoordinator.java)
at android.app.ExitTransitionCoordinator$4.run(ExitTransitionCoordinator.java:216)
at android.app.ActivityTransitionCoordinator.startTransition(ActivityTransitionCoordinator.java:773)
at android.app.ExitTransitionCoordinator.startExit(ExitTransitionCoordinator.java:213)
at android.app.ActivityTransitionState.startExitOutTransition(ActivityTransitionState.java:317)
at android.app.Activity.cancelInputsAndStartExitTransition(Activity.java:3960)
at android.app.Activity.startActivityForResult(Activity.java:3936)
at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java:48)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:75)
at android.app.Activity.startActivity(Activity.java:4196)
at com.faver.mkoslacz.faverdemo.activity.AuthorizationActivity.startWithTransiton(AuthorizationActivity.java:45)
at com.faver.mkoslacz.faverdemo.activity.SplashActivity.onEnterAnimationComplete(SplashActivity.java:27)
at android.app.Activity.dispatchEnterAnimationComplete(Activity.java:5852)
at android.app.ActivityThread.handleEnterAnimationComplete(ActivityThread.java:2668)
at android.app.ActivityThread.-wrap10(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1558)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
ActivityTransitionAnimator
中的代码失败:
private void startInputWhenTransitionsComplete() {
if (mViewsTransitionComplete && mSharedElementTransitionComplete) {
final View decor = getDecor();
if (decor != null) {
final ViewRootImpl viewRoot = decor.getViewRootImpl(); // it's null
viewRoot.setPausedForTransition(false); // crashes here
}
onTransitionsComplete();
}
}
开始下一个
Activity
的方法:
public static void startWithTransiton(Activity activity, android.view.View logo) {
Intent intent = new Intent(activity, AuthorizationActivity.class);
ActivityOptionsCompat options = ActivityOptionsCompat
.makeSceneTransitionAnimation(
activity,
logo,
activity.getString(R.string.logoTransfer));
activity.startActivity(intent, options.toBundle());
}
启动
Activity
内容(简化):
The splash
Activity
contents (simplified):
public class SplashActivity extends AppCompatActivity {
private static final String TAG = "SplashActivity";
private View logo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
logo = findViewById(R.id.logo);
// AuthorizationActivity.startWithTransiton(this, logo); // will fail
new Handler().postDelayed(() -> {
AuthorizationActivity.startWithTransiton(this, logo); // executes flawlessly
}, 300);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
Transition sharedElementEnterTransition = getWindow().getSharedElementEnterTransition();
if (sharedElementEnterTransition != null) {
sharedElementEnterTransition.addListener(new Transition.TransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
Log.d(TAG, "onTransitionStart: never executes");
}
@Override
public void onTransitionEnd(Transition transition) {
Log.d(TAG, "onTransitionEnd: never executes");
}
@Override
public void onTransitionCancel(Transition transition) {
Log.d(TAG, "onTransitionCancel: never executes");
}
@Override
public void onTransitionPause(Transition transition) {
Log.d(TAG, "onTransitionPause: never executes");
}
@Override
public void onTransitionResume(Transition transition) {
Log.d(TAG, "onTransitionResume: never executes");
}
});
}
Transition enterTransition = getWindow().getEnterTransition();
if (enterTransition != null) {
enterTransition.addListener(new Transition.TransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
Log.d(TAG, "onTransitionStart: never executes");
}
@Override
public void onTransitionEnd(Transition transition) {
Log.d(TAG, "onTransitionEnd: never executes");
}
@Override
public void onTransitionCancel(Transition transition) {
Log.d(TAG, "onTransitionCancel: never executes");
}
@Override
public void onTransitionPause(Transition transition) {
Log.d(TAG, "onTransitionPause: never executes");
}
@Override
public void onTransitionResume(Transition transition) {
Log.d(TAG, "onTransitionResume: never executes");
}
});
}
}
}
@Override
protected void onResume() {
super.onResume();
// AuthorizationActivity.startWithTransiton(this, logo); // will fail
}
@Override
public void onEnterAnimationComplete() {
super.onEnterAnimationComplete();
// AuthorizationActivity.startWithTransiton(this, logo); // will fail
}
}
推荐答案
我在处理 Explode Activity 过渡时也面临同样的问题,我发现此代码在 Lollipop 版本中正常运行,但在 Lollipop 上崩溃.即使我无法找出崩溃的原因.但我以另一种方式解决它.只需延迟活动转换.我在下面给出了我的代码
I'm also facing same issue while working with Explode Activity transition,I find one thing this code running normally in Lollipop version, But crashed above Lollipop.Even i can't find out the reason for crashing. But i resolve it another way. Just put delay in activity transition. I given my code below
public class SplashActivity extends AppCompatActivity {
final Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
handler.postDelayed(new Runnable() {
@Override
public void run() {
navigate();
}
},500);
}
private void navigate() {
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this);
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
startActivity(intent, options.toBundle());
}}
添加后在所有版本中都可以正常工作.
After adding this working normally in all version.
这篇关于ActivityTransitionCoordinator 中的 ViewRootImpl.setPausedForTransition(boolean) NullPointerException 当过渡到其他活动过早调用时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!