turing-tech / MaterialScrollBar

An Android library that brings the Material Design 5.1 sidebar to pre-5.1 devices.
Apache License 2.0
778 stars 126 forks source link

Intermittent Crash (Null Pointer) #51

Closed alistairsykes closed 8 years ago

alistairsykes commented 8 years ago

Unfortunately cannot pin down the steps to recreate but very occasionally I get a null pointer exception. Any ideas?

Crash: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getTop()' on a null object reference at android.support.v7.widget.RecyclerView$LayoutManager.getDecoratedTop(RecyclerView.java:7675) at com.turingtechnologies.materialscrollbar.ScrollingUtilities.getCurScrollState(ScrollingUtilities.java:152) at com.turingtechnologies.materialscrollbar.ScrollingUtilities.scrollToPositionAtProgress(ScrollingUtilities.java:107) at com.turingtechnologies.materialscrollbar.MaterialScrollBar.onDown(MaterialScrollBar.java:634) at com.turingtechnologies.materialscrollbar.DragScrollBar$1.onTouch(DragScrollBar.java:74) at android.view.View.dispatchTouchEvent(View.java:9296) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2547) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2240) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at com.android.internal.policy.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2403) at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1737) at android.app.Activity.dispatchTouchEvent(Activity.java:2771) at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:60) at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:60) at com.android.internal.policy.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2364) at android.view.View.dispatchPointerEvent(View.java:9520) at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4230) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4096) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3642) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3695) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3661) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3787) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3669) at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3844) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3642) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3695) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3661) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:36

turing-tech commented 8 years ago

This occurs when materialScrollBar.recyclerView.getChildAt(0); returns null but doesn't throw an exception. The only possible cause is that the first visible object in the recyclerView is null and there are more than 0 objects. Do you have any idea why the first visible object in the recyclerView might be null?

alistairsykes commented 8 years ago

No there should be no reason why it's null that I can see

Setting adapter code:

ExampleAdapter adapter = new ExampleAdapter();
adapter.setDataSet(data);
binding.rvExample.setHasFixedSize(true);
binding.rvExample.setAdapter(adapter);
if (materialScrollBar == null) {
     materialScrollBar = new DragScrollBar(getContext(), binding.rvExample, true);
     materialScrollBar.setHandleColourRes(R.color.blue_normal);
     materialScrollBar.setTextColourRes(R.color.white);
     materialScrollBar.setHandleOffColourRes(R.color.grey_dark);
     materialScrollBar.setBarColourRes(R.color.grey_mid_dark);
     materialScrollBar.addIndicator(new AlphabetIndicator(getContext()), true);
}

Adapter code:

List<T> mDataSet = new ArrayList<>();

public void setDataSet(List<T> mDataSet) {
    this.mDataSet = new ArrayList<>(mDataSet);
    notifyDataSetChanged();
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    ViewExampleItemBinding binding = DataBindingUtil.inflate(inflater, R.layout.view_example_item, parent, false);
    return new ViewHolder(binding.getRoot());
}

@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
    super.onBindViewHolder(holder, position);

    ViewExampleItemBinding binding = DataBindingUtil.bind(holder.rootView);
    DataItem dataItem = mDataSet.get(holder.getAdapterPosition());
    binding.setDataItem(dataItem);
    binding.textView.setVisibility(dataItem.getRegistered() != null ? (dataItem.getRegistered() ? View.GONE : View.VISIBLE) : (View.GONE));
}

@Override
public Character getCharacterForElement(int element) {
    DataItem dataItem = mDataSet.get(element);
    Character c = dataItem.getName().charAt(0);
    if (Character.isDigit(c)) {
        c = '#';
    }
    return c;
}

public static class ViewHolder extends RecyclerView.ViewHolder {
    public final View rootView;

    public ViewHolder(View rootView) {
        super(rootView);
        this.rootView = rootView;
    }
}
turing-tech commented 8 years ago

Here's a zip file with a debug copy of the lib. Open it and put the aar file (do not extract the contents of the aar file, just the aar file itself) inside a library folder in the root of your app module and add the following to your gradle:

