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

Calling hideAllHeaders might lead to NullPointerException #229

Closed
rmunk opened this issue Nov 15, 2016 · 3 comments
Closed

Calling hideAllHeaders might lead to NullPointerException #229

rmunk opened this issue Nov 15, 2016 · 3 comments

Comments

@rmunk
Copy link

rmunk commented Nov 15, 2016

I have a FlexibleAdapter with expandable sticky headers. I want to show or hide headers depending on user selection. It works well on button press, but when I want to set the initial state and call showAllHeaders() or hideAllHeaders() immediately after filling adapter with data it throws a NullPointerException. Calling setDisplayHeadersAtStartUp(false) when configuring adapter doesn't seem to do anything. Also, every time I update the data by calling updateDataSet headers become visible so I need to hide the manually again. Is this expected behavior?

Here is the sample code and the stack trace:

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
       . . .
        
       // FlexibleAdapter init
        adapter.expandItemsAtStartUp()
                .enableStickyHeaders()
                .setDisplayHeadersAtStartUp(showSubSites)
                .setAutoCollapseOnExpand(false)
                .setAutoScrollOnExpand(true)
                .setAnimateToLimit(Integer.MAX_VALUE)
                .setNotifyMoveOfFilteredItems(true)
                .setNotifyChangeOfUnfilteredItems(true)
                .setRemoveOrphanHeaders(true)
                .setAnimationOnScrolling(true)
                .setAnimationOnReverseScrolling(true);
        adapter.initializeListeners(this);

        adapter.updateDataSet(new ArrayList<>(siteHeaderItems.values()));
        if (showSubSites) adapter.showAllHeaders();
        else adapter.hideAllHeaders();
    }

Stack trace:

E/AndroidRuntime: FATAL EXCEPTION: main
   Process: ch.photrack.discharge, PID: 21753
   java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.ViewPropertyAnimator android.view.ViewGroup.animate()' on a null object reference
       at eu.davidea.flexibleadapter.helpers.StickyHeaderHelper.detachFromRecyclerView(StickyHeaderHelper.java:89)
       at eu.davidea.flexibleadapter.FlexibleAdapter$2.run(FlexibleAdapter.java:967)
       at android.os.Handler.handleCallback(Handler.java:739)
       at android.os.Handler.dispatchMessage(Handler.java:95)
       at android.os.Looper.loop(Looper.java:135)
       at android.app.ActivityThread.main(ActivityThread.java:5930)
       at java.lang.reflect.Method.invoke(Native Method)
       at java.lang.reflect.Method.invoke(Method.java:372)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1405)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1200)

@davideas
Copy link
Owner

davideas commented Nov 15, 2016

@rmunk, thanks to have spotted this, but actually the null pointer itself, here, is not so important, because the series of the calls brings you that exception. So, if I understood well, you want display the headers (sticky) or hide them depending by showSubSites boolean value.

The fact is that, I have decided to disable sticky headers also if user hides the headers with
hideAllHeaders(), probably I will fix this by not disabling the sticky behaviour, but the user should keep in mind that the scroll listener continues to work. Anyway, I need to check if headers are shown as well to skip the swapping process.

Now, to resolve your issue you don't need to wait my fix at all. Just be sure that you don't enable sticky if no headers are shown, and re-enable again if you will show them.
Basically, remove these 2 lines:

enableStickyHeaders()
setDisplayHeadersAtStartUp(showSubSites)

Then, call enableStickyHeaders() in the if when you show headers.
You can also check the current status with areHeadersSticky().

updateDataSet() calculates the difference of the previous set and animate the views as well, but you need to activate the animation by passing true.
For this last point is better if you use the snapshot version until next pre-release. Here I'm sure the headers are displayed only if the flag was true, otherwise it skips inserting headers.
Anyway you can check this flag with areHeadersShown().

@davideas davideas added the bug label Nov 15, 2016
@davideas
Copy link
Owner

davideas commented Nov 15, 2016

Another important question, can you check if, when you call enableStickyHeader() the Adapter is attached to the RecyclerView? (RecyclerView must not be null before you enable sticky headers, so you have called setAdapter() already!).

@davideas davideas changed the title Calling hideAllHeaders on the FlexibleAdapter throws NullPointerException Calling hideAllHeaders might lead to NullPointerException Nov 15, 2016
@rmunk
Copy link
Author

rmunk commented Nov 15, 2016

I called enableStickyHeader() after calling recyclerView.setAdapter(adapter) so it was attached.

With the solution you proposed I managed to make it work, but in the end I decided to fill the adapter with list of regular FlexibleItem when user chooses option to see only parent sites (without headers) and use ExpandableHeaderItem with the other option. It made more sense from the data standpoint.

Thanks for your help.
P.S. If you need any more input for the debugging feel free to ask.

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