Analyze the call sequence of the addHeaderView and setAdapter of ListView from the source code.
To add headerview to ListView, you must use addHeaderView. To set data for ListView, you must call the setAdapter method. However, in the order of calling addHeaderView and setAdapter, an exception occurs sometimes in Java. lang. IllegalStateException: Cannot add header view to list -- setAdapter has already been called. This is because setAdapter is called before addHeaderView. Therefore, it is recommended that setAdapter be called after addHeaderView and addfooterView. This ensures security. Next, let's look at the source code. See why.
Android-18 (4.3) addHeaderView source code:
public void addHeaderView(View v, Object data, boolean isSelectable) { final FixedViewInfo info = new FixedViewInfo(); info.view = v; info.data = data; info.isSelectable = isSelectable; mHeaderViewInfos.add(info); // Wrap the adapter if it wasn't already wrapped. if (mAdapter != null) { if (!(mAdapter instanceof HeaderViewListAdapter)) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter); } // In the case of re-adding a header view, or adding one later on, // we need to notify the observer. if (mDataSetObserver != null) { mDataSetObserver.onChanged(); } } }
Source code of addHeaderView of Android-17 (4.2:
public void addHeaderView(View v, Object data, boolean isSelectable) { if (mAdapter != null && ! (mAdapter instanceof HeaderViewListAdapter)) { throw new IllegalStateException( "Cannot add header view to list -- setAdapter has already been called."); } FixedViewInfo info = new FixedViewInfo(); info.view = v; info.data = data; info.isSelectable = isSelectable; mHeaderViewInfos.add(info); // in the case of re-adding a header view, or adding one later on, // we need to notify the observer if (mAdapter != null && mDataSetObserver != null) { mDataSetObserver.onChanged(); } }
In the above section, we can compare the processing differences in the code. In Version 17, as long as the adapter is not empty, an exception is thrown directly, which is exactly the exception we mentioned at the beginning of this article. In Version 18, if the adapter is not empty, a new adapter is created, which contains headerview and footerview and the original adapter we passed in. This is a process made after Version 18. We recommend that you use addHeaderView, addFooterView, and setAdapter Based on the call sequence described above.