allprojects {
    repositories {
        flatDir {
            dirs 'nameOfExampleLibFolderInModuleRoot'
        }
    }
}

dependencies {
    compile(name:'materialScrollBar', ext:'aar')
}

Also don't forget to remove the normal copy of the library.

Once you've gotten that working run your app until you encounter the crash. Just above the stacktrace should be a line from the ScrollingUtilities class. If you wouldn't mind telling me what it is. If there isn't then I need to know that too.

materialScrollBar.zip

alistairsykes commented 8 years ago

Hi, sorry it has taken me a while to get back to you. I added that .aar and the log I got is below.

`05-31 09:20:23.589 9378-9378/com.example D/com.turingtechnologies.materialscrollbar.ScrollingUtilities: View is null; This is not the first render of the bar. 05-31 09:20:23.596 9378-9378/com.example E/InputEventReceiver: Exception dispatching input event. 05-31 09:20:23.597 9378-9378/com.example D/AndroidRuntime: Shutting down VM

                                                                                --------- beginning of crash

05-31 09:20:23.730 9378-9378/com.example E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example, PID: 9378 java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getTop()' on a null object reference at android.support.v7.widget.RecyclerView$LayoutManager.getDecoratedTop(RecyclerView.java:7675) at com.turingtechnologies.materialscrollbar.ScrollingUtilities.getCurScrollState(ScrollingUtilities.java:159) at com.turingtechnologies.materialscrollbar.ScrollingUtilities.scrollToPositionAtProgress(ScrollingUtilities.java:110) at com.turingtechnologies.materialscrollbar.MaterialScrollBar.onDown(MaterialScrollBar.java:636) at com.turingtechnologies.materialscrollbar.DragScrollBar$1.onTouch(DragScrollBar.java:74) at android.view.View.dispatchTouchEvent(View.java:9296) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2547) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2240) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2553) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2254) at com.android.internal.policy.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2403) at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1737) at android.app.Activity.dispatchTouchEvent(Activity.java:2771) at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:60) at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:60) at com.android.internal.policy.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2364) at android.view.View.dispatchPointerEvent(View.java:9520) at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4230) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4096) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3642) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3695) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3661) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3787) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3669) at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3844) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3642) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3695) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3661) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:366`

MFlisar commented 8 years ago

I'm facing this problem as well. In my case, I use a view based stack and sometimes, the "upper" levels are not initialised (and don't need to, views are not visible and won't be) and then I face the same bug...

I have another problem there, so I'm not sure if this fix is necessary, but following will avoid the crash:

if (child == null)
{
    scrollPosState.rowTopOffset = 0;
    scrollPosState.rowHeight = 0;
}
else
{
    scrollPosState.rowTopOffset = materialScrollBar.recyclerView.getLayoutManager().getDecoratedTop(child);
    scrollPosState.rowHeight = child.getHeight();
}
GreaseMonk commented 8 years ago

+1

turing-tech commented 8 years ago

@GreaseMonk Are you having this problem as well?

GreaseMonk commented 8 years ago

@krimin-killr21 Yes. I have a SlidingTabStrip and SlidingTabLayout (pager adapter) inside a Fragment's layout, which has a framelayout with a recyclerview and the indicator inside, It doesn't work immediately. I used a container (framelayout) to inflate this very fragment's layout before this. But now i've inflated it using a pager adapter and from that moment on shit hit the fan.

farbodsz commented 8 years ago

I'm also having this problem when I change orientation.

farbodsz commented 8 years ago

Just another point, in my app, I decided to switch to using the MaterialScrollBar programmatically for more flexibility. This prevented me getting this error when changing orientation.

In other words, I've found that this only seems to occur when changing orientation when the MaterialScrollBar is added through XML as opposed to Java code.

turing-tech commented 8 years ago

Could someone provide me their XML view hierarchy when this bug occurs? I am unable to replicate with a DragScrollBar added by XML which leads me to think it might depend on the order in which the views are created.

farbodsz commented 8 years ago

I would post my XML code, but I changed it to add the scroll bar programmatically.

If I have time, I might try to work backwards to reproduce the XML layout that was causing the issues.