安卓案例:基於網絡樂庫音樂播放器V1.0

目錄

一、項目功能要求

二、涉及知識點

1、MVC模式

2、安卓核心組件

3、意圖(Intent)

4、安卓控件

5、自定義適配器

6、遊標(Cursor)

7、數組列表(ArrayList)

8、補間動畫(Tween Animation)

9、菜單(Menu)

10、共享參數(SharedPreferences)

10、Java數據庫連接(JDBC)

11、MySQL數據庫

12、Servlet基礎知識

13、JSP基礎知識

三、數據庫設計

1、用戶表(user)結構及記錄

2、音樂表(music)結構及記錄

四、Web服務器端:MusicServer

1、在Intellij IDEA裏創建Java項目MusicServer

2、在web目錄下創建lib目錄,添加項目所需jar包

3、在web目錄下創建music目錄,拷貝若干mp3音樂

4、在web目錄下創建images目錄,拷貝音樂專輯圖片

5、在web目錄下創建index.jsp頁面

6、在部署描述文件web.xml裏設置首頁

7、配置Tomcat服務器

(1)打開“編輯配置”對話框

(2)在Defaults列表項裏找到Tomcat Server,點開後選擇local:

(3)單擊【+】按鈕,配置本項目的Web服務器

8、在web目錄下創建登錄頁面login.jsp

9、創建net.hw.music.bean包,在裏面創建用戶實體類User

10、在net.hw.music.bean包裏創建音樂實體類Music

11、創建net.hw.music.util包,在裏面創建數據庫連接管理類ConnectionManager

12、創建net.hw.music.dao包,在裏面創建用戶數據訪問接口UserDao

13、在net.hw.music.dao包裏創建音樂數據訪問接口MusicDao

14、在net.hw.music.dao裏創建impl包,在裏面創建用戶數據訪問接口實現類UserDaoImpl

15、在net.hw.music.dao.impl包裏創建音樂數據訪問接口實現類MusicDaoImpl

16、創建net.hw.music.service包,在裏面創建用戶服務接口UserService

17、在net.hw.music.service包裏創建音樂服務接口MusicService

18、在net.hw.music.service包裏創建impl子包,在impl裏創建用戶服務接口實現類UserServiceImpl

19、在net.hw.music.service.impl包裏創建音樂服務接口實現類MusicServiceImpl

20、創建net.hw.music.servlet包,在裏面創建登錄處理類LoginServlet

21、在net.hw.music.servlet包裏,創建獲取音樂列表處理類GetMusicListServlet

四、安卓客戶端:WebMusicPlayerV1.0

1、創建安卓應用WebMusicPlayerV1.0

2、準備圖片素材,拷貝到res下的mipmap目錄

3、創建ui子包,將SplashScreenActivity拖進ui子包

4、在res裏創建anim目錄,在裏面創建動畫資源文件animator.xml

5、創建自定義邊框配置文件custom_border.xml

6、在drawable目錄裏創建按鈕背景選擇器

(1)下一首按鈕背景選擇器(next_button_selector.xml)

(2)暫停按鈕背景選擇器(pause_button_selector.xml)

(3)播放按鈕背景選擇器(play_button_selector.xml)

(4)上一首按鈕背景選擇器(previous_button_selector.xml)

7、創建entity子包,在裏面創建Music實體類

8、創建app子包,在裏面創建應用程序常量接口AppConstants

9、修改模塊的build.gradle文件

10、在app子包裏創建網絡音樂播放器應用程序類WebMusicPlayerApplicaton

(1)編寫網絡音樂播放器應用程序類WebMusicPlayerApplicaton

(2)在項目清單文件AndroidManifest.xml文件註冊

11、創建adapter子包,在裏面創建音樂適配器MusicAdapter

(1)在layout目錄裏創建音樂列表項模板music_list_item.xml

(2)編寫音樂適配器MusicAdapter

12、創建service子包,在裏面創建音樂播放服務類MusicPlayService

(1)編寫音樂播放服務類MusicPlayService

(2)在項目清單文件裏註冊音樂播放服務

13、啓動界面類SplashScreenActivity

(1)啓動界面佈局文件activity_splash_screen.xml

(2)字符串資源文件strings.xml

(3)編寫啓動界面類SplashScreenActivity

14、在ui子包裏創建登錄界面LoginActivity

(1)登錄界面佈局文件activity_login.xml

(2)字符串資源文件strings.xml

(3)編寫登錄界面類LoginActivity

15、在ui子包裏創建主界面類

(1)主界面佈局文件activity_main.xml

(2)在res下創建menu目錄,在裏面創建主界面菜單資源文件main.xml

(3)字符串資源文件strings.xml

(4)編寫主界面類MainActivity

16、在項目清單文件裏授權訪問因特網

五、運行項目

1、啓動服務器端MusicServer

2、啓動安卓客戶端WebMusicPlayerV1.0


一、項目功能要求

1、數據源來自服務器端音樂庫(數據庫保存專輯圖片與音樂路徑)
2、列表顯示音樂文件(專輯封面圖片、音樂名、演唱者、播放時長)
3、音樂列表可按音樂標識符、標題或播放時長排序
4、利用自定義Service類來實現音樂的播放與暫停以及進度的更新
5、界面類(Activity)與服務類(Service)之間通過廣播接收者進行通信
6、主界面包含播放列表、可設置播放模式、顯示當前音樂名、拖拽條顯示和設置播放進度、顯示播放進度值和播放時長、包含上一首按鈕、下一首按鈕、播放|暫停按鈕

 

二、涉及知識點

1、MVC模式

MVC模式強制性地使應用程序的輸入、處理和輸出分開。使用MVC模式,應用程序被分成三個核心部件:模型(Model,即M)、視圖(View,即V)、控制器(Controller,即C)。它們各自處理自己的任務。
 
分層架構:展現層(Activity)<——>控制層(Servlet)<——>業務層(Service)<——>模型層(Dao)<——>數據庫(DB)

2、安卓核心組件

活動(Activity)、服務(Service)、廣播接收者(BroadcastReceiver)

3、意圖(Intent)

通過意圖激活Activity和Service、發送廣播。

4、安卓控件

按鈕(Button)、標籤(TextView)、拖拽條(SeekBar)、列表控件(ListView)、單選按鈕(RadioButton)、媒體播放器(MediaPlayer)

5、自定義適配器

繼承基適配器(BaseAdapter)創建自定義適配器

6、遊標(Cursor)

7、數組列表(ArrayList)

8、補間動畫(Tween Animation)

9、菜單(Menu)

10、共享參數(SharedPreferences)

10、Java數據庫連接(JDBC)

11、MySQL數據庫

12、Servlet基礎知識

13、JSP基礎知識

 
  • 難點1:通過異步任務從服務器端下載專輯圖片並顯示在列表項裏。
  • 難點2:解決中文數據在網絡傳輸過程中產生的亂碼問題。

三、數據庫設計

MySQL數據庫music_store包含兩張表:用戶表(user)、音樂表(music) 

1、用戶表(user)結構及記錄

2、音樂表(music)結構及記錄

四、Web服務器端:MusicServer

1、在Intellij IDEA裏創建Java項目MusicServer

輸入項目名:

打開項目結構對話框的Modules項,單擊【+】按鈕,增加Web支持:

單擊【Create Artifact】按鈕:

2、在web目錄下創建lib目錄,添加項目所需jar包

jar包下載鏈接:https://pan.baidu.com/s/16w3lPewWYjVvlIir6dYXtw  提取碼:sqja

選中全部jar包,單擊右鍵,選擇“Add as Libary”菜單項:

3、在web目錄下創建music目錄,拷貝若干mp3音樂

4、在web目錄下創建images目錄,拷貝音樂專輯圖片

5、在web目錄下創建index.jsp頁面

6、在部署描述文件web.xml裏設置首頁

7、配置Tomcat服務器

(1)打開“編輯配置”對話框

(2)在Defaults列表項裏找到Tomcat Server,點開後選擇local:

單擊【Configure】按鈕,配置好Tomcat的根目錄:

(3)單擊【+】按鈕,配置本項目的Web服務器

在列表裏去找Tomcat Server:

輸入Tomcat Server的名稱:tomcat 8.0

 

單擊【Fix】按鈕:

單擊【運行】按鈕:

