简体   繁体   中英

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)

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

        }
    });

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM