Search code examples
androidlistviewandroid-listviewandroid-custom-view

CustomListView Crashes When Scrolling Fast


I am trying to implement a custom list view. It is showing up fine, and when I scroll through it slowly it works normally. However, when I start scrolling faster, the app crashes. Below is my code for the list view adapter.

import java.util.List;

import MainActivity.ListViewItem;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class CustomListViewAdapter extends BaseAdapter {

LayoutInflater inflater;
List<ListViewItem> items;

public CustomListViewAdapter(Activity context, List<ListViewItem> items) {
    super();

    this.items = items;
    this.inflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public int getCount() {
    // TODO Auto-generated method stub
    return items.size();
}

@Override
public Object getItem(int position) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public long getItemId(int position) {
    // TODO Auto-generated method stub
    return 0;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub

    ListViewItem item = items.get(position);

    View vi = convertView;

    if (item.Type.equals("Homework")) {

        if (convertView == null)
            vi = inflater.inflate(R.layout.item_row_homework, null);

        ImageView imgThumbnail = (ImageView) vi
                .findViewById(R.id.homework_imgThumbnail);
        TextView txtTitle = (TextView) vi
                .findViewById(R.id.homework_txtTitle);
        TextView txtSubTitle = (TextView) vi
                .findViewById(R.id.homework_txtSubTitle);

        imgThumbnail.setImageResource(item.ThumbnailResource);
        txtTitle.setText(item.Title);
        txtSubTitle.setText(item.SubTitle);
    }
    if (item.Type.equals("Study")) {

        if (convertView == null)
            vi = inflater.inflate(R.layout.item_row_study, null);

        ImageView imgThumbnail = (ImageView) vi
                .findViewById(R.id.study_imgThumbnail);
        TextView txtTitle = (TextView) vi
                .findViewById(R.id.study_txtTitle);
        TextView txtSubTitle = (TextView) vi
                .findViewById(R.id.study_txtSubTitle);

        imgThumbnail.setImageResource(item.ThumbnailResource);
        txtTitle.setText(item.Title);
        txtSubTitle.setText(item.SubTitle);
    }
    if (item.Type.equals("Project")) {

        if (convertView == null)
            vi = inflater.inflate(R.layout.item_row_project, null);

        ImageView imgThumbnail = (ImageView) vi
                .findViewById(R.id.project_imgThumbnail);
        TextView txtTitle = (TextView) vi
                .findViewById(R.id.project_txtTitle);
        TextView txtSubTitle = (TextView) vi
                .findViewById(R.id.project_txtSubTitle);

        imgThumbnail.setImageResource(item.ThumbnailResource);
        txtTitle.setText(item.Title);
        txtSubTitle.setText(item.SubTitle);
    }

    return vi;
}
}

Here is the logcat output.

06-29 19:21:59.543: E/AndroidRuntime(2507): FATAL EXCEPTION: main
06-29 19:21:59.543: E/AndroidRuntime(2507): Process: com.example.customlistview, PID: 2507
06-29 19:21:59.543: E/AndroidRuntime(2507): java.lang.NullPointerException
06-29 19:21:59.543: E/AndroidRuntime(2507):     at com.example.customlistview.CustomListViewAdapter.getView(CustomListViewAdapter.java:68)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.widget.AbsListView.obtainView(AbsListView.java:2240)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.widget.ListView.makeAndAddView(ListView.java:1790)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.widget.ListView.fillDown(ListView.java:691)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.widget.ListView.fillGap(ListView.java:655)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5136)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:3236)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.widget.AbsListView.onTouchMove(AbsListView.java:3580)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.widget.AbsListView.onTouchEvent(AbsListView.java:3424)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.View.dispatchTouchEvent(View.java:7706)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2210)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1945)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2068)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1515)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.app.Activity.dispatchTouchEvent(Activity.java:2458)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2016)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.View.dispatchPointerEvent(View.java:7886)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:3954)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3833)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3399)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3449)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3418)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3525)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3426)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3582)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3399)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3449)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3418)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3426)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3399)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5602)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5582)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5553)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5682)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:176)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:5655)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:5701)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.Choreographer.doCallbacks(Choreographer.java:574)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.Choreographer.doFrame(Choreographer.java:542)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.os.Handler.handleCallback(Handler.java:733)
06-29 19:21:59.543: E/AndroidRuntime(2507):     at android.os.Handler.dispatchMessage(Handler.java:9

Solution

  • You need to properly implement getViewTypeCount() and getItemViewType() for your ListAdapter.

    getViewTypeCount() needs to return the number of distinct row types (in your case, it would appear to be 3).

    getItemViewType() then needs to return a number, from 0 to getViewTypeCount()-1, indicating which view type corresponds to the supplied position. In your case, you would return 0, 1, or 2, depending on whether this is a Homework, Study, or Project row.

    If you implement those properly, the convertView passed into getView() will be of the right type for the row. Right now, you are assuming that the convertView is of the right type, and if it is not, your findViewById() lookup will fail.