项目实例:https://download.csdn.net/download/qq_37437983/10484636
实现环境:
1)Lenovo G50-80 Ubuntu16.04笔记本
2)Android Studio
3)Eclipse J2EE
4)Tomcat 8.5
5)sqlServer
6)jdk1.8
概要设计
基于Android平台的MP3在线播放器的设计与实现的目标为:
(l)采用布局和组件绘制系统界面。
(2)完成系统中登录界面和播放界面之间的跳转。
(3)实现界面上端的歌曲信息展示。
(4)实现在线播放功能。
(4)实现歌曲的上一首和下一首切换。
数据库表设计
(1) 用户表Userlogin,管理员信息表用于存放管理员的相关信息,结构如表1所示。
(2) 题目表Mp3Info,题目表用于存放用户答错的题目,结构如表2所示。
登录模块
运行在线Mp3播放系统,首先进入系统的登录界面。如图所示:
图8 登陆界面
登陆时需要判断用户名和密码是否正确,首先Android端提出登录请求并将请求帐号和密码通过Get形式传送出去,代码如下:
public class UserLogin extends AsyncTask<Void,Void,String> {
private String account;
private String password;
UserLogin(String account,String password){
this.account = account;
this.password = password;
}
@Override
protected String doInBackground(Void... voids) {
String PATH = "http://192.168.43.102:8080/Mp3Manager/login?account="+account+"&password="+password;
String result = "";
try {
HttpGet get = new HttpGet(new URI(PATH));
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(get);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
result = EntityUtils.toString(response.getEntity());
Log.v("+++++++++++++++++++", result);
}else {
Log.v("-------------------", result);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
protected void onPostExecute(String result){
if(result.equals("yes")){
Intent intent = new Intent(mactivity,PlayArea.class);
mactivity.startActivity(intent);
// Toast.makeText(mactivity, "登录成功", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(mactivity, "登录失败,请输入正确的帐号和密码", Toast.LENGTH_SHORT).show();
}
}
}
JavaEE后台收到请求后,通过web.xml筛选后执行UserLogin.java文件,代码如下:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String account = request.getParameter("account");
String password = request.getParameter("password");
String sql = "select password from UserCollection where account = '"+account+"'";
DBOper db = new DBOper();
ResultSet rs = db.exeQuery(sql);
try {
if(rs.next()&&rs.getString(1).equals(password)) {
response.getWriter().append("yes");
// System.out.println("yes");
}else {
response.getWriter().append("no");
// System.out.println("no");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
图9,用户名后台
5.2 播放音乐模块
登录成功之后进入主界面,如图所示:
图10 主界面
此界面分为两部分,上面的部分是歌曲列表,可以根据歌曲多少自适应调整高度,并且点击之后会显示出歌曲的详细信息;下面部分是播放模块,可进行音乐的播放和暂停,并且还可进行上一曲和下一曲的音乐切换.Android端实现的代码如下:
public class myAsyncTask extends AsyncTask<Void, Void, String> {
/**
* 用于异步下载数据
*/
@Override
protected String doInBackground(Void... arg0) {
// TODO Auto-generated method stub
String result = "";
String PATH = "http://192.168.43.102:8080/Mp3Manager/getMp3Info?";
try {
HttpGet get = new HttpGet(new URI(PATH));
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(get);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
result = EntityUtils.toString(response.getEntity());
// 从后台获得的数据去掉空格
result = result.trim();
Log.v("++++++++++", result);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
/**
* 解析result(json格式的字符串)并将之存入到lists中
*/
@Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
try {
JSONArray array = new JSONObject(result).getJSONArray("MP3INFO");
for (int i = 0; i < array.length(); i++) {
Mp3Info mp3 = new Mp3Info();
JSONObject object = array.getJSONObject(i);
// Log.v("+++++++++++++++++++++", i+"+++++++++++++++++++");
String id = object.getString("id").toString();
String song = object.getString("song").toString();
String Zsong = object.getString("Zsong").toString();
String singer = object.getString("singer").toString();
String album = object.getString("album").toString();
String notes = object.getString("notes").toString();
mp3.setAlbum(album);
mp3.setId(id);
mp3.setNotes(notes);
mp3.setSong(song);
mp3.setZsong(Zsong);
mp3.setSinger(singer);
lists.add(mp3);
listSong.add(Zsong);
}
lenMp3 = lists.size();
ArrayAdapter<String> adapter = new ArrayAdapter<String>(PlayArea.this,android.R.layout.simple_list_item_1,listSong);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
curMp3 = i;
Mp3Info mp3Info = (Mp3Info)lists.get(i);
String id = mp3Info.getId().toString();
final String song = mp3Info.getSong().toString();
final String Zsong = mp3Info.getZsong().toString();
final String singer = mp3Info.getSinger().toString();
String album = mp3Info.getAlbum().toString();
String notes = mp3Info.getNotes().toString();
new AlertDialog.Builder(PlayArea.this)
.setIcon(R.drawable.title)
.setTitle("歌曲简介")
.setMessage("歌曲: "+Zsong+"\n\ni d: "+id+"\n\n歌 手: "+singer+"\n\n专 辑: "+album+"\n\n备 注: "+notes)
.setPositiveButton("播放",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
PlayMp3 playMp3 = new PlayMp3();
playMp3.init(song,Zsong,singer);
// Toast.makeText(PlayArea.this, "点击播放 ", Toast.LENGTH_SHORT).show();
}
})
.setNegativeButton("关闭",null)
.show();
}
});
ivMusicPlay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
PlayMp3 playMp3 = new PlayMp3();
playMp3.init();
}
});
ivMusicPre.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
curMp3--;
if(curMp3<0) curMp3 = lenMp3-1;
Mp3Info mp3Info = (Mp3Info) lists.get(curMp3);
final String song = mp3Info.getSong().toString();
final String Zsong = mp3Info.getZsong().toString();
final String singer = mp3Info.getSinger().toString();
PlayMp3 playMp3 = new PlayMp3();
playMp3.init(song,Zsong,singer);
}
});
ivMusicNext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
curMp3++;
if(curMp3>=lenMp3) curMp3 = 0;
Mp3Info mp3Info = (Mp3Info) lists.get(curMp3);
final String song = mp3Info.getSong().toString();
final String Zsong = mp3Info.getZsong().toString();
final String singer = mp3Info.getSinger().toString();
PlayMp3 playMp3 = new PlayMp3();
playMp3.init(song,Zsong,singer);
}
});
} catch (Exception e) {
// TODO Auto-generated catch block
Log.v("+++++++++++++++++++++", e.getMessage());
e.printStackTrace();
}
super.onPostExecute(result);
}
}
图11 点击列表显示详情信息
Android端显示的信息是后台Gson将封装好的list转换为String对象传给Android端解析.代码如下:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//获取gson
Gson gson = new Gson();
List<Mp3Info> infos = new ArrayList<>();
//获取数据库信息
DBOper db = new DBOper();
String sql = "select * from Mp3Info";
ResultSet rs = db.exeQuery(sql);
try {
while(rs.next()) {
Mp3Info info = new Mp3Info();
String id = rs.getString(1);
String song = rs.getString(2);
String Zsong = rs.getString(3);
String singer = rs.getString(4);
String album = rs.getString(5);
String notes = rs.getString(6);
info.setId(id);
info.setSong(song);
info.setAlbum(album);
info.setNotes(notes);
info.setZsong(Zsong);
info.setSinger(singer);
infos.add(info);
}
//将infos转换为json格式的字符串
String str = gson.toJson(infos);
request.setAttribute("MP3INFO", "{\"MP3INFO\":"+str+"}");
request.getRequestDispatcher("index.jsp").forward(request, response);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
response.getWriter().append("Served at: ").append(request.getContextPath());
}
图12 后台歌曲信息界面
5.3 播放器数据源获取
本系统的最关键之处就是从后台Mp3库中获取数据源交给MediaPlayer.主要想法就是定义两个Socket:远程Socket和本地Socket.其中远程Socket用于请求服务器资源,本地Socket负责监听mediaplayer请求,并将远程Socket获得数据写入mediaPlayer中进行播放.
(1)首先初始化本地Socket,代码如下:
public MediaPlayerProxy(String writeFileName, boolean writeFile) throws Exception {
currPlayDegree = 0;//当前音乐播放进度
proxyFail = false;//代理播放失败了
cachedFileLength = 0;//已缓存的文件长度
fileTotalLength = 0;//要缓存的文件总长度
currMusicCachedProgress = 0;//当前的音乐缓冲值(seekbar上的缓冲值)
proxyIdle = false; //代理忙
this.writeFile = writeFile;
this.writeFileName = writeFileName;
try {
if (localServer == null || localServer.isClosed()) {
//创建本地socket服务器,用来监听mediaplayer请求和给mediaplayer提供数据
localServer = new ServerSocket();
localServer.setReuseAddress(true);
//创建IP地址为192.168.43.1,端口号为9090的本地端口地址
InetSocketAddress socketAddress = new InetSocketAddress(InetAddress.getByName(LOCAL_IP_ADDRESS), local_ip_port);
//本地socket绑定本地端口地址
localServer.bind(socketAddress);
}
} catch (Exception e) {
Log.e("1111111111111111+++++++",e.getMessage());
try {
local_ip_port--; //端口号非空闲,自减
localServer = new ServerSocket();
localServer.setReuseAddress(true);
//创建IP地址为192.168.43.1,端口号为9090的本地端口地址
InetSocketAddress socketAddress = new InetSocketAddress(InetAddress.getByName(LOCAL_IP_ADDRESS), local_ip_port);
//本地socket绑定本地端口地址
localServer.bind(socketAddress);
} catch (Exception e2) {
Log.e("22222222222222++++++",e2.getMessage());
throw new Exception();
}
}
}
(2)根据真实的请求音源文件地址,得到本地音源文件地址将本地音源地址通过setDataSource的方式传递给mediaplayer. 前面创建的本地socket对象监听这个地址,用于获取mediaplayer的请求数据。代码如下:
public String getLocalURLAndSetRemotSocketAddr(String url) {
try {
remotUrl = url;
if (writeFile) { //正在缓存的音乐地址
bufferingMusicUrlList.add(remotUrl);
}
String localProxyUrl = "";
final URI originalURI = URI.create(url);
final String remoteHost = originalURI.getHost(); //服务器主机
if (!TextUtils.isEmpty(remoteHost)) { //存在主机
if (originalURI.getPort() != -1) {//URL带Port
new Thread(new Runnable() {
@Override
public void run() {
//服务器的主机号和端口
remoteAddress = new InetSocketAddress(remoteHost, originalURI.getPort());
}
}).start();
//替换
localProxyUrl = url.replace(remoteHost + ":" + originalURI.getPort(), LOCAL_IP_ADDRESS + ":" + local_ip_port);
remoteHostAndPort = remoteHost + ":" + originalURI.getPort();
} else {//URL不带Port,使用80端口
if (!TextUtils.isEmpty(remoteHost)) {
new Thread(new Runnable() {
@Override
public void run() {
remoteAddress = new InetSocketAddress(remoteHost, HTTP_PORT);//使用80端口
}
}).start();
localProxyUrl = url.replace(remoteHost, LOCAL_IP_ADDRESS + ":" + local_ip_port);
remoteHostAndPort = remoteHost;
}
}
}
return localProxyUrl;
} catch (Exception e) {
Log.e("+333333333333++++++++++",e.getMessage());
return "";
}
}
(3)本地socket监听mediaplayer,通过getInputStream方法可以获取到mediaplayer传递过来的请求信息数据,由于我们是通过本地代理地址的方式获取到的,所以我们需要根据这个本地的请求信息替换成真实的远程socket请求信息,向服务器获取真实请求数据。代码如下:
public void getTrueSocketRequestInfo(Socket localSocket) throws Exception {
InputStream in_localSocket = localSocket.getInputStream();
String trueSocketRequestInfoStr = "";//保存MediaPlayer的真实HTTP请求
byte[] local_request = new byte[1024];
while (in_localSocket.read(local_request) != -1) {
String str = new String(local_request);
trueSocketRequestInfoStr = trueSocketRequestInfoStr + str;
if (trueSocketRequestInfoStr.contains("GET") && trueSocketRequestInfoStr.contains("\r\n\r\n")) {
//把request中的本地ip改为远程ip
trueSocketRequestInfoStr = trueSocketRequestInfoStr.replace(LOCAL_IP_ADDRESS + ":" + local_ip_port, remoteHostAndPort);
this.trueSocketRequestInfoStr = trueSocketRequestInfoStr;
//如果用户拖动了进度条,因为拖动了滚动条还有Range则表示本地歌曲还未缓存完,不再保存
if (trueSocketRequestInfoStr.contains("Range")) {
Log.e("+44444++++Range++++++","");
writeFile = false;
}
break;
}
}
}
(4)上一步我们获取到了真实的请求数据信息,此时通过远程socket连接远程请求,代码如下:
public Socket sendRemoteRequest() throws Exception {
//创建远程socket用来请求网络数据
Socket remoteSocket = new Socket();
remoteSocket.connect(remoteAddress, socketTimeoutTime);
remoteSocket.getOutputStream().write(trueSocketRequestInfoStr.getBytes());
remoteSocket.getOutputStream().flush();
return remoteSocket;
}
(5)将远程socket的数据,通过本地socket写入mediaplayer进行播放
(6)最后在PlayMp3.java文件中调用,代码如下:
private void playMusic() {
if(Zsong!=""&&singer!=""){
tv_Name.setText(Zsong);
tv_author.setText(singer);
}
ivMusicPlay.setImageResource(R.mipmap.music_button_pause);
currentState = STATE_PLAY;
* 第一次执行加载数据,之后执行暂停,开始
* */
if (!firstPlay && mediaPlayer.getCurrentPosition() > 0) {
mediaPlayerHttpProxy = null;
mediaPlayer.start();
} else {
try {
// Toast.makeText(playArea, Zsong+"加载"+mediaPlayer.getCurrentPosition(), Toast.LENGTH_SHORT).show();
mediaPlayerHttpProxy = new MediaPlayerProxy(Zsong, false);
//setProgress是文件写入本地进度,setSecondaryProgress就是文件加载进度
mediaPlayerHttpProxy.setOnCaChedProgressUpdateListener(new MediaPlayerProxy.OnCaChedProgressUpdateListener() {
@Override
public void updateCachedProgress(int progress) {
sb_music.setSecondaryProgress(progress);
}
});
//得到从服务器得到的数据源
String localProxyUrl = mediaPlayerHttpProxy.getLocalURLAndSetRemotSocketAddr(TEST_URL);
mediaPlayerHttpProxy.startProxy();
mediaPlayer.setDataSource(localProxyUrl);
mediaPlayer.prepareAsync();
firstPlay = false;
} catch (Exception e) {
Log.e("++++++++++++++++++++",e.getMessage());
}
}
}
项目实例:https://download.csdn.net/download/qq_37437983/10484636