列表视图行的各个控件在使用另一个列表视图中的其他单个控件时会受到影响

时间:2014-09-20 08:45:43

标签: android android-listview baseadapter

我正在为我们的音乐学校开发一个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

1 个答案:

答案 0 :(得分:1)

您的问题在于OnClickListenerViewHoldergetView()方法将回收/重用视图。意味着位置2的View稍后可能会重新用于位置6.这意味着位置2的点击监听器现在突然改变位置6的View

OnClickListener拼接在单独的嵌套课程中,并且不要使ViewHolder成为最终成绩。然后,当您在OnClickListenerViewHolder上实例化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;