Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NullPointerException initStickyHeadersHolder on orientation change #512

Closed
marcelpinto opened this issue Dec 20, 2017 · 7 comments
Closed
Milestone

Comments

@marcelpinto
Copy link

Situation:

  • Launch Activity starts Main activity
  • Fragment added in activity on created
  • Adapter initialized onViewCreated
  • Set stickyHeaders(true)
  • Rotate the device while Main activity has not fully created (timing is difficult, use debugger to stop onCreate and then rotate device)
  • Fragment gets recreated together with the adapter
  • Old adapter execute posted runnable and tries to add sticky header in a null view
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.ViewGroup.addView(android.view.View)' on a null object reference
                                                                        at eu.davidea.flexibleadapter.helpers.StickyHeaderHelper.initStickyHeadersHolder(StickyHeaderHelper.java:104)
                                                                        at eu.davidea.flexibleadapter.helpers.StickyHeaderHelper.attachToRecyclerView(StickyHeaderHelper.java:77)
                                                                        at eu.davidea.flexibleadapter.FlexibleAdapter$5.run(FlexibleAdapter.java:1357)
                                                                        at android.os.Handler.handleCallback(Handler.java:739)
                                                                        at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                        at android.os.Looper.loop(Looper.java:158)
                                                                        at android.app.ActivityThread.main(ActivityThread.java:7225)
                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

The problem is this piece of code

    public FlexibleAdapter<T> setStickyHeaders(final boolean sticky, @Nullable ViewGroup stickyContainer) {
        log.i("Set stickyHeaders=%s (in Post!)%s", sticky, (stickyContainer != null ? " with user defined Sticky Container" : ""));

        // With user defined container
        mStickyContainer = stickyContainer;

        // Run in post to be sure about the RecyclerView initialization
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                // Enable or Disable the sticky headers layout
                if (sticky) {
                    if (mStickyHeaderHelper == null) {
                        mStickyHeaderHelper = new StickyHeaderHelper(FlexibleAdapter.this,
                                mStickyHeaderChangeListener, mStickyContainer);
                        mStickyHeaderHelper.attachToRecyclerView(mRecyclerView);
                        log.i("Sticky headers enabled");
                    }
                } else if (areHeadersSticky()) {
                    mStickyHeaderHelper.detachFromRecyclerView();
                    mStickyHeaderHelper = null;
                    log.i("Sticky headers disabled");
                }
            }
        });
        return this;
    }

Since you are posting a runnable if the timing is good it will be executed after onDestroyView.

Possible solutions, check if recylcer is still there or remove the runnable.

@davideas davideas added the bug label Dec 20, 2017
@davideas
Copy link
Owner

@skimarxall, yes, thank you.
I can fix that.

@davideas
Copy link
Owner

davideas commented Dec 20, 2017

@skimarxall, I'm trying to reproduce as you described but I don't get the exception!

Then, I looked what is that line: the code is expecting a FrameLayout wrapping the RecyclerView, and the null you are having is because no parent layout is found wrapping RV. Indeed, the RecyclerView is never null in any point...

We know, if we are using a Fragment, we have access to the RecyclerView instance after the view is created. it must have that layout also when you rotate. Adapter seems to not be detached from the old RecyclerView.

Which Android version are you using? I tried with 8.0.

@marcelpinto
Copy link
Author

Hi, thanks to take a look.

it happens in a Samsung with v21 and in the emulator v26. As mentioned is hard to reproduce manually so I add a breakpoint on the onCreate, on that moment I turn the device and continue the debugger.

What it might be important to say is that I am initializing the adapter onActivityCreated inside the fragment.

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        userFeedAdapter
                .addListener(this)
                .setStickyHeaders(true)
                .setDisplayHeadersAtStartUp(true)
                .setAnimationOnForwardScrolling(true)
        userFeedAdapter.stickyHeaderElevation = resources.getDimensionPixelSize(R.dimen.spacing_8)

        userFeedList.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
        userFeedList.adapter = userFeedAdapter
    }

So, what I can see with the debugger is:

Activity onCreate -> Turn device -> onAcrtivityCreated -> Init adapter -> Activity recreates -> onActivityCreated is called again (new view, new adapter) -> init new adapter -> Post runnable from old adapter is called -> NullPointer because it misses the reference.

@davideas
Copy link
Owner

@skimarxall, ah the breakpoint is in onCreate not after setStickyHeaders. I will retry.

@davideas
Copy link
Owner

davideas commented Dec 21, 2017

@skimarxall, I don't get the exception, the parent layout is never null in the 2 calls, can you show me your layout where the RV is present?

@davideas
Copy link
Owner

davideas commented Jan 7, 2018

I've put an extra check, even it's so difficult to reproduce it, since the parent layout must always be present if the RecyclerView instance is valid!

@marcelpinto
Copy link
Author

Thanks for fixing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants