Crashes when scrolling fast in listview android

1k Views Asked by At

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)
2

There are 2 best solutions below

3
Muhammad Umar On BEST ANSWER

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;
            }

        }
    });
5
Susmit Agrawal On

IMO, the 200ms delay is what's causing the crash. Off the top of my head,

Change

if(currentLargedPosition != center){
    enlargeMiddleView(currentLargedPosition-firstVisibleItem, center-firstVisibleItem);
    currentLargedPosition = center;
    txtdayok.setText(listday.get(currentLargedPosition));
}

in onScroll to

new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(210);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if(currentLargedPosition != center){
                            enlargeMiddleView(currentLargedPosition-firstVisibleItem, center-firstVisibleItem);
                            currentLargedPosition = center;
                            txtdayok.setText(listday.get(currentLargedPosition));
                        }
                    }
                });
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();

Of course, it will appear as if the app is lagging while scrolling. But this is the only way I can think of, without changing your core logic. Also, this is just a theory, and I'm not 100% sure it will work.