此時,可以訪問項目的靜態資源(音樂專輯圖片):

可以訪問項目的靜態資源(音樂文件):

8、在web目錄下創建登錄頁面login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用戶登錄</title>
    <script type="text/javascript">
        function checkLoginForm() {
            // 獲取用戶名與密碼文本框
            var txtusername = document.getElementById("username");
            var txtpassword = document.getElementById("password");

            // 獲取用戶名與密碼
            var username = txtusername.value;
            var password = txtpassword.value;

            // 非空校驗
            if (username == "") {
                alert("用戶名不能爲空!");
                txtusername.focus();
                return false;
            }
            if (password == "") {
                alert("密碼不能爲空!");
                txtpassword.focus();
                return false;
            }
            return true;
        }

    </script>
</head>
<body>
<h3>用戶登錄</h3>
<hr/>
<form id="frmLogin" action="login" method="post">
    <table border="1">
        <tr>
            <td>賬號:</td>
            <td>
                <input id="username" name="username" type="text"/>
            </td>
        </tr>
        <tr>
            <td>密碼:</td>
            <td>
                <input id="password" name="password" type="password"/>
            </td>
        </tr>
        <tr align="center">
            <td colspan="2">
                <input type="submit" value="登錄" onclick="return checkLoginForm()"/>
                <input type="reset" value="重置"/>
            </td>
        </tr>
    </table>
</form>
</body>
</html>

9、創建net.hw.music.bean包,在裏面創建用戶實體類User

 

package net.hw.music.bean;

/**
 * 用戶實體類
 */
public class User {    
    private int id;
    private String username;
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

10、在net.hw.music.bean包裏創建音樂實體類Music

package net.hw.music.bean;

/**
 * 音樂實體類
 */
public class Music {
    /**
     * 音樂標識
     */
    private int id;
    /**
     * 音樂數據(路徑+文件名)
     */
    private String data;
    /**
     * 音樂標題
     */
    private String title;
    /**
     * 演唱者
     */
    private String artist;
    /**
     * 音樂時長
     */
    private int duration;
    /**
     * 音樂專輯圖片(路徑+文件名)
     */
    private String album;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getArtist() {
        return artist;
    }

    public void setArtist(String artist) {
        this.artist = artist;
    }

    public int getDuration() {
        return duration;
    }

    public void setDuration(int duration) {
        this.duration = duration;
    }

    public String getAlbum() {
        return album;
    }

    public void setAlbum(String album) {
        this.album = album;
    }

