Android RecyclerView停止滚动

时间:2018-01-31 00:51:49

标签: android android-recyclerview

问题

我有一个recyclerview,显示从SQL数据库加载的歌曲列表。我的问题是,当我向下滚动它移动一些元素,然后动画就像它触及底部。然后我可以继续滚动,但它会使滚动起伏并且非常明显。奇怪的是它只会在我向下滚动时发生。如果我向上滚动,我可以顺利地从列表的底部到顶部。向下滚动时,它会回收一些元素,然后突然停止,并且在它停止之前它似乎不是一个设定量。滚动速度也无关紧要,即使速度很慢也会这样做。

我制作了一个自定义字母选择器,允许跳转到列表中的特定部分工作正常,但我禁用它以查看是否导致问题,但不是。

视频

前几个卷轴正在下降,你可以看到它停止了“列表底部”动画。然后我可以继续滚动。最后一个卷轴正在上升,它慢慢停止,并且不显示“列表顶部”动画。

https://www.youtube.com/watch?v=0-Tr8DDGJCc&feature=youtu.be

代码

片段

public class LibraryFragment extends Fragment {

    TextView mTitle;

    private RecyclerView itemsView;
    private SideSelector selector;
    private LibraryListAdapter adapter;
    private AppDatabase mDatabase;
    private Song.ModeType mMode = null;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_library, container, false);

        mTitle = (TextView) view.findViewById(R.id.title);
        mTitle.setText("LIBRARY");

        itemsView = (RecyclerView) view.findViewById(R.id.library_items);
        selector = (SideSelector) view.findViewById(R.id.side_selector);
        adapter = new LibraryListAdapter();
        itemsView.setLayoutManager(new LinearLayoutManager(getContext()));
        itemsView.setAdapter(adapter);
        /*itemsView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                int visiblePos = ((LinearLayoutManager)itemsView.getLayoutManager()).findFirstVisibleItemPosition();
                int section = adapter.getSectionForPosition(visiblePos);
                selector.setCurrentSection(section);
            }
        });

        selector.setView(itemsView);*/

        mDatabase = Room.databaseBuilder(getContext().getApplicationContext(),
                AppDatabase.class, "database-name").build();

        setMenu();

        return view;
    }

    public void setSongs(String title) {
        adapter.clearList();
        mTitle.setText(title);
        selector.setVisibility(View.VISIBLE);

        getSongs();
    }

    public void setMenu() {
        ArrayList<ListItem> data = new ArrayList<>();
        mTitle.setText("LIBRARY");

        data.add(new MenuInfo(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setSongs("ALL");
            }
        }, "All"));
        data.add(new MenuInfo(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setSongs("MUSIC & MUSICALS");
            }
        }, "Music & Musicals"));
        data.add(new MenuInfo(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setSongs("MOVIES & TELEVISION");
            }
        }, "Movies & Television"));
        data.add(new MenuInfo(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setSongs("HISTORY & LITERATURE");
            }
        }, "History & Literature"));

        selector.setVisibility(View.GONE);
        adapter.setListItems(data);
    }

    private void getSongs() {
        new AsyncTask<Void, Void, List<Song>>() {
            @Override
            protected List<Song> doInBackground(Void... params) {
                final Song.Dao songDao = mDatabase.songDao();
                return songDao.getAll();
            }

            @Override
            protected void onPostExecute(List<Song> songs) {
                for (Song song : songs) {
                    adapter.addListItem(new MediaInfo(song));
                }
                adapter.notifyDataSetChanged();
            }
        }.execute();
    }

}

适配器

public class LibraryListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements SectionIndexer {

