3

I have a fragment that displays a list of up to several hundred items using a ListView. When the user causes a long-lasting scroll of the list and, while things are in motion, presses Back, bad things happen (a crash on a null pointer in getView() of the list adapter). So far, I was able to find the following workaround:

@Override
public void onDestroyView() {
    super.onDestroyView();
    // prevent a crash when Back is pressed while a long list is still being scrolled
    mAdapter.clear();
    Log.d(TAG, "Cleared adapter");
}

The trick is to make this work is to have the adapter use a clone of the source item list:

    mAdapter = new ListAdapter((MyListType)mMyList.clone());
    setListAdapter(mAdapter);

Otherwise, the call to mAdapter.clear() will wipe out the source item list, so when the fragment is recreated upon orientation change there will be no items on the list to display. However, a cloning of such a large number of items, even as a shallow copy, is an expensive operation, which I'd rather avoid.

As an alternative approach, in onDestroyView() I tried

mListView.setScrollContainer(false);

but it resulted in a crash as well.

Is there a better approach than the above workaround to achieve a clean destruction of a ListView with scrolling in progress? (Hint: trying to delay the fragment destruction by installing a listener to wait until the ListView stops scrolling is not acceptable -- the user wants an immediate response to a Back press.)

user1408140
  • 639
  • 3
  • 9
  • 20
  • This should not happened, can you show us Adapter#getView() code ? – JafarKhQ Jul 18 '14 at 23:20
  • My getView() uses the traditional ViewHolder pattern and has nothing exotic, so that is why I did not publish it. The crash takes place in convertView = getActivity().getLayoutInflater().inflate(...) due to a null pointer after the fragment is destroyed and scrolling is still taking place. – user1408140 Jul 18 '14 at 23:31
  • 1
    I Think getActivity() return null, you have to check it. i suggest to define layoutInflater globally (in the adapter) then initialize it in the adapter constructor and use it in the getView – JafarKhQ Jul 18 '14 at 23:34

1 Answers1

1

While you are using

convertView = getActivity().getLayoutInflater().inflate(...) 

I think getActivity() returns null.
To fix that:

  1. Define the LayoutInflater globally (in the Adapter)
  2. Initialize the LayoutInflater in the adapter constructor
  3. Use that LayoutInflater in the getView() method.

Also, I suggest you to always define your Adapter as a static class or on a new Java file.

JafarKhQ
  • 8,676
  • 3
  • 35
  • 45
  • 1
    I tried this approach and it seems to prevent my app from crashing. However, I am still concerned that the list scrolling (and the related production of views through the adapter) continues while the fragment is already gone. What would happen if the underlying activity was gone as well -- caching it and the layout inflater in the adapter would do no good? – user1408140 Jul 19 '14 at 18:43