- 在javafx的controller里面定义了一个点击按钮的搜索歌曲方法search,该方法中采用爬取酷我音乐的歌曲作为源,然后将歌曲信息展示在ListView面板上面。方法代码如下:
@FXML
private ListView<Music> musicList;
private ObservableList<Music> data;
//部分搜歌方法,
public void search() {
// 搜索之前先清空之前内容
if (data != null) data.clear();
System.out.println("正在搜索歌曲.......");
String searchStr = searchMusicText.getText();
String musciListHTML = kuwoMusic.searchMusic(searchStr);
//爬冲获取音乐相关信息
List<KuwoLiLabel> labelList = kuwoMusic.parseLiLabelList(musciListHTML);
Long a = new Date().getTime();
// 最多只展示10首歌
for (int i = 0; i < labelList.size() && i < 10; i++) {
KuwoLiLabel label = labelList.get(i);
//解析音乐信息得到名字和音乐播放地址
Music music = kuwoMusic.parseMusicInfo1(label);
data.add(music);
}
Long b = new Date().getTime();
System.out.println("b - a " + (b - a));
}
经过测试我发现,在搜歌展示10首到列表所消耗的时间是肉眼可见的慢,会略微停顿,经过排查发现是for循环里慢。消耗如下:
展示10首歌消耗近1s,因此打算做优化,第一时间想到的是多线程,改善for循环之后代码如下:
Long a = new Date().getTime();
List<FutureTask<Music>> s = new ArrayList<FutureTask<Music>>();
// 最多只展示10首歌
for (int i = 0; i < labelList.size() && i < 10; i++) {
KuwoLiLabel label = labelList.get(i);
FutureTask<Music> futureTask = new FutureTask<Music>(() -> {
Music music = kuwoMusic.parseMusicInfo1(label);
return music;
});
s.add(futureTask);
new Thread(futureTask, "多线程").start();
}
for (int i = 0; i < 10; i++) {
try {
data.add(s.get(i).get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
s=null;
Long b = new Date().getTime();
System.out.println("b - a " + (b - a));
主要是去爬取音乐的时候开了10个线程,分别把返回的futuretask对象保存下来(不要立即获取,不然效果是一样的,因为只有调用futuretask的get方法,就会阻塞当前线程等待返回值),在爬虫循环结束之后再一一获取线程返回的music对象,之后再添加近Listview就好很多了。经过测试,基本上消耗的时间(130左右)接近一个爬虫的时间(一个爬虫爬的是25条数据,只是在页面展示10条,测试大概消耗了100多毫秒)。具体消耗时间如下: