即使使用ViewHolder,ListView也不能平滑滚动

时间:2014-07-13 10:20:34

标签: android performance listview

我为Android制作了一个使用带有4个片段的ViewPager的音乐播放器应用。其中一个片段包含设备中所有歌曲的列表。问题是滚动列表是一种痛苦的经历。它根本不光滑。我应该说,非常吵闹。

为了解决这个问题,我实现了ViewHolder模式。但是,滚动体验并没有改变一点。

请查看我的代码以查看我的ViewHolder模式是否有任何问题,或者是否存在任何低效的代码块。

这里是AllSongsFragment.java。我已经删除了进口商品。

[Imports Here]

public class AllSongsFragment extends Fragment {
    private ArrayList<Song> songArray;
    private ListView songListView;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    } // onCreate()
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        songListView = (ListView)getView().findViewById(R.id.all_songs_list);
        songArray = new ArrayList<Song>();
        getSongList();
        // Sort the songs
        Collections.sort(songArray, new Comparator<Song>() {
            public int compare(Song a, Song b) {
                // For case-insensitive sorting
                String a1 = a.getTitle().toString().toLowerCase();
                String b1 = b.getTitle().toString().toLowerCase();
                return a1.compareTo(b1);
            }
        });
        AllSongsAdapter songAdt = new AllSongsAdapter(getActivity(), songArray);
        songListView.setAdapter(songAdt);
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.all_songs_fragment_layout, container, false);
        return rootView;
    } //onCreateView()
    public void getSongList() {
    //retrieve song info
        ContentResolver musicResolver = getActivity().getContentResolver();
        Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);
        // Iterate over the List
        if(musicCursor!=null && musicCursor.moveToFirst()) {
            //get columns
            int titleColumn = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
            int idColumn = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
            int artistColumn = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.ARTIST);
            //add songs to list
            do {
                long thisId = musicCursor.getLong(idColumn);
                String thisTitle = musicCursor.getString(titleColumn);
                String thisArtist = musicCursor.getString(artistColumn);
                songArray.add(new Song(thisId, thisTitle, thisArtist));
            }  while (musicCursor.moveToNext());
        }
    } //getSongList()
} //AllSongsFragment

我有一个Song.java文件代表每首歌。

public class Song {
    private long id;
    private String title;
    private String artist;
    //Constructor
    public Song(long songID, String songTitle, String songArtist) {
        id=songID;
        title=songTitle;
        artist=songArtist;
    }
    // get methods
    public long getID() {
        return id;
    }
    public String getTitle() {
        return title;
    }
    public String getArtist() {
        return artist;
    }
} //.Song

这是适配器 - AllSongsAdapter.java

public class AllSongsAdapter extends BaseAdapter {
    private ArrayList<Song> songs;
    private LayoutInflater songInf;
    // constructor
    public AllSongsAdapter(Context c, ArrayList<Song> theSongs){
        songs = theSongs;
        songInf = LayoutInflater.from(c);
    }
    static class ViewHolder {
        TextView title;
        TextView artist;
    }
    @Override
    public int getCount() {
        return songs.size();
    }
    @Override
    public Object getItem(int arg0) {
    // TODO Auto-generated method stub
        return null;
    }
    @Override
    public long getItemId(int arg0) {
            // TODO Auto-generated method stub
        return 0;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // Avoid unneccessary calls to findViewById() on each row, which is expensive!
        ViewHolder vh;
        /* If convertView is not null, we can reuse it directly, no inflation required!    * We only inflate a new View when the convertView is null. */
        if(convertView == null) {
            convertView = songInf.inflate(R.layout.song_item_layout, null);
            // Create a ViewHolder and store references to the children views
            vh = new ViewHolder();
            //map to song layout
            //get title and artist views
            vh.title = (TextView)convertView.findViewById(R.id.song_title);
            vh.artist = (TextView)convertView.findViewById(R.id.song_artist);
            convertView.setTag(vh);
        } else {
        // Get the ViewHolder back to get fast access to the TextViews
            vh = (ViewHolder)convertView.getTag();
        }
        //get song using position
        Song currSong = songs.get(position);
        String theTitle = currSong.getTitle();
        String theArtist = currSong.getArtist();
        // Bind that data efficiently!
        vh.title.setText(theTitle);
        if(theArtist.equals("<unknown>") || theArtist.equals("Unknown")) {
            vh.artist.setText("Unknown Artist");
        } else {
            vh.artist.setText(theArtist);
        }
        return convertView;
    } //getView()
}

我觉得访问Song类的get方法可能会产生一些影响,但我不确定。你对此有何看法?

1 个答案:

答案 0 :(得分:0)

我找到了原因。

每个歌曲项目的布局都在这里。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:paddingTop="@dimen/list_item_padding"
    android:paddingBottom="@dimen/list_item_padding"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/song_title"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textColor="#43174c"
        android:textSize="@dimen/list_item_title"
        android:singleLine="true"
        android:ellipsize="marquee" />
    <TextView
        android:id="@+id/song_artist"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textColor="#5a1f66"
        android:textSize="@dimen/list_item_second_line"
        android:singleLine="true"
        android:ellipsize="marquee" />
</LinearLayout>

注意android:ellipsize =“marquee”属性。对于每个溢出显示的TextView,线的末端都是模糊的。我在开发者设置中启用了“显示GPU透支”,发现模糊部分显示为红色,我认为这意味着透支超过2倍或3倍。所以我删除了那个属性,现在,而不是模糊的结尾,有一个省略号[...]。

现在滚动很顺利。