java.lang.NullPointerException when try listview.getChildAt()

前端 未结 3 1372
猫巷女王i
猫巷女王i 2021-01-25 07:12

There is ListView with correct values:

public class FragmentTab1 extends SherlockFragment {

ListView list;
LazyAdapter adapter;

@Override
public void onViewCre         


        
3条回答
  •  故里飘歌
    2021-01-25 08:04

    I know this is very old post. But I'm answering because people are still looking for a work around on ListView getChildAt() null pointer exception.

    This is because the ArrayApdater is REMOVING and RECYCLING the views that are not visible yet on the ListView because of height. So that if you have 10 item views, and ListView can display 4 - 5 at a the time :

    • The Adapter REMOVE the item views at position 5 to 9, so that any attempt to adapter.getChildAt(5... to 9) will cause null pointer exception

    • The Adapter also RECYCLE the item view, so that any reference you made on position 3 for example will be lost when you scroll down to 5 to 9, and also any Input that you make on position 3 (EditText, Checkbox, etc.) will be recycled when you scroll down to 5 to 9 and will be reused at another position later (ex position 1, 2 or 3, etc.) with the same value

    The only way I found to control this is to forget about getting the View and to have :

    • Attribute HashMap cbValues or any type you want for handling the values you want to use for each item on the list. The first type must be unique for item like item->getId() or position. Initialize it with new HashMap<>() in the Constructor;
    • Add InputListener for Input Views, (addTextChangedListener for EditText, setOnCheckedChangeListener for Checkbox, etc.) And on input, update the HashMap key (item.getId() or position) and value (editable.toString() or true or false). Ex. on @Override public void onCheckedChanged, put boolean result cbValues.put(item.getId(), b);
    • Prevent Adapter from using recycled convertView, remove condition if(convertView == null) so that adapter always inflate a brand new view instance. Because the view instance is new each time, you must set the value from HashMap each time also like if it already contains the key if(cbValues.containsKey(item.getId())){cbItem.setChecked(cbValue.get(cbItem.getId()))};. Probably in this case there is not tons of Items, so that smooth scrolling won't be a must.

    • And finally create public methods to get the Values outside of Adapter passing item->getId() Integer as parameter. Ex : 'public bool getCheckboxValueForItemId(int itemId) { return cbValues.get(itemId); }` . It will be easy then to select Item from Adapter

    Here is the Codes at the end :

    public class LazyAdapter extends BaseAdapter {
    
    
    private Activity activity;
    ArrayList bitmapArray = new ArrayList();
    private ArrayList mObjects;
    private static LayoutInflater inflater=null;
    public ImageLoader imageLoader;
    
    HashMap cbValues;
    
    public LazyAdapter(Activity a, ArrayList mObjects1) {
        activity = a;
        mObjects = mObjects1;
        cbValues = new HashMap<>();
        inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        imageLoader=new ImageLoader(activity.getApplicationContext());
    }
    
    public int getCount() {
        return mObjects.size();
    }
    
    public Object getItem(int position) {
        return position;
    }
    
    public long getItemId(int position) {
        return position;
    }
    
    public View getView(int position, View convertView, ViewGroup parent) {
        Data item = mObjects.get(position);
        View vi=convertView;
        // Remove convertView condition
        //if(convertView==null)
    
        vi = inflater.inflate(R.layout.item_internet, null);
        TextView text=(TextView)vi.findViewById(R.id.title1);
        ImageView image=(ImageView)vi.findViewById(android.R.id.icon);
        Checkbox cbItem = (Checkbox) vi.findViewById(android.R.id.checkbox1);
        text.setText(item.getmTitle());
        bitmapArray.add(imageLoader.getBitmap());
        imageLoader.DisplayImage(item.getmImageUrl(), image);
    
        if(cbValues.containsKey(item.getId())) {
            cbItem.setChecked(cbValue.get(cbItem.getId()))};
        }
    
        cbItem.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
               cbValues.put(item.getId(), b);
           }
        });
    
        return vi;
    }
    
    // itemId : unique identifier for an Item, not the position of Item in Adapter
    public bool getCheckboxValueForItemId(int itemId) {
        return cbValues.get(itemId);
    }
    
    }
    

提交回复
热议问题