【问题标题】:Individual controls of a list view row gets affected on working with other individual control in another list view列表视图行的单个控件在与另一个列表视图中的其他单个控件一起使用时会受到影响
【发布时间】:2014-09-20 08:45:42
【问题描述】:

我正在为我们的音乐学校开发一个安卓应用程序。我设计了一个带有列表视图的布局,每个列表视图都显示了歌曲的详细信息,例如电影海报、电影名称、歌曲名称、发行年份、歌曲价格、播放/停止、查看示例、添加到/从购物车图像视图中删除.

布局截图如下所示

![显示歌曲列表的布局屏幕][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]

请告诉我是什么导致了这个问题?

谢谢, 斯里尼

【问题讨论】:

    标签: android android-listview baseadapter


    【解决方案1】:

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

    拼接你的OnClickListener,因为它在单独的嵌套类中,不要使ViewHolder最终。然后,当您实例化OnClickListener 时,传递ViewHolderSong。它更容易在代码中显示,所以这里有一个简单的例子:

    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;
    

    【讨论】:

    • 您好 Jay Sover,感谢您的回复。我将代码更改如下
    • 非常感谢。它现在对我有用。我在 Song 类中添加了一个布尔变量,并在播放歌曲时将其设置为 true。
    • 很高兴我能帮上忙。那你能接受这个答案吗?
    • 您好 Jay Sover,我如何接受您的回答?抱歉,我是 stackoverflow 的新手。
    • 您好 Jay Sover,我向 Android 应用内计费提出了一个新问题。你能帮我解决这个问题吗?
    猜你喜欢
    • 2014-11-07
    • 1970-01-01
    • 2016-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-28
    • 2020-04-28
    • 1970-01-01
    相关资源
    最近更新 更多