    @Override
    public String toString() {
        return "Music{" +
                "id=" + id +
                ", data='" + data + '\'' +
                ", title='" + title + '\'' +
                ", artist='" + artist + '\'' +
                ", duration=" + duration +
                ", album='" + album + '\'' +
                '}';
    }
}

11、創建net.hw.music.util包,在裏面創建數據庫連接管理類ConnectionManager

package net.hw.music.util;

import javax.swing.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class ConnectionManager {
    /**
     * 數據庫驅動程序
     */
    private static final String DRIVER = "com.mysql.jdbc.Driver";
    /**
     * 數據庫統一資源定位符
     */
    private static final String URL = "jdbc:mysql://localhost:3306/music_store";
    /**
     * 數據庫用戶名
     */
    private static final String USER = "root";
    /**
     * 數據庫密碼
     */
    private static final String PASSWORD = "1";

    /**
     * 私有化構造方法,禁止實例化
     */
    private ConnectionManager() {
    }

    /**
     * 獲取數據庫連接
     *
     * @return
     */
    public static Connection getConnection() {
        // 聲明數據庫連接
        Connection conn = null;

        try {
            // 安裝數據庫驅動程序
            Class.forName(DRIVER);
            // 獲取數據庫連接
            conn = DriverManager.getConnection(URL + "?useUnicode=true&characterEncoding=UTF8", USER, PASSWORD);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }

        // 返回數據庫連接
        return conn;
    }

    /**
     * 關閉數據庫連接
     *
     * @param conn
     */
    public static void closeConnection(Connection conn) {
        if (conn != null) {
            try {
                if (!conn.isClosed()) {
                    // 關閉連接
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 主方法:測試數據庫連接
     *
     * @param args
     */
    public static void main(String[] args) {
        Connection conn = getConnection();
        if (conn != null) {
            JOptionPane.showMessageDialog(null, "恭喜,數據庫連接成功!");
        } else {
            JOptionPane.showMessageDialog(null, "遺憾,數據庫連接失敗!");
        }
    }
}
運行程序,結果如下:

12、創建net.hw.music.dao包,在裏面創建用戶數據訪問接口UserDao

package net.hw.music.dao;

import net.hw.music.bean.User;

/**
 * 用戶數據訪問接口
 */
public interface UserDao {
    boolean login(User user);
}

13、在net.hw.music.dao包裏創建音樂數據訪問接口MusicDao

 

package net.hw.music.dao;

import net.hw.music.bean.Music;

import java.util.List;

/**
 * 音樂數據訪問接口
 */
public interface MusicDao {
    List<Music> getMusicList();
}

14、在net.hw.music.dao裏創建impl包,在裏面創建用戶數據訪問接口實現類UserDaoImpl

package net.hw.music.dao.impl;

import net.hw.music.bean.User;
import net.hw.music.dao.UserDao;
import net.hw.music.util.ConnectionManager;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 用戶數據訪問接口實現類
 */
public class UserDaoImpl implements UserDao {
    @Override
    public boolean login(User user) {
        // 獲取數據庫連接
        Connection conn = ConnectionManager.getConnection();
        // 定義SQL字符串
        String strSQL = "SELECT * FROM user WHERE username = ? AND password = ?";
        try {
            // 創建預備語句對象
            PreparedStatement pstmt = conn.prepareStatement(strSQL);
            // 設置佔位符的值
            pstmt.setString(1, user.getUsername());
            pstmt.setString(2, user.getPassword());
            // 執行查詢,返回結果集
            ResultSet rs = pstmt.executeQuery();
            // 判斷結果集裏是否有記錄
            if (rs.next()) {
                // 登錄成功
                return true;
            }
            // 關閉結果集
            rs.close();
            // 關閉預備語句對象
            pstmt.close();
            // 關閉數據庫連接
            ConnectionManager.closeConnection(conn);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        // 登錄失敗
        return false;
    }

    /**
     * 主方法:測試用戶登錄
     *
     * @param args
     */
    public static void main(String[] args) {
        User user = new User();
        user.setUsername("admin");
        user.setPassword("12345");
        UserDao userDao = new UserDaoImpl();
        if (userDao.login(user)) {
            System.out.println("恭喜,用戶[" + user.getUsername() + "]登錄成功!");
        } else {
            System.out.println("遺憾,用戶[" + user.getUsername() + "]登錄失敗!");
        }
    }
}
運行程序,結果如下:

15、在net.hw.music.dao.impl包裏創建音樂數據訪問接口實現類MusicDaoImpl

package net.hw.music.dao.impl;

import net.hw.music.bean.Music;
import net.hw.music.dao.MusicDao;
import net.hw.music.util.ConnectionManager;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * 音樂數據訪問接口實現類
 */
public class MusicDaoImpl implements MusicDao {
    @Override
    public List<Music> getMusicList() {
        // 創建音樂列表
        List<Music> musicList = new ArrayList<>();

        // 獲取數據庫連接
        Connection conn = ConnectionManager.getConnection();
        // 定義SQL字符串
        String strSQL = "SELECT * FROM music";
        try {
            // 創建語句對象
            Statement stmt = conn.createStatement();
            // 執行查詢返回結果集
            ResultSet rs = stmt.executeQuery(strSQL);
            // 遍歷結果集
            while (rs.next()) {
                // 創建音樂實體
                Music music = new Music();
                // 利用當前記錄的字段值設置音樂實體屬性
                music.setId(rs.getInt("id"));
                music.setData(rs.getString("data"));
                music.setTitle(rs.getString("title"));
                music.setDuration(rs.getInt("duration"));
                music.setArtist(rs.getString("artist"));
                music.setAlbum(rs.getString("album"));
                // 將音樂實體添加到音樂列表
                musicList.add(music);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

        // 返回音樂列表
        return musicList;
    }

    /**
     * 主方法:測試音樂列表的獲取
     *
     * @param args
     */
    public static void main(String[] args) {
        MusicDao musicDao = new MusicDaoImpl();
        List<Music> musicList = musicDao.getMusicList();
        for (Music music : musicList) {
            System.out.println(music);
        }
    }
}
運行程序,結果如下:

16、創建net.hw.music.service包,在裏面創建用戶服務接口UserService

 

package net.hw.music.service;

import net.hw.music.bean.User;

/**
 * 用戶服務接口
 */
public interface UserService {
    boolean login(User user);
}

17、在net.hw.music.service包裏創建音樂服務接口MusicService

package net.hw.music.service;

import net.hw.music.bean.Music;

import java.util.List;

/**
 * 音樂服務接口
 */
public interface MusicService {
    List<Music> getMusicList();
}

18、在net.hw.music.service包裏創建impl子包,在impl裏創建用戶服務接口實現類UserServiceImpl

 

package net.hw.music.service.impl;

import net.hw.music.bean.User;
import net.hw.music.dao.UserDao;
import net.hw.music.dao.impl.UserDaoImpl;
import net.hw.music.service.UserService;

/**
 * 用戶服務接口實現類 
 */
public class UserServiceImpl implements UserService{
    private UserDao userDao;    
    
    public UserServiceImpl() {
        userDao = new UserDaoImpl();
    }
    
    @Override
    public boolean login(User user) {
        return userDao.login(user);
    }
}

19、在net.hw.music.service.impl包裏創建音樂服務接口實現類MusicServiceImpl

 

package net.hw.music.service.impl;

import net.hw.music.bean.Music;
import net.hw.music.dao.MusicDao;
import net.hw.music.dao.impl.MusicDaoImpl;
import net.hw.music.service.MusicService;

import java.util.List;

/**
 * 音樂服務接口實現類
 */
public class MusicServiceImpl implements MusicService {
    private MusicDao musicDao;
    
    public MusicServiceImpl() {
        musicDao = new MusicDaoImpl();
    }
    
    @Override
    public List<Music> getMusicList() {
        return musicDao.getMusicList();
    }
}

20、創建net.hw.music.servlet包,在裏面創建登錄處理類LoginServlet

package net.hw.music.servlet;

import net.hw.music.bean.User;
import net.hw.music.service.UserService;
import net.hw.music.service.impl.UserServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 設置請求對象的字符編碼
        request.setCharacterEncoding("utf-8");

        // 獲取客戶端表單提交的數據
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        // 定義用戶
        User user = new User();
        // 設置用戶屬性
        user.setUsername(username);
        user.setPassword(password);

        // 創建用戶服務對象
        UserService us = new UserServiceImpl();
        // 獲取打印輸出流
        PrintWriter out = response.getWriter();
        // 判斷用戶登錄是否成功
        if (us.login(user)) {
            // 向客戶端輸出登錄成功信息
            out.print("success");
            // 在服務器端輸出登錄成功信息
            System.out.print("恭喜,用戶[" + user.getUsername() + "]登錄成功!");
        } else {            
            // 向客戶端輸出登錄失敗信息
            out.print("failure");
            // 在服務器端輸出登錄成功信息
            System.out.print("遺憾,用戶[" + user.getUsername() + "]登錄失敗!");
        }
        // 刷新輸出流
        out.flush();
        // 關閉輸出流
        out.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }
}
啓動服務器,訪問登錄頁面,輸入用戶名和密碼:

單擊【登錄】按鈕:

查看服務器端控制檯:

21、在net.hw.music.servlet包裏,創建獲取音樂列表處理類GetMusicListServlet

package net.hw.music.servlet;

import net.hw.music.bean.Music;
import net.hw.music.service.MusicService;
import net.hw.music.service.impl.MusicServiceImpl;
import net.sf.json.JSONArray;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

/**
 * 獲取音樂列表處理類
 */
@WebServlet("/getMusicList")
public class GetMusicListServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 創建音樂服務對象
        MusicService ms = new MusicServiceImpl();
        // 獲取音樂列表對象
        List<Music> musicList = ms.getMusicList();
        // 將音樂列表對象轉換成JSON字符串用於網絡傳輸
        String musicListJson = JSONArray.fromObject(musicList).toString();
        // 給響應對象設置字符編碼
        response.setCharacterEncoding("gbk");
        // 獲取打印輸出流
        PrintWriter out = response.getWriter();
        // 向客戶端輸出音樂列表JSON字符串
        out.print(musicListJson);
        // 刷新輸出流
        out.flush();
        // 關閉輸出流
        out.close();
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}
啓動服務器,在瀏覽器地址欄裏訪問http://localhost:8080/getMusicList

上圖顯示的是JSON數組,每個數組元素都是一個JSON對象,由六個鍵值對組成。六個鍵分別是id、data、title、artist、duration、album。

四、安卓客戶端:WebMusicPlayerV1.0

1、創建安卓應用WebMusicPlayerV1.0

2、準備圖片素材,拷貝到res下的mipmap目錄

3、創建ui子包,將SplashScreenActivity拖進ui子包

 

4、在res裏創建anim目錄,在裏面創建動畫資源文件animator.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <alpha
        android:duration="3000"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />

    <rotate
        android:duration="3000"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="1"
        android:repeatMode="reverse"
        android:toDegrees="+360" />

</set>

5、創建自定義邊框配置文件custom_border.xml

在res下的drawable目錄裏創建自定義邊框配置文件custom_border.xml,用於設置播放模式線性佈局的邊框:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <corners android:radius="5dp" />

    <solid android:color="#eeeeee"/>

    <stroke
        android:width="1dp"
        android:color="#555" />

    <padding
        android:bottom="10dp"
        android:left="10dp"
        android:right="10dp"
        android:top="10dp" />

</shape>

6、在drawable目錄裏創建按鈕背景選擇器

(1)下一首按鈕背景選擇器(next_button_selector.xml)

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@mipmap/next_button_pressed" android:state_pressed="true"/>
    <item android:drawable="@mipmap/next_button" android:state_pressed="false"/>

</selector>

(2)暫停按鈕背景選擇器(pause_button_selector.xml)

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@mipmap/pause_button_pressed" android:state_pressed="true"/>
    <item android:drawable="@mipmap/pause_button" android:state_pressed="false"/>

</selector>

(3)播放按鈕背景選擇器(play_button_selector.xml)

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@mipmap/play_button_pressed" android:state_pressed="true"/>
    <item android:drawable="@mipmap/play_button" android:state_pressed="false"/>

</selector>

(4)上一首按鈕背景選擇器(previous_button_selector.xml)

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@mipmap/previous_button_pressed" android:state_pressed="true"/>
    <item android:drawable="@mipmap/previous_button" android:state_pressed="false"/>

</selector>

7、創建entity子包,在裏面創建Music實體類

 

package net.hw.web_music_player.entity;

/**
 * 音樂實體類
 */
public class Music {
    /**
     * 音樂標識
     */
    private int id;
    /**
     * 音樂數據(路徑+文件名)
     */
    private String data;
    /**
     * 音樂標題
     */
    private String title;
    /**
     * 演唱者
     */
    private String artist;
    /**
     * 音樂時長
     */
    private int duration;
    /**
     * 音樂專輯圖片(路徑+文件名)
     */
    private String album;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getArtist() {
        return artist;
    }

    public void setArtist(String artist) {
        this.artist = artist;
    }

    public int getDuration() {
        return duration;
    }

    public void setDuration(int duration) {
        this.duration = duration;
    }

    public String getAlbum() {
        return album;
    }

    public void setAlbum(String album) {
        this.album = album;
    }

    @Override
    public String toString() {
        return "Music{" +
                "id=" + id +
                ", data='" + data + '\'' +
                ", title='" + title + '\'' +
                ", artist='" + artist + '\'' +
                ", duration=" + duration +
                ", album='" + album + '\'' +
                '}';
    }
}

8、創建app子包,在裏面創建應用程序常量接口AppConstants

 

package net.hw.web_music_player.app;

/**
 * 應用程序常量接口
 *
 * Created by howard on 2018/1/27.
 */

public interface AppConstants {
    /**
     * 應用程序標記
     */
    String TAG = "net.hw.web_music_player";
    /**
     * 音樂服務器網址
     */
    String MUSIC_SERVER_URL = "http://192.168.86.100:8080";
    /**
     * 廣播頻道常量:播放上一首
     */
    String INTENT_ACTION_PREVIOUS = TAG + ".intent.action.PREVIOUS";
    /**
     * 廣播頻道常量:播放下一首
     */
    String INTENT_ACTION_NEXT = TAG + ".intent.action.NEXT";
    /**
     * 廣播頻道常量:播放或暫停
     */
    String INTENT_ACTION_PLAY_OR_PAUSE = TAG + ".intent.action.PLAY_OR_PAUSE";
    /**
     * 廣播頻道常量:播放
     */
    String INTENT_ACTION_PLAY = TAG + ".intent.action.PLAY";
    /**
     * 廣播頻道常量:更新播放進度
     */
    String INTENT_ACTION_UPDATE_PROGRESS = TAG + ".intent.action.UPDATE_PROGRESS";
    /**
     * 廣播頻道常量:用戶改變播放進度
     */
    String INTENT_ACTION_USER_CHANGE_PROGRESS = TAG + ".intent.action.USER_CHANGE_PROGRESS";
    /**
     * 控制圖標常量:播放或暫停
     */
    String CONTROL_ICON = "control_icon";
    /**
     * 播放時長常量
     */
    String DURATION = "duration";
    /**
     * 播放模式:順序播放
     */
    int PLAY_MODE_ORDER = 0;
    /**
     * 播放模式:隨機播放
     */
    int PLAY_MODE_RANDOM = 1;
    /**
     * 播放模式:單曲循環
     */
    int PLAY_MODE_LOOP = 2;
    /**
     * 用戶配置文件名
     */
    String USER_CONFIG = "user-config";
}
注意:必須將IP地址改成你電腦的IP地址。

9、修改模塊的build.gradle文件

 

在android元素裏添加:useLibrary 'org.apache.http.legacy'

10、在app子包裏創建網絡音樂播放器應用程序類WebMusicPlayerApplicaton

 

(1)編寫網絡音樂播放器應用程序類WebMusicPlayerApplicaton

package net.hw.web_music_player.app;

import android.app.Application;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;

import net.hw.web_music_player.entity.Music;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * 網絡音樂播放器應用程序類
 *
 * Created by howard on 2018/1/27.
 */

public class WebMusicPlayerApplication extends Application implements AppConstants {
    /**
     * 簡單日期格式
     */
    private SimpleDateFormat sdf;
    /**
     * 音樂列表
     */
    private List<Music> musicList;
    /**
     * 專輯圖片數組
     */
    private Bitmap[] albums;
    /**
     * 專輯圖片索引
     */
    private int albumIndex;
    /**
     * 當前音樂索引
     */
    private int currentMusicIndex;
    /**
     * 音樂當前播放位置
     */
    private int currentPosition;
    /**
     * 播放模式
     */
    private int playMode;
    /**
     * 用戶修改的播放進度
     */
    private int progressChangedByUser;

    @Override
    public void onCreate() {
        super.onCreate();
        // 創建簡單日期格式對象
        sdf = new SimpleDateFormat("mm:ss");
        // 定義獲取音樂列表的網址
        String strGetMusicListUrl = MUSIC_SERVER_URL + "/getMusicList";
        // 執行獲取音樂列表異步任務,傳入一個參數:獲取音樂列表的網址
        new GetMusicListTask().execute(strGetMusicListUrl);
    }
    
    

    /**
     * 獲取音樂列表異步任務類
     */
    private class GetMusicListTask extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... params) {
            // 定義結果字符串
            String result = "";
            // 創建get請求
            HttpGet request = new HttpGet(params[0]);
            // 創建http客戶端
            HttpClient client = new DefaultHttpClient();
            try {
                // 執行get請求,返回響應對象
                HttpResponse response = client.execute(request);
                // 根據響應對象裏的狀態碼判斷是否請求成功
                if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    // 獲取響應數據實體
                    HttpEntity entity = response.getEntity();
                    // 將響應數據實體轉換成字符串作爲返回值
                    result = EntityUtils.toString(entity, "gbk");
                }

            } catch (IOException e) {
                e.printStackTrace();
            }

            // 返回結果字符串
            return result;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            // 判斷結果是否爲空
            if (!result.equals("")) {
                /* 將獲取json字符串轉換成數組列表 */
                // 創建音樂列表
                musicList = new ArrayList<>();
                try {
                    // 基於json字符串創建json數組
                    JSONArray array = new JSONArray(result);
                    // 創建專輯圖片數組
                    albums = new Bitmap[array.length()];
                    // 創建json對象
                    JSONObject object;
                    // 遍歷json數組
                    for (int i = 0; i < array.length(); i++) {
                        // 獲取json數組元素
                        object = array.getJSONObject(i);
                        // 創建音樂實體
                        Music music = new Music();
                        // 設置音樂實體屬性
                        music.setId(object.getInt("id"));
                        music.setData(object.getString("data"));
                        music.setTitle(object.getString("title"));
                        music.setArtist(object.getString("artist"));
                        music.setDuration(object.getInt("duration"));
                        music.setAlbum(object.getString("album"));
                        // 執行獲取專輯圖片異步任務,傳入兩個參數(專輯圖片索引,專輯圖片路徑)
                        new GetAlbumTask().execute(String.valueOf(i), music.getAlbum());
                        // 將音樂實體添加到音樂列表
                        musicList.add(music);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 獲取專輯圖片異步任務
     */
    private class GetAlbumTask extends AsyncTask<String, Void, Void> {
        @Override
        protected Void doInBackground(String... params) {
            // 獲取專輯圖片索引
            albumIndex = Integer.parseInt(params[0]);
            // 獲取專輯圖片路徑
            String albumPath = params[1];
            // 聲明URL連接
            HttpURLConnection conn = null;
            // 聲明位圖對象
            Bitmap bitmap = null;
            try {
                // 定義URL對象
                URL url = new URL(MUSIC_SERVER_URL + albumPath);
                // 打開URL連接
                conn = (HttpURLConnection) url.openConnection();
                // 獲取響應碼
                int responseCode = conn.getResponseCode();
                // 根據響應碼執行不同操作
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    // 由連接獲取字節輸入流
                    InputStream in = conn.getInputStream();
                    // 利用位圖工廠生成位圖對象
                    bitmap = BitmapFactory.decodeStream(in);
                } else {
                    Log.d(TAG, "沒有得到響應數據。");
                }
                // 設置專輯圖片數組元素值
                albums[albumIndex] = bitmap;

            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
        }
    }

    /**
     * 獲取格式化時間
     *
     * @param time
     * @return
     */
    public String getFormatTime(int time) {
        return sdf.format(time);
    }

    public List<Music> getMusicList() {
        return musicList;
    }

    public Bitmap[] getAlbums() {
        return albums;
    }

    public int getCurrentMusicIndex() {
        return currentMusicIndex;
    }

    public void setCurrentMusicIndex(int currentMusicIndex) {
        this.currentMusicIndex = currentMusicIndex;
    }

    public int getCurrentPosition() {
        return currentPosition;
    }

    public void setCurrentPosition(int currentPosition) {
        this.currentPosition = currentPosition;
    }

    public int getPlayMode() {
        return playMode;
    }

    public void setPlayMode(int playMode) {
        this.playMode = playMode;
    }

    public int getProgressChangedByUser() {
        return progressChangedByUser;
    }

    public void setProgressChangedByUser(int progressChangedByUser) {
        this.progressChangedByUser = progressChangedByUser;
    }
}

(2)在項目清單文件AndroidManifest.xml文件註冊

11、創建adapter子包,在裏面創建音樂適配器MusicAdapter

(1)在layout目錄裏創建音樂列表項模板music_list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="5dp" >

    <ImageView
        android:id="@+id/iv_icon"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="10dp"
        android:src="@mipmap/music" />

    <TextView
        android:id="@+id/tv_music_name"
        android:layout_width="wrap_content"
        android:layout_height="20dp"
        android:layout_alignTop="@+id/iv_icon"
        android:layout_toRightOf="@+id/iv_icon"
        android:text="Someday The Dream Will End"
        android:textColor="#000000"
        android:textSize="16sp" />

    <TextView
        android:id="@+id/tv_duration"
        android:layout_width="wrap_content"
        android:layout_height="20dp"
        android:layout_alignBaseline="@+id/tv_music_name"
        android:layout_alignParentRight="true"
        android:text="04:34"
        android:textColor="#aaaaaa"
        android:textSize="12sp" />

    <TextView
        android:id="@+id/tv_artist"
        android:layout_width="wrap_content"
        android:layout_height="20dp"
        android:layout_alignLeft="@+id/tv_music_name"
        android:layout_below="@+id/tv_music_name"
        android:layout_marginTop="10dp"
        android:text="Nubuo Uematsu"
        android:textColor="#0000ff"
        android:textSize="15sp" />

</RelativeLayout>

(2)編寫音樂適配器MusicAdapter

package net.hw.web_music_player.adapter;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import net.hw.web_music_player.R;
import net.hw.web_music_player.app.AppConstants;
import net.hw.web_music_player.app.WebMusicPlayerApplication;
import net.hw.web_music_player.entity.Music;

import java.util.List;

/**
 * 音樂適配器
 *
 * Created by howard on 2018/1/24.
 */

public class MusicAdapter extends BaseAdapter implements AppConstants {
    /**
     * 上下文環境
     */
    private Context context;
    /**
     * 音樂列表
     */
    private List<Music> musicList;
    /**
     * 訪問網絡樂庫應用程序
     */
    private WebMusicPlayerApplication app;

    /**
     * 構造方法
     *
     * @param context
     * @param musicList
     */
    public MusicAdapter(Context context, List<Music> musicList) {
        this.context = context;
        this.musicList = musicList;
        // 獲取訪問網絡樂庫應用程序對象
        app = (WebMusicPlayerApplication) ((Activity) context).getApplication();
    }

    /**
     * 獲取列表項個數
     */
    @Override
    public int getCount() {
        return musicList.size();
    }

    /**
     * 獲取列表項對象
     */
    @Override
    public Object getItem(int position) {
        return musicList.get(position);
    }

    /**
     * 獲取列表項標識符
     */
    @Override
    public long getItemId(int position) {
        return position;
    }

    /**
     * 獲取視圖
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // 聲明視圖容器
        ViewHolder holder;

        // 判斷轉換視圖是否爲空
        if (convertView == null) {
            // 將音樂列表項模板映射成轉換視圖
            convertView = LayoutInflater.from(context).inflate(R.layout.music_list_item, null);
            // 實例化視圖容器
            holder = new ViewHolder();
            // 獲取視圖容器各控件實例
            holder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
            holder.tvMusicName = (TextView) convertView.findViewById(R.id.tv_music_name);
            holder.tvDuration = (TextView) convertView.findViewById(R.id.tv_duration);
            holder.tvArtist = (TextView) convertView.findViewById(R.id.tv_artist);
            // 將視圖容器附加到轉換視圖
            convertView.setTag(holder);
        } else {
            // 從轉換視圖裏獲取視圖容器
            holder = (ViewHolder) convertView.getTag();
        }

        // 獲取音樂實體作爲數據源
        Music music = musicList.get(position);
        // 設置音樂專輯圖片
        if (app.getAlbums()[position] != null) {
            holder.ivIcon.setImageBitmap(app.getAlbums()[position]);
        } else {
            holder.ivIcon.setImageResource(R.mipmap.music);
        }
        // 設置音樂名
        holder.tvMusicName.setText(music.getTitle());
        // 設置演唱者
        holder.tvArtist.setText(music.getArtist());
        // 設置音樂時長
        holder.tvDuration.setText(app.getFormatTime(music.getDuration()));
        // 返回轉換視圖
        return convertView;
    }

    /**
     * 視圖容器
     */
    private static class ViewHolder {
        ImageView ivIcon;
        TextView tvMusicName;
        TextView tvDuration;
        TextView tvArtist;
    }
}

12、創建service子包,在裏面創建音樂播放服務類MusicPlayService

(1)編寫音樂播放服務類MusicPlayService

package net.hw.web_music_player.service;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaPlayer;
import android.os.IBinder;

import net.hw.web_music_player.R;
import net.hw.web_music_player.app.AppConstants;
import net.hw.web_music_player.app.WebMusicPlayerApplication;
import net.hw.web_music_player.entity.Music;

import java.io.IOException;
import java.util.List;
import java.util.Random;

/**
 * 音樂服務類
 *
 * Created by howard on 2018/1/27.
 */

public class MusicPlayService extends Service implements AppConstants {
    /**
     * 媒體播放器
     */
    private MediaPlayer mp;
    /**
     * 音樂列表(數據源)
     */
    private List<Music> musicList;
    /**
     * 音樂文件名
     */
    private String musicName;
    /**
     * 更新音樂播放進度的線程
     */
    private Thread thread;
    /**
     * 線程循環控制變量
     */
    private boolean isRunning;
    /**
     * 音樂播放器應用程序
     */
    private WebMusicPlayerApplication app;
    /**
     * 音樂廣播接收器
     */
    private MusicReceiver receiver;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // 獲取獲得音樂播放器應用程序對象
        app = (WebMusicPlayerApplication) getApplication();

        // 獲取音樂列表(數據源)
        musicList = app.getMusicList();

        // 創建媒體播放器
        mp = new MediaPlayer();
        // 給媒體播放器起註冊完成監聽器
        mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                // 切換到下一首音樂
                nextMusic();
            }
        });


        // 設置線程循環控制變量爲真
        isRunning = true;
        // 創建線程更新播放進度
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (isRunning) {
                    // 判斷音樂是否在播放
                    if (mp.isPlaying()) {
                        // 設置音樂當前播放位置
                        app.setCurrentPosition(mp.getCurrentPosition());
                        // 創建意圖
                        Intent intent = new Intent();
                        // 設置廣播頻道:更新播放進度
                        intent.setAction(INTENT_ACTION_UPDATE_PROGRESS);
                        // 讓意圖攜帶播放時長
                        intent.putExtra(DURATION, mp.getDuration());
                        // 讓意圖攜帶控制圖標(暫停圖標)
                        intent.putExtra(CONTROL_ICON, R.drawable.pause_button_selector);
                        // 按意圖發送廣播
                        sendBroadcast(intent);
                    }
                    // 讓線程睡眠500毫秒
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        // 啓動線程
        thread.start();

        // 創建音樂廣播接收者
        receiver = new MusicReceiver();
        // 創建意圖過濾器
        IntentFilter filter = new IntentFilter();
        // 通過意圖過濾器添加廣播頻道
        filter.addAction(INTENT_ACTION_PLAY_OR_PAUSE);
        filter.addAction(INTENT_ACTION_PLAY);
        filter.addAction(INTENT_ACTION_PREVIOUS);
        filter.addAction(INTENT_ACTION_NEXT);
        filter.addAction(INTENT_ACTION_USER_CHANGE_PROGRESS);
        // 註冊廣播接收者
        registerReceiver(receiver, filter);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 返回非粘性服務
        return Service.START_NOT_STICKY;
    }

    /**
     * 上一首音樂
     */
    private void previousMusic() {
        // 更新音樂索引
        if (app.getCurrentMusicIndex() > 0) {
            app.setCurrentMusicIndex(app.getCurrentMusicIndex() - 1);
        } else {
            app.setCurrentMusicIndex(musicList.size() - 1);
        }
        // 當前播放位置歸零
        app.setCurrentPosition(0);
        // 調用播放方法
        play();
    }

    /**
     * 下一首音樂
     */
    private void nextMusic() {
        // 根據播放模式來更新音樂索引
        switch (app.getPlayMode()) {
            // 順序播放模式
            case PLAY_MODE_ORDER:
                if (app.getCurrentMusicIndex() < musicList.size() - 1) {
                    app.setCurrentMusicIndex(app.getCurrentMusicIndex() + 1);
                } else {
                    app.setCurrentMusicIndex(0);
                }
                break;
            // 隨機播放模式
            case PLAY_MODE_RANDOM:
                // 隨機設置索引
                app.setCurrentMusicIndex(new Random().nextInt(app.getMusicList().size()));
                break;
            // 單曲循環模式
            case PLAY_MODE_LOOP:
                // 音樂索引保持不變
                break;
        }
        // 當前播放位置歸零
        app.setCurrentPosition(0);
        // 調用播放方法
        play();
    }

    /**
     * 播放方法
     */
    private void play() {
        try {
            // 重置播放器
            mp.reset();
            // 獲取當前播放的音樂名
            musicName = musicList.get(app.getCurrentMusicIndex()).getData();
            // 設置播放源
            mp.setDataSource(MUSIC_SERVER_URL + musicName);
            // 緩衝播放源,加載到內存
            mp.prepare();
            // 定位到暫停時的播放位置
            mp.seekTo(app.getCurrentPosition());
            // 啓動音樂的播放
            mp.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 暫停方法
     */
    private void pause() {
        // 暫停播放
        mp.pause();
        // 保存當前音樂播放位置
        app.setCurrentPosition(mp.getCurrentPosition());
        /* 發送廣播給前臺MainActivity,更改圖標、更改播放進度 */
        // 創建意圖
        Intent intent = new Intent();
        // 設置廣播頻道:更新播放進度
        intent.setAction(INTENT_ACTION_UPDATE_PROGRESS);
        // 讓意圖攜帶播放時長
        intent.putExtra(DURATION, mp.getDuration());
        // 讓意圖攜帶控制圖標(播放圖標)
        intent.putExtra(CONTROL_ICON, R.drawable.play_button_selector);
        // 按意圖發送廣播
        sendBroadcast(intent);
    }

    /**
     * 音樂廣播接收者
     */
    private class MusicReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            // 獲取意圖動作(廣播頻道)
            String action = intent.getAction();
            // 當廣播頻道非空時進行判斷
            if (action != null) {
                // 根據不同廣播頻道執行不同的操作
                switch (action) {
                    case INTENT_ACTION_PLAY:
                        // 播放進度值歸零
                        app.setCurrentPosition(0);
                        // 調用播放方法
                        play();
                        break;
                    case INTENT_ACTION_PLAY_OR_PAUSE:
                        // 判斷音樂是否在播放
                        if (mp.isPlaying()) {
                            pause();
                        } else {
                            play();
                        }
                        break;
                    case INTENT_ACTION_PREVIOUS:
                        // 切換到上一首音樂
                        previousMusic();
                        break;
                    case INTENT_ACTION_NEXT:
                        // 切換到下一首音樂
                        nextMusic();
                        break;
                    case INTENT_ACTION_USER_CHANGE_PROGRESS:
                        // 根據拖拽條的進度值計算當前播放位置
                        app.setCurrentPosition(app.getProgressChangedByUser() * mp.getDuration() / 100);
                        // 根據音樂當前播放位置開始播放音樂
                        play();
                        break;
                }
            }
        }
    }

    /**
     * 銷燬回調方法
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        // 釋放媒體播放器
        if (mp != null) {
            mp.release();
            mp = null;
        }
        // 註銷廣播接收者
        unregisterReceiver(receiver);
        // 設置線程循環控制變量
        isRunning = false;
        // 銷燬子線程
        thread = null;
    }
}

(2)在項目清單文件裏註冊音樂播放服務

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.hw.web_music_player">

    <application
        android:name=".app.WebMusicPlayerApplication"
        android:allowBackup="true"
        android:icon="@mipmap/app_icon"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".ui.SplashScreenActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".service.MusicPlayService" />
    </application>

</manifest>

13、啓動界面類SplashScreenActivity

(1)啓動界面佈局文件activity_splash_screen.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@mipmap/splash_background"
    android:gravity="center"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/iv_music_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:src="@mipmap/music" />

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="@string/title"
        android:textColor="#0000ff"
        android:textSize="25sp" />

    <TextView
        android:id="@+id/tv_version"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="@string/version"
        android:textColor="#ff0000"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_author"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="@string/author"
        android:textColor="#000000"
        android:textSize="20sp" />
</LinearLayout>

(2)字符串資源文件strings.xml

<resources>
    <string name="app_name">基於網絡樂庫音樂播放器V1.0</string>
    <string name="title">基於網絡樂庫音樂播放器</string>
    <string name="version">Version 1.0</string>
    <string name="author">瀘職院信息系·華衛</string>
</resources>

(3)編寫啓動界面類SplashScreenActivity

package net.hw.web_music_player.ui;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;

import net.hw.web_music_player.R;
/**
 * 啓動界面類
 *
 * Created by howard on 2018/1/27.
 */

public class SplashScreenActivity extends Activity {
    /**
     * 動畫對象
     */
    private Animation animation;
    /**
     * 音樂圖標圖像控件
     */
    private ImageView ivMusicIcon;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 利用佈局資源文件設置用戶界面
        setContentView(R.layout.activity_splash_screen);

        // 通過資源標識獲得控件實例
        ivMusicIcon = findViewById(R.id.iv_music_icon);

        // 加載動畫資源文件,創建動畫對象
        animation = AnimationUtils.loadAnimation(this, R.anim.animator);
        // 讓音樂圖標圖像控件啓動動畫
        ivMusicIcon.startAnimation(animation);
        // 給動畫對象設置監聽器
        animation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                // 啓動主界面
                startActivity(new Intent(SplashScreenActivity.this, LoginActivity.class));
                // 關閉啓動界面
                finish();
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }
        });
    }
}

14、在ui子包裏創建登錄界面LoginActivity

(1)登錄界面佈局文件activity_login.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@mipmap/background"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="10dp" >