    public static String[] ALPHABET = new String[]{"#", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
            "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};

    private List<ListItem> mDataArray = new ArrayList<ListItem>();

    public void setListItems(List<ListItem> items) {
        mDataArray = items;
        notifyDataSetChanged();
    }

    public void addListItem(ListItem item) {
        mDataArray.add(item);
    }

    public void clearList() {
        mDataArray.clear();
        notifyDataSetChanged();
    }

    public void notifyChange() {
        notifyDataSetChanged();
    }

    @Override
    public int getItemViewType(int position) {
        if(mDataArray.size() > position && position >= 0) {
            return mDataArray.get(position).getType();
        }

        return -1;
    }

    @Override
    public int getSectionForPosition(int position) {
        int section = 0;
        if(mDataArray.size() > position && position >= 0) {
            for(String letter : ALPHABET) {
                if(mDataArray.get(position).getName().startsWith(letter)) {
                    break;
                }
                section++;
            }
        }

        return section;
    }

    @Override
    public Object[] getSections() {
        return ALPHABET;
    }

    @Override
    public int getPositionForSection(int sectionIndex) {
        if(sectionIndex < 0) { sectionIndex = 0; }
        if(sectionIndex >= ALPHABET.length) { sectionIndex = ALPHABET.length - 1; }

        int position = 0;
        for (ListItem info : mDataArray) {
            if(info instanceof MediaInfo) {
                if (((MediaInfo) info).getName().charAt(0) >= ALPHABET[sectionIndex].charAt(0)) {
                    break;
                }
            }
            position++;
        }

        return position;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View item = null;

        switch (viewType) {
            case ListItem.VIEW_TYPE_MEDIA:
                item = LayoutInflater.from(parent.getContext()).inflate(R.layout.library_media_item, parent, false);
                return new MediaItemViewHolder(item);
            case ListItem.VIEW_TYPE_MENU_ITEM:
                item = LayoutInflater.from(parent.getContext()).inflate(R.layout.library_menu_item, parent, false);
                return new MenuItemViewHolder(item);
            default:
                return null;
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        holder.itemView.setOnClickListener(mDataArray.get(position).getOnClickListener());

        switch (holder.getItemViewType()) {
            case ListItem.VIEW_TYPE_MEDIA:
                MediaItemViewHolder holder_media = (MediaItemViewHolder) holder;
                holder_media.setTitle(mDataArray.get(position).getName());
                holder_media.setArtist(((MediaInfo) mDataArray.get(position)).getSong().getArtist());
                holder_media.setType(((MediaInfo) mDataArray.get(position)).getSong().getMode());
                break;
            case ListItem.VIEW_TYPE_MENU_ITEM:
                MenuItemViewHolder holder_menu = (MenuItemViewHolder) holder;
                holder_menu.setName(mDataArray.get(position).getName());
                break;
        }
    }

    @Override
    public int getItemCount() {
        return mDataArray.size();
    }

    public static class MediaItemViewHolder extends RecyclerView.ViewHolder {

        public TextView mTitleView;
        public TextView mArtistView;
        public ImageView mImageView;

        public MediaItemViewHolder(View v) {
            super(v); // done this way instead of view tagging
            mTitleView = (TextView) v.findViewById(R.id.library_item_title);
            mArtistView = (TextView) v.findViewById(R.id.library_item_artist);
            mImageView = (ImageView) v.findViewById(R.id.library_item_icon);
        }

        public void setTitle(String title) {
            mTitleView.setText(title);
        }

        public void setArtist(String artist) {
            mArtistView.setText(artist);
        }

        public void setType(Song.ModeType type) {
            switch (type) {
                case BOOK:
                    mImageView.setImageResource(R.drawable.ic_book);
                    break;
                case MOVIE:
                    mImageView.setImageResource(R.drawable.ic_movie);
                    break;
                case SONG:
                    mImageView.setImageResource(R.drawable.ic_music);
                    break;
            }
        }
    }

    public static class MenuItemViewHolder extends RecyclerView.ViewHolder {

        public TextView mNameView;

        public MenuItemViewHolder(View v) {
            super(v); // done this way instead of view tagging
            mNameView = (TextView) v.findViewById(R.id.name);
        }

        public void setName(String name) {
            mNameView.setText(name);
        }
    }
}

布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="35dp"
    android:paddingRight="35dp"
    android:paddingTop="25dp"
    android:paddingBottom="25dp">

    <TextView
        android:id="@+id/title"
        android:text="TITLE"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fontFamily="serif"
        android:textSize="24dp"
        android:textColor="@android:color/black" />

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/library_items"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_toStartOf="@+id/side_selector"
            android:background="@drawable/border_top_gray"
            android:nestedScrollingEnabled="true"
            android:layout_marginTop="10dp"></android.support.v7.widget.RecyclerView>

        <com.beneville.grandfatherclock.views.SideSelector
            android:id="@+id/side_selector"
            android:layout_width="30dp"
            android:layout_height="match_parent"
            android:layout_alignParentRight="true" />

    </RelativeLayout>

</LinearLayout>

1 个答案:

答案 0 :(得分:0)

Android中的不稳定滚动是应用程序在更新UI的主应用程序线程上花费了太多时间。对于RecyclerView,这意味着在onBindViewHolder()或onCreateViewHolder()中可能需要花费太多时间。

以下是关于如何使滚动顺利成为黄油的好方法:6 ways to make your Android app scroll faster than the wind