如果在JList中添加一个ListSelectionListener,在监听到动作之后进行播放音乐。如果在播放过程中进行歌曲切换,那么先前进行播放的进程无法关闭,会造成多个播放进程同时运行。
如何解决这个问题呢? 解决方法如下(实现上一曲、下一曲、暂停和播放,三个按钮以及JList点击元素播放音乐):
public String listener(JButton b1, JButton b2, JButton b3) {
list.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
// TODO Auto-generated method stub
flag = flag + 1; // 俩次点击解决
if ((flag % 2) == 0) { // 监听到俩次
str = (String) list.getSelectedValue();
/** 调用播放音乐的类并传入播放音乐名称 **/
playMusic p = new playMusic(str);
try {
p.getConnection();
} catch (NoPlayerException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
p.start();
// System.out.println("播放: "+str);
/** 播放按钮监听部分 **/
/* 上一曲 */
ActionListener b1Action = new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
p.close();
System.out.println("ok");
for (int i = 0; i < songs.length; i++) {
if (songs[i].equals(str)) {
str = songs[i - 1];
playMusic p = new playMusic(str);
try {
p.getConnection();
System.out.println("正在播放:" + str);
} catch (NoPlayerException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
p.start();
break;
}
}
}
};
b1.addActionListener(b1Action);
/* 暂停播放 */
ActionListener b2Action = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if (!Booleanflag) {
p.stop();
Booleanflag = true;
System.out.println("stop");
} else {
p.start();
Booleanflag = false;
System.out.println("start");
}
}
};
b2.addActionListener(b2Action);
/* 下一曲 */
ActionListener b3Action = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
p.close();
System.out.println("ok");
for (int i = 0; i < songs.length; i++) {
if (songs[i].equals(str)) {
str = songs[i + 1];
playMusic p = new playMusic(str);
try {
p.getConnection();
System.out.println("正在播放:" + str);
} catch (NoPlayerException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
p.start();
break;
}
}
}
};
b3.addActionListener(b3Action);
/** 衔接下一次点击,切换歌曲部分 **/
list.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
// TODO Auto-generated method stub
if ((flag % 2) == 0) { // 尽量减少重复的操作
p.close();
b2.removeActionListener(b2Action);// 点击列表进行切换歌曲的时候一处监听器
b1.removeActionListener(b1Action);
b3.removeActionListener(b3Action);
System.out.println(flag);
list.removeListSelectionListener(this);
}
}
});
}
}
});
return str;
}
解决方法的原理是:对一个事件构造多个监听器。(俩个,内嵌入一个JList监听器)
监听流程:第一次点击List对象,运行播放;第二次,点击List对象,执行第一次监听器中的内嵌监听对象的内容,因为在同一个代码块中(监听器),线程对象未变,此时关闭上次播放的播放线程对象。同时又会出现一个新的内嵌监听对象(俩个监听器),但是前面的内嵌监听器(俩个监听器的第二个监听器)并不会消失,因此p.close()操作会被执行俩次,而后每点击一次JList对象增加一个内嵌监听器,p.close()多执行一次,不断叠加。但是,前面的第二个监听器中的p线程是消亡的,故此有效的p.close()只有执行一次,为最新生成的内嵌监听器里面的p.close()。
解决办法:在内嵌监听器(俩个监听器的第二个监听器)中加入代码:list.removeListSelectionListener(this); 消除当前的匿名内部监听器。