1. 程式人生 > >Android從本地伺服器獲取Mp3實現邊下邊播(JavaEE+Tomcat+SQLServer)

Android從本地伺服器獲取Mp3實現邊下邊播(JavaEE+Tomcat+SQLServer)

實現環境:

    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());
        }
    }
}