我为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方法可能会产生一些影响,但我不确定。你对此有何看法?
答案 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倍。所以我删除了那个属性,现在,而不是模糊的结尾,有一个省略号[...]。
现在滚动很顺利。