    <TextView
        android:id="@+id/tv_user_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="30dp"
        android:text="@string/user_login"
        android:textColor="#0000ff"
        android:textSize="25sp" />

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginBottom="20dp"
        android:layout_marginTop="10dp"
        android:background="#bbbbbb" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/tv_user_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/username"
            android:textColor="#000000"
            android:textSize="20sp" />

        <EditText
            android:id="@+id/edt_username"
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="@string/input_username"
            android:singleLine="true" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/tv_password"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/password"
            android:textColor="#000000"
            android:textSize="20sp" />

        <EditText
            android:id="@+id/edt_password"
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="@string/input_password"
            android:inputType="textPassword"
            android:singleLine="true" />
    </LinearLayout>

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginBottom="10dp"
        android:layout_marginTop="20dp"
        android:background="#bbbbbb" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dip"
        android:gravity="center_horizontal"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/btn_login"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="doLogin"
            android:paddingLeft="30dp"
            android:paddingRight="30dp"
            android:text="@string/login"
            android:textSize="20sp" />

        <Button
            android:id="@+id/btn_cancel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="doCancel"
            android:paddingLeft="30dp"
            android:paddingRight="30dp"
            android:text="@string/cancel"
            android:textSize="20sp" />
    </LinearLayout>

</LinearLayout>

(2)字符串資源文件strings.xml

<resources>
    <string name="app_name">基於網絡樂庫音樂播放器V1.0</string>
    <string name="title">基於網絡樂庫音樂播放器</string>
    <string name="version">Version 1.0</string>
    <string name="author">瀘職院信息系·華衛</string>
    <string name="user_login">用戶登錄</string>
    <string name="username">賬號:</string>
    <string name="password">密碼:</string>
    <string name="login">登錄</string>
    <string name="cancel">取消</string>
    <string name="input_username">輸入賬號</string>
    <string name="input_password">輸入密碼</string>
</resources>

(3)編寫登錄界面類LoginActivity

package net.hw.access_web_music_store.ui;

import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import net.hw.access_web_music_store.R;
import net.hw.access_web_music_store.app.AppConstants;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

public class LoginActivity extends Activity implements AppConstants {
    /**
     * 用戶名編輯框
     */
    private EditText edtUsername;
    /**
     * 密碼編輯框
     */
    private EditText edtPassword;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 利用佈局資源文件設置用戶界面
        setContentView(R.layout.activity_login);

