Android本地及网络音乐播放器-网络音乐的试听和下载(四)
2016-10-09 10:16
627 查看
上节讲了如何搜索网络音乐并以列表的形式展示在我们面前,该节将述点击网络音乐搜索列表中的歌曲后选择试听或者下载的功能实现.
首先是网络音乐列表添加点击监听,点击后弹出提示框-选择试听或者下载,根据选择的不同将执行不同的功能代码,具体代码如下:
NetFragment添加如下代码:
试听功能模块关键代码如下:
这样后台播放音乐的service将切换音乐开始试听;
下载功能代码如下:
下载任务一般比较耗时,因此应当在后台服务上运行,这里新建一个下载服务-DownloadService,主要代码如下:
在DownloadService中创建了一个下载任务DownloadUtil,其代码如下:
同时MainActivity中需要添加几个变量:
数据库类MyDatabaseHelper:
到这里下载和试听的主要代码差不多了,代码的方法名都是根据意义来取的,比较好懂;下一节将讲述下载列表的展示和下载的暂停/继续/删除功能.
项目源码下载地址如下:
Android本地及网络音乐播放器
首先是网络音乐列表添加点击监听,点击后弹出提示框-选择试听或者下载,根据选择的不同将执行不同的功能代码,具体代码如下:
NetFragment添加如下代码:
musicList.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapter, View view, int position, long id) { final int pos = position; Log.d(TAG, "item " + position + " clicked"); new AlertDialog.Builder(NetFragment.this.getActivity()) .setIcon(R.drawable.ic_launcher) .setTitle("下载/试听") .setMessage("请选择下载或试听") .setNegativeButton("试听", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(NetFragment.this.getActivity(), "试听", 300).show(); shiTing(pos); } }) .setPositiveButton("下载", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { downloadMusic(pos); Toast.makeText(NetFragment.this 4000 .getActivity(), "下载", 300).show(); } }).show(); } }); private String formatDuration(long dur) { long totalSecond = dur / 1000; String minute = totalSecond / 60 + ""; if (minute.length() < 2) minute = "0" + minute ; String second = totalSecond % 60 + ""; if (second.length() < 2) second = "0" + second; return minute + ":" + second; }
试听功能模块关键代码如下:
private void shiTing(int position) { Map<String, String> item = searchResults.get(position); final String downloadUrl = item.get("audioUrl"); final String name = item.get("name"); final String artist = item.get("artist"); MainActivity.currentMusicTitle = item.get("name"); MainActivity.currentMusicArtist = item.get("artist"); MainActivity.currentMusicUrl = item.get("audioUrl"); getMusicDuration(downloadUrl); MainActivity.isPlaying = true; MainActivity.MSG = MainActivity.MSG_PLAY; Log.d(TAG, "send name=" + name); DownloadFragment.playDownloadMusic = true; Intent musicIntent = new Intent(); musicIntent.setAction("action.changesong"); NetFragment.this.getActivity().sendBroadcast(musicIntent); } //获取音乐时长 private void getMusicDuration(String url) { final String musicUrl = url; new Thread(new Runnable() { @Override public void run() { int duration = 0; MediaPlayer mp = null; try { mp = new MediaPlayer(); mp.reset(); mp.setDataSource(musicUrl); mp.prepare(); duration = mp.getDuration(); } catch (Exception e) { e.printStackTrace(); } finally { mp.release(); } MainActivity.currentMusicDuration = formatDuration(duration); } }).start(); }
这样后台播放音乐的service将切换音乐开始试听;
下载功能代码如下:
protected synchronized void downloadMusic(int position) { Map<String, String> item = searchResults.get(position); final String downloadUrl = item.get("audioUrl"); final String name = item.get("name"); final String artist = item.get("artist"); final String picUrl = item.get("picUrl"); Intent intent = new Intent(NetFragment.this.getActivity(), DownloadService.class); intent.putExtra("downloadUrl", downloadUrl); intent.putExtra("name", name); intent.putExtra("artist", artist); intent.putExtra("picUrl", picUrl); Log.d(TAG, "send name=" + name); NetFragment.this.getActivity().startService(intent); }
下载任务一般比较耗时,因此应当在后台服务上运行,这里新建一个下载服务-DownloadService,主要代码如下:
@Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand"); musicUrl = intent.getStringExtra("downloadUrl"); musicName = intent.getStringExtra("name"); musicArtist = intent.getStringExtra("artist"); picUrl = intent.getStringExtra("picUrl"); Log.d(TAG, "receive name=" + musicName); downloadMusic(); return super.onStartCommand(intent, flags, startId); } private void downloadMusic() { isDownloading = true; final String targetMusicFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/musicplayer/"+ musicName + ".mp3"; final String targetPicFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/musicplayer/albumPic/"+ musicName + "-"+ musicArtist + ".jpg"; final DownloadUtil downloadUtil = new DownloadUtil(musicName, musicUrl, targetMusicFile, 1, this); Log.d(TAG, "picUr = " + picUrl); final DownloadUtil downloadUtil1 = new DownloadUtil(musicName, picUrl, targetPicFile, 1, this); final Map<String, Object> item = new HashMap<String, Object>(); item.put("downloadUrl", musicUrl); item.put("title", musicName); item.put("artist", musicArtist); item.put("musicSize", musicSize + ""); item.put("url", targetMusicFile); DownloadFragment.downloadingList.add(item);//DownloadFragment将下载任务添加到下载列表中 notifyDownloadFragment(); Map<String, Object> map = new HashMap<String, Object>(); map.put("thread", downloadUtil1); map.put("musicName", musicName); threadList.add(map); new Thread(new Runnable() { @Override public void run() { try { downloadUtil.download(); } catch (Exception e) { e.printStackTrace(); File file = new File(targetMusicFile); File file1 = new File(targetPicFile); try { if (file.exists()) { file.delete(); } if (file1.exists()) { file1.delete(); } } catch (Exception e1) { e1.printStackTrace(); } Log.d(TAG, "网络不可用!"); } } }).start();
在DownloadService中创建了一个下载任务DownloadUtil,其代码如下:
package com.example.comfortmusic_1.util; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.Map; import com.example.comfortmusic_1.MainActivity; import com.example.comfortmusic_1.fragment.DownloadFragment; import com.example.comfortmusic_1.service.DownloadService; import android.app.Service; import android.content.Context; import android.content.Intent; import android.database.sqlite.SQLiteDatabase; import android.media.MediaScannerConnection; import android.net.Uri; import android.os.Environment; import android.os.IBinder; import android.util.Log; import android.widget.Toast; public class DownloadUtil { private Context context; private String path; private String targetFile; private int threadNum; public DownloadThread[] threads; private int fileSize; private boolean pause = false;//控制下载任务的暂停和继续 private boolean stop = false;//是否删除下载任务 public static boolean isDownloading; public static String TAG = "DownloadUtil"; private int count; private boolean isAlbum; private String musicName; private String artist; SQLiteDatabase db; URL testUrl = null; public DownloadUtil(String musicName, String path, String targetFile, int threadNum, Context context) { this.path = path; this.targetFile = targetFile; this.threadNum = threadNum; this.context = context; this.musicName = musicName; threads = new DownloadThread[threadNum]; db = MainActivity.dbHelper.getReadableDatabase(); try { testUrl = new URL("http://img15.3lian.com/2015/f2/50/d/71.jpg"); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //将下载任务存进数据库 private void saveDownloadTask(int threadId, int startPos, int currentSize, int completeSize, int fileSize) { db.execSQL("insert into downloadTask_1 values(null, ?, ?, ?, ?, ?, ?, ?, ?, ?)", new Object[] {musicName, path, targetFile, threadNum, threadId, start 1016d Pos, currentSize, completeSize, fileSize}); Log.d(TAG, musicName + ":thread " + threadId + " 下载信息存储成功!"); } //随着下载的进行更新数据库中已下载数据 private void updateDownloadTask(int id, int completeSize) { // db.execSQL("update downloadTask set completeSize = '" + completeSize + // "' where musicName like '" + musicName + "' and threadId = '" + id + "'" ); db.execSQL("update downloadTask_1 set completeSize = ? " + "where musicName = ? and threadId = ?", new Object[]{completeSize, musicName, id}); Log.d(TAG, musicName + ":thread " + id + " 下载信息更新成功!"); Log.d(TAG, "completeSize = " + completeSize); } //下载完成从数据库移除对应任务 private void removeDownloadTask() { db.execSQL("delete from downloadTask_1 where musicName = '" + musicName + "'"); Log.d(TAG, musicName + ":下载完成,移出数据库"); } //从头开始下载调用该方法,断点下载将调用continueDownloadTask public void download() throws Exception { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5*1000); conn.setRequestMethod("GET"); fileSize = conn.getContentLength(); Log.d(TAG, "fileSize = " + fileSize); int partSize = fileSize / threadNum + 1; conn.disconnect(); File file = new File(targetFile); if (!file.exists()) { file.createNewFile(); } RandomAccessFile raf = new RandomAccessFile(file, "rwd"); raf.setLength(fileSize); raf.close(); for (int i=0; i<threadNum; i++) { Log.d("DownloadUtil", "init thread"); int startPos = i * partSize; RandomAccessFile currentRaf = new RandomAccessFile(targetFile, "rwd"); currentRaf.seek(startPos); threads[i] = new DownloadThread(i, startPos, partSize, currentRaf); threads[i].start(); Log.d("DownloadUtil", "thread" + i); saveDownloadTask(i, startPos, partSize, 0, fileSize); } isDownloading = true; DownloadService.downloadTask++; } //断点下载调用该方法继续下载 public void continueDownloadTask(Map<String, Object> map) { fileSize = Integer.parseInt((String) map.get("fileSize")); for (int i=0; i<threadNum; i++) { try { Log.d("DownloadUtil", "continue download thread"); int startPos = Integer.parseInt((String) map.get("startPos")) + Integer.parseInt((String) map.get("completeSize")); RandomAccessFile currentRaf = new RandomAccessFile((String) map.get("targetFile"), "rwd"); currentRaf.seek(startPos); int partSize = Integer.parseInt((String) map.get("currentSize"));//- Integer.parseInt((String) map.get("completeSize")); threads[i] = new DownloadThread(i, startPos, partSize, currentRaf); threads[i].setLength(Integer.parseInt((String) map.get("completeSize"))); Log.d(TAG, "threads" + i + "completeSize = " + (String) map.get("completeSize")); threads[i].start(); Log.d("DownloadUtil", "continue thread:" + i); updateDownloadTask(i, threads[i].length); } catch (Exception e) { e.printStackTrace(); } } isDownloading = true; DownloadService.downloadTask++; } public int getCompleteRate () { int sumSize = 0; for (DownloadThread thread: threads) { sumSize += thread.length; } Log.d(TAG, "fileSize = " + fileSize); return sumSize * 100 / fileSize; } public static void skipFully (InputStream in, long bytes) throws IOException { long remaining = bytes; long len = 0; while (remaining > 0) { len = in.skip(remaining); remaining -= len; } } //下载任务线程 private class DownloadThread extends Thread { private int startPos; private int currentPartSize; private RandomAccessFile currentRaf; public int length = 0; private int id; public DownloadThread(int id, int startPos, int currentPartSize, RandomAccessFile currentRaf) { this.id = id; this.startPos = startPos; this.currentPartSize = currentPartSize; this.currentRaf = currentRaf; } @Override public void run() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5*1000); conn.setRequestMethod("GET"); conn.setRequestProperty("Range", "bytes = " + currentPartSize); InputStream inStream = conn.getInputStream(); skipFully(inStream, this.startPos); byte[] buffer = new byte[1024]; int hasRead = 0; while (length < currentPartSize && (hasRead = inStream.read(buffer)) > 0 && !stop && !MainActivity.exit) { while (pause) {//如果pause=true则暂停下载任务-死循环,pause=false时断开死循环继续下载 Log.d("DownloadThread", "Thread pause! " ); if(stop) {//stop=true时终止下载并在DownloadFragment里删除对应的文件 Log.d("DownloadThread", "Thread break! " ); break; } } Log.d("DownloadThread", "Thread start running! " ); currentRaf.write(buffer, 0, hasRead); length += hasRead; updateDownloadTask(id,length); Log.d("DownloadThread", "Thread running! " ); } currentRaf.close(); inStream.close(); if (stop) { return; } sleep(500); notifyDownloadFragment();//下载完成通知 } catch (Exception e) { e.printStackTrace(); Log.d(TAG, "网络不可用!"); } } public int getLength() { return length; } public void setLength(int length) { this.length = length; } } private void notifyDownloadFragment() { count++; Intent intent = new Intent(); if (count == threadNum) { Log.d("DownloadThread", "下载完成"); if (isAlbum) { intent.setAction("action.refreshAlbum"); } else { intent.setAction("action.downloadComplete"); } DownloadService.threadList.remove(DownloadUtil.this); // DownloadService.downloadingList.remove(DownloadUtil.this); DownloadService.downloadTask--; if (DownloadService.downloadTask == 0) isDownloading = false; Log.d(TAG, "downloadingList" + DownloadFragment.downloadingList.size()); removeDownloadTask(); scanFile(context, targetFile); } context.sendBroadcast(intent); } /下载完成后扫描添加到音乐列表中 public void scanFile(Context context, String filePath) { // Toast.makeText(context, " scanning file...", 300).show(); MediaScannerConnection.scanFile(context, new String[] { filePath }, null, new MediaScannerConnection.OnScanCompletedListener() { public void onScanCompleted(String path1, Uri uri) { Log.i("ExternalStorage", "Scanned " + path1); Log.i("ExternalStorage", "-> uri=" + uri); } }); Log.d(TAG, "scanFile"); try { new Thread().sleep(1000); notifyMainActivity(); } catch (InterruptedException e) { e.printStackTrace(); } } //通知MainActivity更新音乐列表 protected void notifyMainActivity() { Intent intent = new Intent(); intent.setAction("action.refreshMusicList"); context.sendBroadcast(intent); } public boolean isPause() { return pause; } public void setPause(boolean pause) { this.pause = pause; } public boolean isStop() { return stop; } public void setStop(boolean stop) { this.stop = stop; if (stop) { File file = new File(targetFile); if (file.exists()) { file.delete(); Log.d("DownloadThread", "移除下载任务:" + file.getName()); if (DownloadService.downloadTask > 0) DownloadService.downloadTask--; removeDownloadTask(); } } } public boolean isDownloading() { return isDownloading; } public void setDownloading(boolean isDownloading) { this.isDownloading = isDownloading; } public boolean isAlbum() { return isAlbum; } public void setAlbum(boolean isAlbum) { this.isAlbum = isAlbum; } }
同时MainActivity中需要添加几个变量:
public static MyDatabaseHelper dbHelper; public static String downloadedPath;//下载路径 public static boolean exit = false;//退出应用 //init in onCreate downloadedPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/musicplayer"; dbHelper = new MyDatabaseHelper(this, "comfortmusic_1.db3", 1);
数据库类MyDatabaseHelper:
package com.example.comfortmusic_1.sqlite; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class MyDatabaseHelper extends SQLiteOpenHelper { final String CREATE_TABLE_SQL = "create table downloadedMusic_1(_id integer primary key autoincrement, title, artist, duration, url)"; final String CREATE_DOWNLOAD_TASK = "create table downloadTask_1(_id integer primary key autoincrement," + " musicName, url, targetFile, threadNum, threadId, startPos, currentSize, completeSize, fileSize)"; public MyDatabaseHelper(Context context, String name, int version) { super(context, name, null, version); } @Override public void onCreate(SQLiteDatabase db) { // TODO Auto-generated method stub db.execSQL(CREATE_DOWNLOAD_TASK); db.execSQL(CREATE_TABLE_SQL); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO Auto-generated method stub System.out.println("-------------onUpdate Called-----------" + oldVersion + "------>" + newVersion); } }
到这里下载和试听的主要代码差不多了,代码的方法名都是根据意义来取的,比较好懂;下一节将讲述下载列表的展示和下载的暂停/继续/删除功能.
项目源码下载地址如下:
Android本地及网络音乐播放器
相关文章推荐
- Android开发本地及网络Mp3音乐播放器(十五)网络音乐及歌词下载功能实现
- 22_Android中的本地音乐播放器和网络音乐播放器的编写,本地视频播放器和网络视频播放器,照相机案例,偷拍案例实现
- 基于android的网络音乐播放器-下载完成后下拉音乐列表刷新(八)
- Android本地及网络音乐播放器-播放本地音乐(一)
- Android播放器推荐:可以播放本地音乐、视频、在线播放音乐、视频、网络收音机等
- Android本地及网络音乐播放器-网络音乐的搜索(三)
- Android开发本地及网络Mp3音乐播放器(十四)网络音乐下载功能实现
- Android开发本地及网络Mp3音乐播放器(十四)网络音乐下载功能实现
- 基于android的网络音乐播放器-下载任务的暂停/继续/删除以及断点下载(七)
- 基于android的网络音乐播放器-本地音乐的加载和后台播放(一)
- Android开发本地及网络Mp3音乐播放器(二十)歌曲下载完成后通知主界面更新本地音乐
- Android开发本地及网络Mp3音乐播放器(二十)歌曲下载完成后通知主界面更新本地音乐
- Android本地及网络音乐播放器-播放界面显示(二)
- Android开发本地及网络Mp3音乐播放器(十五)网络音乐及歌词下载功能实现
- Android 下载网络图片并显示到本地
- Android开发本地及网络Mp3音乐播放器(九)音乐收藏与列表切换
- Android:ListView异步加载图片(实现网络下载、存储本地、缓存内存、压缩显示)
- Android开发本地及网络Mp3音乐播放器(九)音乐收藏与列表切换
- Android开发本地及网络Mp3音乐播放器(十一)使用Jsoup组件请求网络,并解析音乐数据
- Android异步从网络下载图片并且缓存图片到本地的demo