Getting Custom List Adapter to properly inflate multiple linear layouts

13,374

You have an error in your getView() method:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View v;
    if (convertView == null) {
       v = inflater.inflate(R.layout.single_word_container_item, null); 
    } else {
       v = convertView;
    }
    TextView wordName = (TextView) v.findViewById(R.id.wordName);

    // questionable logic
    if(!_words.isEmpty()){
        wordName.setText(_word.remove(0));
    }

    return v;
}

findViewById() must be called on the row's view.

Also look at the questionable logic above, what are you trying to do? This won't work too well if you are removing the listview objects directly from the adapter.

Share:
13,374
pat
Author by

pat

mobile developer

Updated on June 28, 2022

Comments

  • pat
    pat almost 2 years

    I'm a little new to android and am trying to figure out these custom list adapter. So I have an activity that extends BaseListActivity and a function like:

    public void inflate(){
    
        ArrayList<String> words = new ArrayList<String>();
        orders.add("hello");
        orders.add("world");
    
        wordsList = (ListView) findViewById(R.id.list);
    
        WordsAdapter adapter = new WordsAdapter(this, R.layout.single_word_container_item,words);
        wordsList.setAdapter(adapter);
    

    And then I implement my custom WordsAdapter as follows:

    public class WordsAdapter extends ArrayAdapter<String>{
        public Context context;
        public ArrayList<String> _words;
    
        //not sure the purpose of 'a' here
        public WordsAdapter(Context context, int a, ArrayList<String> words) {
            super(context, a, words);
            _words = words;
            this.context = context;
        }
    
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
    
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View v = inflater.inflate(R.layout.single_word_container_item, null);
            TextView wordName = (TextView) findViewById(R.id.wordName);
            if(!_words.isEmpty()){
                wordName.setText(_word.remove(0));
            }
    
            return v;
        }
    
    }
    

    From what I can tell from the logs is that getView is never being called. 'single_word_container_item' is simply an xml file with a layout that I want to inflate multiple times. I'm not sure about the entire process - I figured you set an adapter on your listview and then in that adapter you take care of displaying what will actually show up each time, so what am I doing wrong here? Currently I'm getting a null pointer exception where I set my adapter but earlier it just would not show anything. The logs show that it is getting into the WordsAdapter constructor but then dying. Thanks in advance for any advice.

    EDIT: So it appears to be something wrong with identifying the listview in my xml.

    If you use:

    ListView
    android:id="@+id/android:list" OR android:id="@id/android:list"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" 
    ListView
    

    the error is a null pointer exception when you use it

    but if you define it as:

    ListView
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" 
    ListView
    

    you get the error: 07-15 19:18:50.240: E/AndroidRuntime(29842): Caused by: java.lang.RuntimeException: Your content must have a ListView whose id attribute is 'android.R.id.list'

    EDIT: So apparently you can't extend listactivity and call setcontentview(). Since I need a view on top of the listview I don't want to extend list activity but rather call setcontentview and just refer to the list by its id.

    Now my error is:

    java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread.

    I tried calling adapter.notifyDataSetChanged() after my setAdapter() but that didn't seem to work. Am I supposed to call it somewhere else?

  • pat
    pat almost 12 years
    Hey thanks for the help that makes total sense but I believe there is still something else wrong. I updated getView() to reflect your suggestions but still I get a null pointer exception when trying to call setAdapter() and my log still shows that getView() is not even being called. What exactly calls getView() anyway? Thanks again.
  • azgolfer
    azgolfer almost 12 years
    Well you need to post the logcat that shows where the NPE occurs. getView() is called by the OS when it needs to paint the listview's items.
  • pat
    pat almost 12 years
    sorry added it..I can't get much out of it. I would guess that maybe it can't find a reference to my listview in the xml. I read that you have to make an explicit listview with id/list so that is what I'm doing but maybe there is a problem with using findviewbyid on it
  • azgolfer
    azgolfer almost 12 years
    Remove the line 'wordName.setText(_word.remove(0));' it's causing the crash. Change it to something like wordName.setText("abc"); and see if the crash stops.
  • pat
    pat almost 12 years
    wow I can't believe thats what it was thank you so much for the help