        // 通過資源標識獲得控件實例
        edtUsername = findViewById(R.id.edt_username);
        edtPassword = findViewById(R.id.edt_password);
    }

    /**
     * 登錄按鈕單擊事件處理方法
     *
     * @param view
     */
    public void doLogin(View view) {
        // 獲取用戶名
        String username = edtUsername.getText().toString().trim();
        // 獲取密碼
        String password = edtPassword.getText().toString().trim();

        // 用戶名非空校驗
        if (username.equals("")) {
            Toast.makeText(this, "用戶名不能爲空!", Toast.LENGTH_SHORT).show();
            edtUsername.setFocusable(true);
            edtUsername.requestFocus();
            return;
        }

        // 密碼非空校驗
        if (password.equals("")) {
            Toast.makeText(this, "密碼不能爲空!", Toast.LENGTH_SHORT).show();
            edtPassword.setFocusable(true);
            edtPassword.requestFocus();
            return;
        }

        // 定義登錄網址字符串
        String strLoginUrl = MUSIC_SERVER_URL + "/login";
        // 執行登錄異步任務,傳入三個參數
        new LoginTask().execute(strLoginUrl, username, password);
    }

    /**
     * 登錄異步任務
     */
    private class LoginTask extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... params) {
            // 定義結果字符串
            String result = "";

            // 獲取登錄網址字符串
            String strLoginUrl = params[0];
            // 創建post請求
            HttpPost request = new HttpPost(strLoginUrl);
            // 創建名值對列表
            List<NameValuePair> list = new ArrayList<>();
            // 將用戶提交的數據添加到名值對列表
            list.add(new BasicNameValuePair("username", params[1]));
            list.add(new BasicNameValuePair("password", params[2]));
            try {
                // 將名值對列表封裝成url編碼格式實體作爲請求參數
                request.setEntity(new UrlEncodedFormEntity(list, "utf-8"));
                // 創建http客戶端
                HttpClient client = new DefaultHttpClient();
                // 執行post請求,獲取響應對象
                HttpResponse response = client.execute(request);
                // 如果請求成功
                if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    // 獲取響應數據實體
                    HttpEntity entity = response.getEntity();
                    // 將響應數據實體轉換成字符串保存到結果字符串裏
                    result = EntityUtils.toString(entity);
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            return result;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            // 根據響應結果執行不同操作
            if (result.trim().equals("success")) {
                // 跳轉到主界面
                startActivity(new Intent(LoginActivity.this, MainActivity.class));
                // 關閉登錄界面
                finish();
            } else {
                Toast.makeText(LoginActivity.this, "用戶名或密碼錯誤,登錄失敗!", Toast.LENGTH_SHORT).show();
            }
        }
    }

    /**
     * 取消按鈕單擊事件處理方法
     *
     * @param view
     */
    public void doCancel(View view) {
        edtUsername.setText("");
        edtPassword.setText("");
        edtUsername.requestFocus();
    }
}

