将项目添加到ListView

时间:2017-01-18 15:32:18

标签: android react-native react-native-listview

我有一个ListView在某些情况下,当我添加一个项目时,它似乎崩溃了。 这次崩溃最糟糕的事情是我找不到一致的复制步骤。它总是在新项目添加到ListView时发生,但每次添加~10项时只会发生一次。

我有一个实时客户端,随着时间的推移不断添加数据。当我有两个显示相同数据的设备将一个新数据组合在一起并且其中一个崩溃时,另一个设备崩溃也是出于同样的原因。

这是堆栈跟踪和错误:

    E/AndroidRuntime: FATAL EXCEPTION: main
    Process: {packagename}, PID: 28309
    java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
    at android.view.ViewGroup.addViewInner(ViewGroup.java:4309)
    at android.view.ViewGroup.addView(ViewGroup.java:4145)
    at android.view.ViewGroup.addView(ViewGroup.java:4086)
    at com.facebook.react.views.view.ReactViewManager.addView(ReactViewManager.java:203)
    at com.facebook.react.views.view.ReactViewManager.addView(ReactViewManager.java:37)
    at com.facebook.react.uimanager.NativeViewHierarchyManager.manageChildren(NativeViewHierarchyManager.java:394)

我在react-native中找不到任何与此问题有关的人,这与他自己的本机代码无关。我没有在这个中写任何本机代码。

根据有关本机Android应用程序此问题的帖子,它闻起来像ListView以某种方式错误处理它的项目并尝试在从前一个父项中删除它之前添加一个项目。

有没有人对可能导致它的原因有什么想法? 感谢。

更新

这是我的代码,它比示例所需的时间长,但是如果它包含了我正在做的奇怪的事情导致了这个问题,我附加了整个事情

class ItemsViewer extends Component {
    constructor() {
        super();

        this._isMounted = true;
        const dataSource = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
        this.state = {
          dataSource: dataSource,
        };

        this._shouldAdjustScrollForKeyboardOnNextLayout = false;

        this._scrollListToBottomThrottled = throttle(this._scrollListToBottom.bind(this), 300);
        this._onListLayout = this._onListLayout.bind(this);
        this._onFooterLayout = this._onFooterLayout.bind(this);
        this._renderRow = this._renderRow.bind(this);
        this._renderFooter = this._renderFooter.bind(this);
    }

    componentWillUnmount() {
        this._isMounted = false;
    }

    componentWillMount() {
        this._isMounted = true;
        this.setState({dataSource: this.state.dataSource.cloneWithRows(this.props.items)});
    }

    componentWillReceiveProps(nextProps) {
        if (this.props.items != nextProps.items) {
            this.setState({dataSource: this.state.dataSource.cloneWithRows(nextProps.items)});
        }

        if(this.props.isKeyboardShown != nextProps.isKeyboardShown) {
            this._shouldAdjustScrollForKeyboardOnNextLayout = true;
        }
    }

    _scrollListToBottom() {
        if(!this._isMounted) return;

        if (this.listHeight && this.footerY && this.footerY > this.listHeight) {
            var scrollTarget = this.listHeight - this.footerY;
            var scrollResponder = this.refs.itemsList.getScrollResponder();

            scrollResponder.scrollTo({y: -scrollTarget});
        }
    }

    _onScroll(event) {
        this.scrollY = event.nativeEvent.contentOffset.y;
    }

    _renderRow(rowData, sectionID, rowID) {
        let prevItem = null;
        if(this.props.items.length > 1 && rowID > 0) {
            prevItem = this.props.items[rowID - 1];
        }

        return renderItem(getItemByContentType, rowData, prevItem, this.props.userColor);
    }

    _onListLayout(event) {
        this.prevListHeight = this.listHeight === undefined ? 0 : this.listHeight;
        this.listHeight = event.nativeEvent.layout.height;

        this._adjustScrollForKeyboardIfNeeded();
    }

    _adjustScrollForKeyboardIfNeeded() {
        if(!this._isMounted) return;

        if(!this._shouldAdjustScrollForKeyboardOnNextLayout) return;
        this._shouldAdjustScrollForKeyboardOnNextLayout = false;

        const diff = this.prevListHeight - this.listHeight;
        var scrollTarget = this.scrollY + diff;
        this.refs.itemsList.scrollTo({y: scrollTarget});
    }

    _onFooterLayout(event) {
        const prevY = this.footerY;
        this.footerY = event.nativeEvent.layout.y + event.nativeEvent.layout.height;

        // Scrolling to bottom when footer location has changed, indicating new items arrived
        if(this.footerY !== prevY) {
            this._scrollListToBottomThrottled();
        }
    }

    _renderFooter() {
        return <View onLayout={this._onFooterLayout}
                     style={style.listFooter} />;
    }

    render() {
        const {dataSource} = this.state;

        return <ListView dataSource={dataSource} enableEmptySections={true}
                         renderRow={this._renderRow}
                         ref='itemsList' initialListSize={50}
                         onLayout={this._onListLayout}
                         renderFooter={this._renderFooter}
                         onScroll={this._onScroll.bind(this)} />;
    }
};

0 个答案:

没有答案