ViewRootImpl.setPausedForTransition(boolean)在转换到其他Activity过早调用时,ActivityTransitionCoordinator中的NullPointerException [英] ViewRootImpl.setPausedForTransition(boolean) NullPointerException in ActivityTransitionCoordinator when transition to other Activity invoked too early

查看:579
本文介绍了ViewRootImpl.setPausedForTransition(boolean)在转换到其他Activity过早调用时,ActivityTransitionCoordinator中的NullPointerException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的Android应用程序中,我有一个启动画面,我可以在其中进行一些设置和加载。我的应用使用默认 explode 作为 windowEnterTransition windowExitTransition changeImageTransform 加上 changeBounds 转换设置为 windowSharedElementEnterTransition windowSharedElementExitTransition 。为方便起见,我使用静态方法启动下一个活动,其中我将当前活动作为<$ c $传递c> 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.

其中一个场景是没有任何东西可以加载,所以app几乎立即触发下一个活动。问题是,在这种情况下,应用程序以某种方式神秘地在 ActivityTransitionCoordinator 中崩溃,并在本文的下一部分中给出了一个堆栈。调试内部显示 ViewRootImpl 实现的是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.

为了专注于这个失败的情况,让我们假设一个逻辑决定没有任何东西可以加载和应该立即启动下一个活动这么简单,可以简化为刚开始提到的活动。

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中调用第二个 Activity 的开头没有区别( ) onResume(),或 onEnterAnimationComplete()方法。我甚至尝试在通过调用 getWindow()获取的Transition上添加一个侦听器.getSharedElementEnterTransition() getWindow()。getEnterTransition()启动下一个活动。给定的 Transitions 不是null,但app永远不会进入附加侦听器的方法。

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 来调用下一个活动延迟。

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();
    }
}

开始下一个的方法活动

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());
}

启动活动内容(简化):

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.

这篇关于ViewRootImpl.setPausedForTransition(boolean)在转换到其他Activity过早调用时,ActivityTransitionCoordinator中的NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