15、在ui子包裏創建主界面類

 

(1)主界面佈局文件activity_main.xml

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@mipmap/background"
    android:orientation="vertical"
    android:padding="10dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@drawable/custom_border"
        android:gravity="center"
        android:orientation="horizontal"
        android:padding="5dp">

        <TextView
            android:id="@+id/tv_play_mode"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/play_mode"
            android:textSize="13sp" />

        <RadioGroup
            android:id="@+id/rg_play_mode"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <RadioButton
                android:id="@+id/rb_order"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:checked="true"
                android:text="@string/order"
                android:textSize="13sp" />

            <RadioButton
                android:id="@+id/rb_random"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/random"
                android:textSize="13sp" />

            <RadioButton
                android:id="@+id/rb_loop"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/loop"
                android:textSize="13sp" />
        </RadioGroup>
    </LinearLayout>

    <ListView
        android:id="@+id/lv_music_list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="8"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginBottom="5dp"
        android:layout_marginTop="5dp"
        android:background="#aaaaaa" />

    <TextView
        android:id="@+id/tv_music_name"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_weight="0.5"
        android:textColor="#0000ff"
        android:textSize="16sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginBottom="10dp"
        android:layout_marginTop="10dp"
        android:layout_weight="1"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tv_current_position"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textColor="#ff0000" />

        <SeekBar
            android:id="@+id/sb_music_progress"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="6" />

        <TextView
            android:id="@+id/tv_duration"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textColor="#ff00ff" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="center"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_previous"
            android:layout_width="60dp"
            android:layout_height="50dp"
            android:background="@drawable/previous_button_selector"
            android:onClick="doPrevious" />

        <Button
            android:id="@+id/btn_play_pause"
            android:layout_width="60dp"
            android:layout_height="50dp"
            android:background="@drawable/play_button_selector"
            android:onClick="doPlayOrPause" />

        <Button
            android:id="@+id/btn_next"
            android:layout_width="60dp"
            android:layout_height="50dp"
            android:background="@drawable/next_button_selector"
            android:onClick="doNext" />
    </LinearLayout>

