nativescript-community / ui-collectionview

Allows you to easily add a collection view (grid list view) to your projects. Supports vertical and horizontal modes, templating, and more.
Apache License 2.0
59 stars 18 forks source link

PullToRefresh + CollectionView crashes when clearing data #84

Closed dangrima90 closed 3 days ago

dangrima90 commented 4 days ago

Which platform(s) does your issue occur on?

Please, provide the following version numbers that your issue occurs with:

Please, tell us how to recreate the issue in as much detail as possible.

I have an issue when using PullToRefresh and CollectionView together in NativeScript Vue 3. The issue is occurring when the list data being passed to CollectionView is cleared.

The curious thing is that when PullToRefresh is not used, clearing data does not crash the application.

I see the following error when the Android app crashes:

TypeError: Cannot read properties of null (reading 'getRecycledViewPool')

Stacktrace is pointing to this line as the result of the failure: https://github.com/nativescript-community/ui-collectionview/blob/bc530ed7117a06ab7a656b8ec8fa7ef724d1e5f0/src/collectionview/index.android.ts#L515

Is there any code involved?

Here is a sample with which I've managed to replicate the issue with:

<template>
  <Page>
    <StackLayout>
      <Button text="Clear Data" @tap="clearData" />
      <PullToRefresh @refresh="onPullToRefreshInitiated">
        <CollectionView
          v-if="listData.length > 0"
          :height="500"
          :items="listItems"
          itemIdGenerator="index"
          :itemTemplateSelector="templateSelector"
          @loadMoreItems="getData"
        >
          <template #element="{ item }">
            <StackLayout class="pb-4 border-b-2 border-red-400">
              <Label :textWrap="true" :text="item.index" class="font-bold text-blue-500" />
              <Label :textWrap="true" :text="item.element.title" class="font-bold text-gray-900" />
              <Label :textWrap="true" :text="item.element.body" class="text-gray-600" />
            </StackLayout>
          </template>
          <template #noData>
            <Label text="NO DATA" />
          </template>
        </CollectionView>
      </PullToRefresh>
    </StackLayout>
  </Page>
</template>

<script>
import axios from 'axios/dist/axios';
import { ObservableArray } from '@nativescript/core';

export default {
  created: function () {
    this.getData();
  },

  data() {
    return {
      pullToRefreshActive: false,
      listData: []
    };
  },

  computed: {
    listItems() {
      const data = new ObservableArray();

      if (this.listData.length > 0) {
        data.push(...this.listData.map((element, index) => ({ section: 'element', element, index })));
      } else {
        data.push({ section: 'noData' });
      }

      console.log('listItems...', this.listData, data);
      return data;
    }
  },

  methods: {
    templateSelector(item) {
      return item?.section || 'spinner' || 'default';
    },

    onPullToRefreshInitiated({ object }) {
      if (!this.pullToRefreshActive) {
        this.pullToRefreshActive = true;
        // get data after refreshing list
        this.$nextTick(async () => {
          await this.getData();
          // hide pull to refresh loader
          object.refreshing = false;
          this.pullToRefreshActive = false;
        });
      }
    },

    async getData() {
      const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
      this.listData.push(...response.data);
    },

    clearData() {
      console.log('clear data');
      this.listData = [];
    }
  }
};
</script>
farfromrefug commented 4 days ago

@dangrima90 thanks for thé detailed report. Can you share the full stacktrace?

dangrima90 commented 4 days ago

@dangrima90 thanks for thé detailed report. Can you share the full stacktrace?

