我正在为我们的音乐学校开发一个Android应用程序。我设计了一个带有列表视图的布局,每个列表视图显示了歌曲的详细信息,如电影海报,电影名称,歌曲名称,发布年份,歌曲价格,播放/停止,查看示例,添加到/从购物车中移除图像视图
布局截图如下所示
![显示歌曲列表的布局屏幕] [1]
现在我希望用户在点击“播放”按钮时听到该歌曲的mp3版本。播放歌曲时,我想将播放图像更改为停止图像,并为用户提供停止播放歌曲的功能。
以下是保存列表视图的布局文件代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F8AE9F"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
style="@style/aboutComposer"
android:layout_width="wrap_content"
android:layout_height="45sp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:gravity="center_vertical|center_horizontal"
android:text="@string/msv_songs"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/tvCartTotal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView1"
android:layout_centerHorizontal="true"
android:text="@string/cart_total"
android:textAppearance="?android:attr/textAppearanceMedium" />
<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tvCartTotal"
android:layout_centerHorizontal="true"
android:layout_marginTop="14dp"
android:src="@drawable/icon_pay_now" />
<ListView
android:id="@+id/lstMSVSongs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/imageView1"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"
android:focusable="false" >
</ListView>
</RelativeLayout>
下面是指定每首歌曲细节显示方式的布局代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tvViewSample"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/imgFilmPoster"
android:layout_width="75sp"
android:layout_height="75sp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="@drawable/abc_ab_bottom_solid_dark_holo" />
<TextView
android:id="@+id/tvSongName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/tvFilmName"
android:layout_below="@+id/tvFilmName"
android:text="@string/dummy"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/tvYearReleased"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/tvSongName"
android:layout_below="@+id/tvSongName"
android:text="@string/dummy"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/tvPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/tvYearReleased"
android:layout_below="@+id/tvYearReleased"
android:text="@string/dummy"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/tvFilmName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="14dp"
android:layout_toRightOf="@+id/imgFilmPoster"
android:focusable="true"
android:text="@string/dummy"
android:textAppearance="?android:attr/textAppearanceSmall" />
<ImageView
android:id="@+id/imgAddCart"
android:layout_width="35sp"
android:layout_height="35sp"
android:contentDescription="@string/add_to_cart"
android:layout_alignTop="@+id/imgView"
android:layout_toRightOf="@+id/imgView"
android:src="@drawable/add_to_cart"
android:tag = "@string/add_to_cart" />
<ImageView
android:id="@+id/imgView"
android:layout_width="35sp"
android:layout_height="35sp"
android:layout_below="@+id/imgFilmPoster"
android:layout_marginTop="14dp"
android:layout_toRightOf="@+id/imgPlay"
android:src="@drawable/view_icon" />
<ImageView
android:id="@+id/imgPlay"
android:layout_width="35sp"
android:layout_height="35sp"
android:layout_alignLeft="@+id/tvPrice"
android:layout_alignTop="@+id/imgView"
android:contentDescription="@string/play_mp3"
android:src="@drawable/play" />
</RelativeLayout>
我将每首歌曲的详细信息存储为类对象。以下是Song.class的代码
package com.srindroid.indianmusicsheets;
import java.io.File;
public class Song {
private int filmImageID;
private String movieName;
private String songName;
private String yearReleased;
private int songPrice;
private int mp3File;
public Song(int filmImageID, String movieName, String songName,
String yearReleased, int songPrice, int mp3File) {
super();
this.filmImageID = filmImageID;
this.movieName = movieName;
this.songName = songName;
this.yearReleased = yearReleased;
this.songPrice = songPrice;
this.mp3File = mp3File;
}
public int getFilmImageID() {
return filmImageID;
}
public String getMovieName() {
return movieName;
}
public String getSongName() {
return songName;
}
public String getYearReleased() {
return yearReleased;
}
public int getSongPrice() {
return songPrice;
}
public int getmp3File() {
return mp3File;
}
public void setFilmImageID(int filmImageID) {
this.filmImageID = filmImageID;
}
public void setMovieName(String movieName) {
this.movieName = movieName;
}
public void setSongName(String songName) {
this.songName = songName;
}
public void setYearReleased(String yearReleased) {
this.yearReleased = yearReleased;
}
public void setSongPrice(int songPrice) {
this.songPrice = songPrice;
}
}
下面是为列表视图创建每一行的java代码
public class MsvSongs extends Activity {
int cart_total;
public MediaPlayer mp3Player=null;
private ArrayList<Song> msvSongs = new ArrayList<Song>();
ListView songs;
@Override
protected void onStop(){
if(mp3Player!=null && mp3Player.isPlaying()){
mp3Player.stop();
mp3Player.release();
mp3Player=null;
}
super.onStop();
}
@Override
protected void onPause(){
if(mp3Player!=null && mp3Player.isPlaying()){
mp3Player.pause();
}
super.onPause();
}
@Override
protected void onResume(){
if(mp3Player!=null){
mp3Player.start();
}
super.onResume();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.msv_music_sheets);
populateSongsList();
populateSongsListView();
}
private void populateSongsList() {
msvSongs.add(new Song(R.drawable.msv_ayirathil_oruvan,"Ayirathil Oruvan","Adho Andha Paravai Pola","1965",150,R.raw.msv_adho_andha_paravai_pola_ao));
msvSongs.add(new Song(R.drawable.msv_karuppu_panam,"Karuppu Panam","Aadavaralaam","1964",150,R.raw.msv_aadavaralaam_kp));
msvSongs.add(new Song(R.drawable.msv_paalum_pazhamum,"Paalum Paazhamum","Aalayamaniyin Oosai","1961",150,R.raw.msv_aalayamaniyin_oosai_pp));
msvSongs.add(new Song(R.drawable.msv_paava_mannippu,"Paava Mannipu","Athaan Ennathan","1961",150,R.raw.msv_athaan_ennathaan_pm));
msvSongs.add(new Song(R.drawable.msv_periya_idhuthu_pen,"Periya Idhuthu Pen","Andru Vandhadhadhum Adhey Nila","1963",175,R.raw.msv_andru_vandhadhum_adhey_nila_pip));
msvSongs.add(new Song(R.drawable.msv_puthiya_paravai,"Pudhiya Paravai","Enge Nimmadhi","1964",250,R.raw.msv_enge_nimmadhi_pparavai));
msvSongs.add(new Song(R.drawable.msv_server_sundaram,"Server Sundaram","Avalukku Enna Azhagiya Mugam","1964",150,R.raw.msv_avalukkenna_azhagiamugham_ss));
msvSongs.add(new Song(R.drawable.msv_panam_padaithavan,"Panam Padaithavan","Kan Pona Pookiley","1965",175,R.raw.msv_kan_pona_pokkile_pp));
msvSongs.add(new Song(R.drawable.msv_vasantha_maligai,"Vasantha Maligai","Mayakkam Enna","1972",120,R.raw.msv_mayakkam_yenna_vm));
}
private void populateSongsListView() {
songs=(ListView) findViewById(R.id.lstMSVSongs);
BaseAdapter msvAdapter = new MsvSongsAdapter(MsvSongs.this, msvSongs);
songs.setAdapter(msvAdapter);
}
public class MsvSongsAdapter extends BaseAdapter{
private LayoutInflater mInflater;
private List<Song> songs;
public MsvSongsAdapter(Context context, ArrayList<Song> msvSongs){
mInflater = LayoutInflater.from(context);
songs = msvSongs;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return songs.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return songs.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view;
final ViewHolder holder;
if(convertView == null) {
view = mInflater.inflate(R.layout.songs_view, parent, false);
holder = new ViewHolder();
holder.filmPoster = (ImageView)view.findViewById(R.id.imgFilmPoster);
holder.filmName = (TextView)view.findViewById(R.id.tvFilmName);
holder.songName = (TextView)view.findViewById(R.id.tvSongName);
holder.yearReleased = (TextView)view.findViewById(R.id.tvYearReleased);
holder.songPrice = (TextView)view.findViewById(R.id.tvPrice);
holder.mp3 = (ImageView)view.findViewById(R.id.imgPlay);
view.setTag(holder);
} else {
view = convertView;
holder = (ViewHolder)view.getTag();
}
Song currentSong = songs.get(position);
holder.filmPoster.setImageResource(currentSong.getFilmImageID());
holder.filmName.setText(currentSong.getMovieName());
holder.songName.setText(currentSong.getSongName());
holder.yearReleased.setText(currentSong.getYearReleased());
holder.songPrice.setText("Rs. "+currentSong.getSongPrice());
holder.mp3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String contentDesc = (String) holder.mp3.getContentDescription();
if (contentDesc.contains("Play")) {
if (mp3Player != null && mp3Player.isPlaying()) {
Toast.makeText(MsvSongs.this, "Stop the previous song", Toast.LENGTH_SHORT).show();
} else {
mp3Player = MediaPlayer.create(MsvSongs.this, songs.get(position).getmp3File());
mp3Player.start();
((ImageView)v).setImageResource(R.drawable.stop);
((ImageView)v).setContentDescription("Stop MP3");
}
} else {
mp3Player.pause();
mp3Player.stop();
mp3Player.release();
mp3Player = null;
((ImageView)v).setImageResource(R.drawable.play);
((ImageView)v).setContentDescription("Play MP3");
}
}
});
return view;
}
private class ViewHolder {
public ImageView filmPoster, mp3;
public TextView filmName, songName, yearReleased, songPrice;
}
}
}
现在我遇到的问题是当我在列表视图中单击第一首歌曲的“播放”按钮时,它会播放相应的mp3文件,并按预期将“播放”图标更改为“停止”图标。见下面的截图
![在此输入图片说明] [2]
但它也会将列表中其他歌曲的播放图标更改为停止图标。见下面的截图
![在此输入图片说明] [3]
您能告诉我导致此问题的原因吗?
谢谢, 作者Srini
答案 0 :(得分:1)
您的问题在于OnClickListener
和ViewHolder
。 getView()
方法将回收/重用视图。意味着位置2的View
稍后可能会重新用于位置6.这意味着位置2的点击监听器现在突然改变位置6的View
。
将OnClickListener
拼接在单独的嵌套课程中,并且不要使ViewHolder
成为最终成绩。然后,当您在OnClickListener
和ViewHolder
上实例化Song
次传递时。它在代码中显示起来更容易,所以这里有一个简单的例子:
private class OnSongClickListener implements OnClickListener {
private WeakReference<ViewHolder> mViewHolder;
private Song mSong;
public OnSongClickListener(ViewHolder vh, Song song) {
mViewHolder = new WeakReference<ViewHolder>(vh);
mSong = song;
}
@Override
public void onClick(View v) {
ViewHolder vh = mViewHolder.get();
if (vh == null) {
return;
}
//Do your click logic here
}
}
您还需要使用getView()
方法确保根据当前播放状态重置视图。例如:
Song currentSong = songs.get(position);
holder.filmPoster.setImageResource(currentSong.getFilmImageID());
holder.filmName.setText(currentSong.getMovieName());
holder.songName.setText(currentSong.getSongName());
holder.yearReleased.setText(currentSong.getYearReleased());
holder.songPrice.setText("Rs. "+currentSong.getSongPrice());
holder.mp3.setOnClickListener(new OnSongClickListener(holder,currentSong));
if (currentSong is playing) { //You'll need a way to determine this
holder.mp3.setImageResource(R.drawable.play);
holder.mp3.setContentDescription("Play MP3");
} else {
holder.mp3.setImageResource(R.drawable.stop);
holder.mp3.setContentDescription("Stop MP3");
}
return view;