</LinearLayout>

(2)在res下創建menu目錄,在裏面創建主界面菜單資源文件main.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/action_settings"
        android:icon="@mipmap/order_mode"
        android:orderInCategory="100"
        android:title=""
        android:showAsAction="always">
        <menu>
            <item
                android:id="@+id/action_default_order"
                android:icon="@mipmap/default_order"
                android:checked="true"
                android:showAsAction="always"
                android:title="@string/default_order"/>
            <item
                android:id="@+id/action_title_order"
                android:icon="@mipmap/title_order"
                android:showAsAction="always"
                android:title="@string/title_order"/>
            <item
                android:id="@+id/action_duration_order"
                android:icon="@mipmap/duration_order"
                android:showAsAction="always"
                android:title="@string/duration_order"/>
        </menu>
    </item>

</menu>

(3)字符串資源文件strings.xml

<resources>
    <string name="app_name">基於網絡樂庫音樂播放器V1.0</string>
    <string name="title">基於網絡樂庫音樂播放器</string>
    <string name="version">Version 1.0</string>
    <string name="author">瀘職院信息系·華衛</string>
    <string name="user_login">用戶登錄</string>
    <string name="username">賬號:</string>
    <string name="password">密碼:</string>
    <string name="login">登錄</string>
    <string name="cancel">取消</string>
    <string name="input_username">輸入賬號</string>
    <string name="input_password">輸入密碼</string>
    <string name="play_mode">播放模式:</string>
    <string name="order">順序</string>
    <string name="loop">單曲循環</string>
    <string name="random">隨機</string>    
     <string name="default_order">默認排序</string>
     <string name="title_order">按標題排序</string>
     <string name="duration_order">按時長排序</string>
</resources>

(4)編寫主界面類MainActivity