Sure thing, here you go :)

  System.err: Calling js method getItemViewType failed
  System.err: TypeError: Cannot read properties of null (reading 'getRecycledViewPool')
  System.err:
  System.err: StackTrace:
  System.err: setNativePoolSize(file: src/webpack:/app/node_modules/@nativescript-community/ui-collectionview/index.android.js:414:0)
  System.err:   at templateKeyToNativeItem(file: src/webpack:/app/node_modules/@nativescript-community/ui-collectionview/index.android.js:1029:0)
  System.err:   at getItemViewType(file: src/webpack:/app/node_modules/@nativescript-community/ui-collectionview/index.android.js:1001:0)
  System.err:   at com.tns.Runtime.callJSMethodNative(Native Method)
  System.err:   at com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1302)
  System.err:   at com.tns.Runtime.callJSMethodImpl(Runtime.java:1188)
  System.err:   at com.tns.Runtime.callJSMethod(Runtime.java:1175)
  System.err:   at com.tns.Runtime.callJSMethod(Runtime.java:1153)
  System.err:   at com.tns.Runtime.callJSMethod(Runtime.java:1149)
  System.err:   at com.tns.gen.com.nativescript.collectionview.AdapterInterface.getItemViewType(AdapterInterface.java:46)
  System.err:   at com.nativescript.collectionview.Adapter.getItemViewType(Adapter.java:53)
  System.err:   at androidx.recyclerview.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:6548)
  System.err:   at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6727)
  System.err:   at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6688)
  System.err:   at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6684)
  System.err:   at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2362)
  System.err:   at androidx.recyclerview.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:584)
  System.err:   at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1622)
  System.err:   at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:687)
  System.err:   at androidx.recyclerview.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:182)
  System.err:   at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4604)
  System.err:   at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:4307)
  System.err:   at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4873)
  System.err:   at com.nativescript.collectionview.RecyclerView.onLayout(RecyclerView.java:66)
  System.err:   at android.view.View.layout(View.java:24461)
  System.err:   at android.view.ViewGroup.layout(ViewGroup.java:7412)
  System.err:   at androidx.swiperefreshlayout.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:689)
  System.err:   at android.view.View.layout(View.java:24461)
  System.err:   at android.view.ViewGroup.layout(ViewGroup.java:7412)
  System.err:   at org.nativescript.widgets.CommonLayoutParams.layoutChild(CommonLayoutParams.java:222)
  System.err:   at org.nativescript.widgets.StackLayout.layoutVertical(StackLayout.java:178)
  System.err:   at org.nativescript.widgets.StackLayout.onLayout(StackLayout.java:133)
  System.err:   at android.view.View.layout(View.java:24461)
  System.err:   at android.view.ViewGroup.layout(ViewGroup.java:7412)
  System.err:   at org.nativescript.widgets.CommonLayoutParams.layoutChild(CommonLayoutParams.java:222)
  System.err:   at org.nativescript.widgets.GridLayout.onLayout(GridLayout.java:425)
  System.err:   at android.view.View.layout(View.java:24461)
  System.err:   at android.view.ViewGroup.layout(ViewGroup.java:7412)
  System.err:   at org.nativescript.widgets.CommonLayoutParams.layoutChild(CommonLayoutParams.java:222)
  System.err:   at org.nativescript.widgets.ContentLayout.onLayout(ContentLayout.java:80)
  System.err:   at android.view.View.layout(View.java:24461)
  System.err:   at android.view.ViewGroup.layout(ViewGroup.java:7412)
  System.err:   at org.nativescript.widgets.CommonLayoutParams.layoutChild(CommonLayoutParams.java:222)
  System.err:   at org.nativescript.widgets.GridLayout.onLayout(GridLayout.java:425)
  System.err:   at android.view.View.layout(View.java:24461)
  System.err:   at android.view.ViewGroup.layout(ViewGroup.java:7412)
  System.err:   at android.widget.FrameLayout.layoutChildren(FrameLayout.java:374)
  System.err:   at android.widget.FrameLayout.onLayout(FrameLayout.java:312)
  System.err:   at android.view.View.layout(View.java:24461)
  System.err:   at android.view.ViewGroup.layout(ViewGroup.java:7412)
  System.err:   at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
  System.err:   at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
  System.err:   at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
  System.err:   at android.view.View.layout(View.java:24461)
  System.err:   at android.view.ViewGroup.layout(ViewGroup.java:7412)
  System.err:   at android.widget.FrameLayout.layoutChildren(FrameLayout.java:374)
  System.err:   at android.widget.FrameLayout.onLayout(FrameLayout.java:312)
  System.err:   at android.view.View.layout(View.java:24461)
  System.err:   at android.view.ViewGroup.layout(ViewGroup.java:7412)
  System.err:   at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
  System.err:   at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
  System.err:   at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
  System.err:   at android.view.View.layout(View.java:24461)
  System.err:   at android.view.ViewGroup.layout(ViewGroup.java:7412)
  System.err:   at android.widget.FrameLayout.layoutChildren(FrameLayout.java:374)
  System.err:   at android.widget.FrameLayout.onLayout(FrameLayout.java:312)
  System.err:   at com.android.internal.policy.DecorView.onLayout(DecorView.java:1331)
  System.err:   at android.view.View.layout(View.java:24461)
  System.err:   at android.view.ViewGroup.layout(ViewGroup.java:7412)
  System.err:   at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:4609)
  System.err:   at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:4031)
  System.err:   at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2919)
  System.err:   at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:10491)
  System.err:   at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1108)
  System.err:   at android.view.Choreographer.doCallbacks(Choreographer.java:866)
  System.err:   at android.view.Choreographer.doFrame(Choreographer.java:797)
  System.err:   at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1092)
  System.err:   at android.os.Handler.handleCallback(Handler.java:938)
  System.err:   at android.os.Handler.dispatchMessage(Handler.java:99)
  System.err:   at android.os.Looper.loopOnce(Looper.java:226)
  System.err:   at android.os.Looper.loop(Looper.java:313)
  System.err:   at android.app.ActivityThread.main(ActivityThread.java:8663)
  System.err:   at java.lang.reflect.Method.invoke(Native Method)
  System.err:   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
  System.err:   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
farfromrefug commented 3 days ago

@dangrima90 i tested here and your example works fine. Must be something in your project. The error is meaning that the collectionview (native view) is destroyed at the time of the call (which should never happen!). You are using vue ? 2 or 3? I had to modify your code to make it work in vue 2 but once i did it worked just fine

dangrima90 commented 3 days ago

@farfromrefug in Vue 2 it will work fine. The issue is happening for me in Vue 3.

dangrima90 commented 3 days ago

@farfromrefug I actually re-read your message and I think the issue is related to v-if="listData.length > 0".

The error is meaning that the collectionview (native view) is destroyed at the time of the call (which should never happen!).

I'm basing my assumption on your comment. Once the data is cleared, v-if will destroy the view as the length will be 0 - so that might be the cause. Still a bit strange that without the PullToRefresh the issue doesn't happen.

farfromrefug commented 3 days ago

@dangrima90 yes could be that. Not sure what happening. But v-i there is a bad idea yes

dangrima90 commented 3 days ago

@farfromrefug seems highly likely. I'll test a bit more and just to make sure whether without the v-if I can work fine. Thanks for your feedback, will keep you updated.

dangrima90 commented 3 days ago

@farfromrefug confirmed that without the v-if all is good! Thanks once again for your feedback - keep up the good work 💪 🚀