androidandroid-studiolistviewfastscroll

Crashes when scrolling fast in listview android


I have a list view that when scrolling, the item in the middle of the list view is enlarged and its color changes. But I have a problem, and it crashes when I scroll fast. My code is located below. Can anyone tell me what is causing the problem? Thanks

myActivity.java

public class myActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_entekhb_zaman);


       txtday=(TextView)findViewById(R.id.txtday);
       txtdayok=(TextView)findViewById(R.id.txtdayok);
       listviewday = (ListView) findViewById(R.id.listday);

       listday.add("");
       listday.add("1");
       listday.add("2");
       listday.add("3");
       listday.add("4");
       listday.add("");

       adapterday=new Custom_List_Day(this,android.R.layout.simple_list_item_1,listday);
       listviewday.setAdapter(adapterday);


        listviewday.setOnScrollListener(new AbsListView.OnScrollListener() {

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            // TODO Auto-generated method stub
            if (scrollState == SCROLL_STATE_IDLE) {
                View itemView = view.getChildAt(0);
                int top = Math.abs(itemView.getTop());
                int bottom = Math.abs(itemView.getBottom());
                int scrollBy = top >= bottom ? bottom : -top;
                if (scrollBy == 0) {
                    return;
                }
                smoothScrollDeferred(scrollBy, (ListView)view);
            }
        }

        private void smoothScrollDeferred(final int scrollByF,
                                          final ListView viewF) {
            final Handler h = new Handler();
            h.post(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    viewF.smoothScrollBy(scrollByF, 200);
                }
            });
        }

        @Override
        public void onScroll(AbsListView arg0, int firstVisibleItem, int visibleItemCount, int totalItemCount){
            Log.i("Scroll","first "+firstVisibleItem+", visibleItemCount "+visibleItemCount+",totalCount "+totalItemCount);
            int center = firstVisibleItem+(visibleItemCount)/2 ;
            if(currentLargedPosition != center){
                enlargeMiddleView(currentLargedPosition-firstVisibleItem, center-firstVisibleItem);
                currentLargedPosition = center;
                txtdayok.setText(listday.get(currentLargedPosition));
            }

        }
    });


     }

void enlargeMiddleView(int oldPosition, int newPosition){

    // get enlarged view and make it return default size
    TextView newTextView = (TextView)listviewday.getChildAt(oldPosition).findViewById(R.id.txtday3);
    newTextView.setTextSize(22);
    newTextView.setTextColor(getResources().getColor(R.color.white));


    // get the current center view and make it bigger
    TextView oldTextView = (TextView)listviewday.getChildAt(newPosition).findViewById(R.id.txtday3);
    oldTextView.setTextSize(28);
    oldTextView.setTextColor(getResources().getColor(R.color.sormeii));
}
}

Custom_List_Day

public class Custom_List_Day extends ArrayAdapter<String> {

private final Activity context;
private final ArrayList<String> name;
private final int resource;


public Custom_List_Day(Activity context,int resource, ArrayList<String> name) {
    super(context, resource, name);

    this.context = context;
    this.name = name ;
    this.resource=resource;


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

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

@Override
public int getViewTypeCount() {
    return super.getViewTypeCount();
}



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


    LayoutInflater infalter = context.getLayoutInflater();


    View rowLayout = null;




    if (convertView == null) {
        // inflating the row

        rowLayout =  infalter.inflate(this.resource, parent,false);


    } else {
        rowLayout = convertView;
    }


    TextView txtName = (TextView) rowLayout.findViewById(R.id.txtday3);

    txtName.setText(name.get(position));

    return rowLayout ;
}
}

list_day.xml

  <LinearLayout android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:background="@color/colorPrimary"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:padding="4dp">


    <TextView
        android:id="@+id/txtday3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="شنبه - ۹خرداد"
        android:textColor="@color/white"
        android:textSize="22sp"/>

     </LinearLayout>

When I slowly scroll, I have no problems and the program works. But when I scroll fast, the program crashes. logcat error

07-15 12:32:45.607 14920-14920/anjam.carno E/AndroidRuntime: FATAL EXCEPTION: main
                                                         Process: anjam.carno, PID: 14920
                                                         java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference
                                                             at anjam.carno.ActivityEntekhabZaman.enlargeMiddleView2(ActivityEntekhabZaman.java:232)
                                                             at anjam.carno.ActivityEntekhabZaman$2.onScroll(ActivityEntekhabZaman.java:189)
                                                             at android.widget.AbsListView.invokeOnItemScrollListener(AbsListView.java:1519)
                                                             at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5245)
                                                             at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:4668)
                                                             at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
                                                             at android.view.Choreographer.doCallbacks(Choreographer.java:580)
                                                             at android.view.Choreographer.doFrame(Choreographer.java:549)
                                                             at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
                                                             at android.os.Handler.handleCallback(Handler.java:739)
                                                             at android.os.Handler.dispatchMessage(Handler.java:95)
                                                             at android.os.Looper.loop(Looper.java:135)
                                                             at android.app.ActivityThread.main(ActivityThread.java:5910)
                                                             at java.lang.reflect.Method.invoke(Native Method)
                                                             at java.lang.reflect.Method.invoke(Method.java:372)
                                                             at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1405)
                                                             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1200)

Solution

  • Firstly, I would like to suggest you to read Standing coding guidelines for android. It will improve your coding standards.

    Secondly you need to remove the handler. Judging from your code, you want to snap the ListView to middle. Please have a look at RecyclerView. If you want to add snap to middle this link Linear Snap Helper will help you.

    However if you want to modify your code I suggest you do following changes

        listviewday.setOnScrollListener(new AbsListView.OnScrollListener()
        {
    
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState)
            {
                // TODO Auto-generated method stub
                if (scrollState == SCROLL_STATE_IDLE)
                {
                    View itemView = view.getChildAt(0);
                    int top = Math.abs(itemView.getTop());
                    int bottom = Math.abs(itemView.getBottom());
                    int scrollBy = top >= bottom ? bottom : -top;
                    if (scrollBy == 0)
                    {
                        return;
                    }
    
                    view.smoothScrollBy(scrollBy, 200);
                }
            }
    
            @Override
            public void onScroll(AbsListView arg0, int firstVisibleItem, int visibleItemCount, int totalItemCount)
            {
                if (visibleItemCount != 0)
                {
                    if (oldTextView != null)
                    {
                        oldTextView.setTextSize(22);
                        oldTextView.setTextColor(Color.WHITE);
                        oldTextView = null;
                    }
    
                    final int midPosition = visibleItemCount - (visibleItemCount / 2);
                    final TextView listItem = (TextView) listviewday.getChildAt(midPosition - 1).findViewById(R.id.txtday3);
                    listItem.setTextSize(26);
                    listItem.setTextColor(Color.BLACK);
    
                    oldTextView = listItem;
                }
    
            }
        });