package net.hw.web_music_player.ui;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.RadioGroup;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import net.hw.web_music_player.R;
import net.hw.web_music_player.adapter.MusicAdapter;
import net.hw.web_music_player.app.AppConstants;
import net.hw.web_music_player.app.WebMusicPlayerApplication;
import net.hw.web_music_player.entity.Music;
import net.hw.web_music_player.service.MusicPlayService;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class MainActivity extends Activity implements AppConstants {
    /**
     * 音樂文件名
     */
    private String musicName;
    /**
     * 顯示音樂名的標籤
     */
    private TextView tvMusicName;
    /**
     * 播放|暫停按鈕
     */
    private Button btnPlayOrPause;
    /**
     * 顯示當前播放位置的標籤
     */
    private TextView tvCurrentPosition;
    /**
     * 顯示音樂播放時長的標籤
     */
    private TextView tvDuration;
    /**
     * 音樂播放拖拽條
     */
    private SeekBar sbMusicProgress;
    /**
     * 音樂名列表控件
     */
    private ListView lvMusicList;
    /**
     * 音樂列表(數據源)
     */
    private List<Music> musicList;
    /**
     * 音樂適配器
     */
    private MusicAdapter adapter;
    /**
     * 網絡音樂播放器應用程序對象
     */
    private WebMusicPlayerApplication app;
    /**
     * 音樂廣播接收器
     */
    private MusicReceiver receiver;
    /**
     * 播放模式單選按鈕組
     */
    private RadioGroup rgPlayMode;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 利用佈局資源文件設置用戶界面
        setContentView(R.layout.activity_main);

        // 通過資源標識獲得控件實例
        lvMusicList = findViewById(R.id.lv_music_list);
        tvMusicName = findViewById(R.id.tv_music_name);
        btnPlayOrPause = findViewById(R.id.btn_play_pause);
        tvCurrentPosition = findViewById(R.id.tv_current_position);
        tvDuration = findViewById(R.id.tv_duration);
        sbMusicProgress = findViewById(R.id.sb_music_progress);
        rgPlayMode = findViewById(R.id.rg_play_mode);

        // 創建網絡音樂播放器應用程序對象
        app = (WebMusicPlayerApplication) getApplication();

        // 獲得音樂列表作爲數據源
        musicList = app.getMusicList();
        // 判斷網絡樂庫裏是否有音樂
        if (musicList != null) {
            // 創建音樂適配器
            adapter = new MusicAdapter(this, musicList);
            // 列表控件設置適配器
            lvMusicList.setAdapter(adapter);

            // 獲取當前音樂文件名(完整路徑)
            musicName = app.getMusicList().get(app.getCurrentMusicIndex()).getData();
            // 獲取當前音樂時長
            int duration = app.getMusicList().get(app.getCurrentMusicIndex()).getDuration();

            // 設置正在播放文件名(去掉擴展名)
            tvMusicName.setText("No." + (app.getCurrentMusicIndex() + 1) + "  "
                    + musicName.substring(musicName.lastIndexOf("/") + 1,
                    musicName.lastIndexOf(".")));
            // 設置播放當前位置
            tvCurrentPosition.setText(app.getFormatTime(0));
            // 設置音樂時長
            tvDuration.setText(app.getFormatTime(duration));

            // 啓動音樂播放服務
            startService(new Intent(MainActivity.this, MusicPlayService.class));

            // 給音樂列表控件註冊監聽器
            lvMusicList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    // 獲取音樂索引
                    app.setCurrentMusicIndex(position);
                    // 播放進度歸零
                    app.setCurrentPosition(0);
                    // 獲取音樂名
                    musicName = app.getMusicList().get(position).getData();
                    // 設置音樂名標籤內容,去掉路徑和擴展名
                    tvMusicName.setText("No. " + (app.getCurrentMusicIndex() + 1) + " " + musicName.substring(
                            musicName.lastIndexOf('/') + 1, musicName.lastIndexOf(".")));
                    // 創建意圖
                    Intent intent = new Intent();
                    // 設置廣播頻道:播放
                    intent.setAction(INTENT_ACTION_PLAY);
                    // 按意圖發送廣播
                    sendBroadcast(intent);
                }
            });

            // 給播放模式單選按鈕組註冊監聽器
            rgPlayMode.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
                    // 判斷用戶選擇何種播放模式
                    switch (checkedId) {
                        // 順序播放模式
                        case R.id.rb_order:
                            app.setPlayMode(PLAY_MODE_ORDER);
                            break;
                        // 隨機播放模式
                        case R.id.rb_random:
                            app.setPlayMode(PLAY_MODE_RANDOM);
                            break;
                        // 單曲循環模式
                        case R.id.rb_loop:
                            app.setPlayMode(PLAY_MODE_LOOP);
                            break;
                    }
                }
            });

            // 給音樂播放拖拽條註冊監聽器
            sbMusicProgress.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                    // 判斷進度是否爲用戶修改
                    if (fromUser) {
                        // 設置用戶修改的播放進度
                        app.setProgressChangedByUser(progress);
                        // 創建意圖
                        Intent intent = new Intent();
                        // 設置廣播頻道:用戶修改播放進度
                        intent.setAction(INTENT_ACTION_USER_CHANGE_PROGRESS);
                        // 按意圖發送廣播
                        sendBroadcast(intent);
                    }
                }

                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
                }

                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                }
            });

            // 創建音樂廣播接收器
            receiver = new MusicReceiver();
            // 創建意圖過濾器
            IntentFilter filter = new IntentFilter();
            // 通過意圖過濾器添加廣播頻道
            filter.addAction(INTENT_ACTION_UPDATE_PROGRESS);
            // 註冊音樂廣播接收器
            registerReceiver(receiver, filter);
        } else {
            Toast.makeText(this, "網絡樂庫裏沒有音樂文件!", Toast.LENGTH_LONG).show();
        }
    }

    /**
     * 創建選項菜單
     *
     * @param menu
     * @return
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            // 默認排序
            case R.id.action_default_order:
                Collections.sort(app.getMusicList(), new Comparator<Music>() {

                    @Override
                    // lhs: left-hand-side; rhs: right-hand-side
                    public int compare(Music lhs, Music rhs) {
                        return (int) (lhs.getId() - rhs.getId());
                    }
                });

                saveDefaultOrderBy("default");
                break;
            // 按標題排序
            case R.id.action_title_order:
                Collections.sort(app.getMusicList(), new Comparator<Music>() {

                    @Override
                    // lhs: left-hand-side; rhs: right-hand-side
                    public int compare(Music lhs, Music rhs) {
                        return lhs.getTitle().compareTo(rhs.getTitle());
                    }
                });

                saveDefaultOrderBy("title");
                break;
            // 按時長排序
            case R.id.action_duration_order:
                Collections.sort(app.getMusicList(), new Comparator<Music>() {

                    @Override
                    // lhs: left-hand-side; rhs: right-hand-side
                    public int compare(Music lhs, Music rhs) {
                        return (int) (lhs.getDuration() - rhs.getDuration());
                    }
                });
                saveDefaultOrderBy("duration");
                break;
        }

        // 更新列表控件
        adapter.notifyDataSetInvalidated();

        return true;
    }

    /**
     * 保存個性化設置(偏好設置):默認的列表排序方法
     *
     * @param orderBy
     *            列表排序方法
     */
    private void saveDefaultOrderBy(String orderBy) {
        // 獲得共享參數對象
        SharedPreferences sp = getSharedPreferences(USER_CONFIG, MODE_PRIVATE);
        // 獲得共享參數的編輯器
        SharedPreferences.Editor editor = sp.edit();
        // 存放數據
        editor.putString("order-by", orderBy);
        // 提交數據
        editor.commit();
    }


    /**
     * 上一首音樂按鈕單擊事件處理方法
     *
     * @param view
     */
    public void doPrevious(View view) {
        // 創建意圖
        Intent intent = new Intent();
        // 設置廣播頻道
        intent.setAction(INTENT_ACTION_PREVIOUS);
        // 按意圖發送廣播
        sendBroadcast(intent);
    }

    /**
     * 下一首音樂按鈕單擊事件處理方法
     *
     * @param view
     */
    public void doNext(View view) {
        // 創建意圖
        Intent intent = new Intent();
        // 設置廣播頻道
        intent.setAction(INTENT_ACTION_NEXT);
        // 按意圖發送廣播
        sendBroadcast(intent);
    }

    /**
     * 播放|暫停按鈕單擊事件處理方法
     *
     * @param view
     */
    public void doPlayOrPause(View view) {
        // 創建意圖
        Intent intent = new Intent();
        // 設置廣播頻道
        intent.setAction(INTENT_ACTION_PLAY_OR_PAUSE);
        // 按意圖發送廣播
        sendBroadcast(intent);
    }

    /**
     * 音樂廣播接收者
     */
    private class MusicReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            // 獲取廣播頻道
            String action = intent.getAction();
            // 判斷廣播頻道是否爲空
            if (action != null) {
                // 根據不同廣播頻道執行不同操作
                if (INTENT_ACTION_UPDATE_PROGRESS.equals(action)) {
                    // 獲取播放時長
                    int duration = intent.getIntExtra(DURATION, 0);
                    // 獲取播放控制圖標
                    int controlIcon = intent.getIntExtra(CONTROL_ICON,
                            R.drawable.play_button_selector);
                    // 計算進度值
                    int progress = app.getCurrentPosition() * 100 / duration;
                    // 獲取音樂名
                    musicName = app.getMusicList().get(app.getCurrentMusicIndex()).getData();
                    // 設置正在播放的文件名(去掉擴展名)
                    tvMusicName.setText("No." + (app.getCurrentMusicIndex() + 1) + "  "
                            + musicName.substring(musicName.lastIndexOf("/") + 1, musicName.lastIndexOf(".")));
                    // 設置播放進度值標籤
                    tvCurrentPosition.setText(app.getFormatTime(app.getCurrentPosition()));
                    // 設置播放時長標籤
                    tvDuration.setText(app.getFormatTime(duration));
                    // 設置播放拖拽條的進度值
                    sbMusicProgress.setProgress(progress);
                    // 設置【播放|暫停】按鈕顯示的圖標
                    btnPlayOrPause.setBackgroundResource(controlIcon);
                }
            }
        }
    }

    /**
     * 銷燬方法
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 停止音樂播放服務
        stopService(new Intent(MainActivity.this, MusicPlayService.class));
        // 註銷廣播接收者
        unregisterReceiver(receiver);
    }
}

16、在項目清單文件裏授權訪問因特網

五、運行項目

 

1、啓動服務器端MusicServer

2、啓動安卓客戶端WebMusicPlayerV1.0


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章