1. 程式人生 > >基於android的網路音樂播放器-本地音樂的載入和後臺播放(一)

基於android的網路音樂播放器-本地音樂的載入和後臺播放(一)

作為android初學者,最近把瘋狂android講義和瘋狂Java講義看了一遍,看到書中介紹的知識點非常多,很難全部記住,為了更好的掌握基礎知識點,我將開發一個網路音樂播放器-EasyMusic來鞏固下,也當作是練練手。感興趣的朋友可以看看,有設計不足的地方也歡迎指出。

開發之前首先介紹下該音樂播放器將要開發的功能(需求):

1.本地音樂的載入和播放;

2.網路音樂的搜尋,試聽和下載;

3.音樂的斷點下載;

4.點選播放圖示載入專輯圖片,點選歌詞載入歌詞並滾動顯示(支援滑動歌詞改變音樂播放進度);

5.支援基於popupWindow的彈出式選單;

6.支援後臺工作列顯示和控制。

該篇主要實現本地音樂的載入和播放,主要程式碼如下:
1. MainActivity.java

package com.sprd.easymusic;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.sprd.easymusic.service.PlayMusicService;

import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import
android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.database.Cursor; import android.os.Bundle; import android.os.IBinder; import android.provider.MediaStore; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import
android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity { private String TAG = "MainActivity"; //dbMusic儲存媒體庫中的所有音樂 private List<Map<String,Object>> dbMusic = new ArrayList<>(); private ListView musicListView; private LayoutInflater inflater; private Context mContext; PlayMusicService playService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; musicListView = (ListView)findViewById(R.id.musicList); getMusicFromDb(); bindToService(); inflater = LayoutInflater.from(mContext); //音樂列表musicListView的adapter定義 SimpleAdapter adapter = new SimpleAdapter(this, dbMusic, R.layout.musiclist_item, new String[] {"title", "artist"}, new int[] {R.id.musicTitle, R.id.musicArtist}); musicListView.setAdapter(musicListAdapter); musicListView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { playMusic(position); Toast.makeText(mContext, "click on position " + position, Toast.LENGTH_LONG).show(); } }); } //繫結服務時的ServiceConnection引數 private ServiceConnection conn = new ServiceConnection() { //繫結成功後該方法回撥,並獲得服務端IBinder的引用 public void onServiceConnected(ComponentName name, IBinder service) { //通過獲得的IBinder獲取PlayMusicService的引用 playService = ((PlayMusicService.MusicBinder)service).getService(); Toast.makeText(mContext, "onServiceConnected", Toast.LENGTH_LONG).show(); } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "onServiceDisconnected"); } }; //繫結服務PlayMusicService private void bindToService() { bindService(new Intent(mContext, com.sprd.easymusic.service.PlayMusicService.class), conn, Service.BIND_AUTO_CREATE); } //通過獲得的PlayMusicService引用呼叫播放音樂的方法,方法傳進去的引數為音樂url protected void playMusic(int position) { if (playService != null) { playService.play((String)dbMusic.get(position).get("url")); } } //從媒體庫中查詢音樂 private void getMusicFromDb() { if (dbMusic.size() > 0) dbMusic.clear(); Cursor musicCursor1 = this.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER); //從外部儲存獲取 getMusic(musicCursor1); Cursor musicCursor2 = this.getContentResolver().query(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER); //從內部儲存獲取 getMusic(musicCursor2); } //獲取到的音樂以Map的形式儲存在dbMusic中 private void getMusic(Cursor musicCursor) { while (musicCursor.moveToNext()) { Map<String, Object> item = new HashMap<String, Object>(); long id = musicCursor.getLong(musicCursor.getColumnIndex(MediaStore.Audio.Media._ID)); String title = musicCursor.getString(musicCursor.getColumnIndex(MediaStore.Audio.Media.TITLE)); String artist = musicCursor.getString(musicCursor.getColumnIndex(MediaStore.Audio.Media.ARTIST)); if (artist != null && artist.equals("<unknown>")) { continue; } long duration = musicCursor.getLong(musicCursor.getColumnIndex(MediaStore.Audio.Media.DURATION)); long size = musicCursor.getLong(musicCursor.getColumnIndex(MediaStore.Audio.Media.SIZE)); String url = musicCursor.getString(musicCursor.getColumnIndex(MediaStore.Audio.Media.DATA)); int isMusic = musicCursor.getInt(musicCursor.getColumnIndex(MediaStore.Audio.Media.IS_MUSIC)); if (isMusic != 0) { item.put("id", id); item.put("title", title); item.put("artist", artist); item.put("duration", formatDuration(duration)); item.put("size", size); item.put("url", url); Log.d("MainActivity", "MusicTitle = " + title); Log.d("MainActivity", "MusicArtist = " + artist); Log.d("MainActivity", "MusicUrl = " + url); dbMusic.add(item); } } } //將音樂時長轉換為00:00格式 private String formatDuration(long dur) { long totalSecond = dur / 1000; String minute = totalSecond / 60 + ""; if (minute.length() < 2) minute = "0" + minute ; String second = totalSecond % 60 + ""; if (second.length() < 2) second = "0" + second; return minute + ":" + second; } private BaseAdapter musicListAdapter = new BaseAdapter() { @Override public int getCount() { return dbMusic.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; Map<String, Object> item = dbMusic.get(position); if (convertView == null) { view = inflater.inflate(R.layout.musiclist_item, null); } TextView musicTitle = (TextView)view.findViewById(R.id.musicTitle); TextView musicArtist = (TextView)view.findViewById(R.id.musicArtist); musicTitle.setText((String)item.get("title")); musicTitle.setText((String)item.get("artist")); return view; } }; @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }

佈局檔案就一個ListView就不貼出來了,這裡貼一下musicListAdapter的item佈局:
musiclist_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/RelativeLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_vertical"
    android:orientation="horizontal"
    android:padding="5dp" >

    <ImageView
        android:id="@+id/musicTag"
        android:layout_width="50dp"
        android:layout_height="40dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_centerVertical="true"
        android:src="@drawable/music" />

    <TextView
        android:id="@+id/musicTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@id/musicTag"
        android:text="TextView" />

    <TextView
        android:id="@+id/musicArtist"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/musicTag"
        android:layout_below="@+id/musicTitle"
        android:text="TextView" />

    <ImageView
        android:id="@+id/love"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/musicTag"
        android:layout_alignParentRight="true"
        android:src="@android:drawable/btn_star_big_off" />

</RelativeLayout>

2 PlayMusicService.java 這是後臺播放音樂的服務

package com.sprd.easymusic.service;

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class PlayMusicService extends Service {
    private final String TAG = "PlayMusicService";
    private MediaPlayer mPlayer = new MediaPlayer();
    //後臺播放音樂的執行緒
    private PlayThread myPlayThread = new PlayThread(); 

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
    }
    /*
     * MainActivity呼叫bindService後該方法回撥,緊接著MainActivity的ServiceConnection的
     * onServiceConnected方法回撥,onBind回撥的返回值傳遞給onServiceConnected中的引數service
     * 從而MainActivity就可以通過Binder的getService方法獲得PlayMusicService的引用,後續的音樂播放
     * 控制就簡單了
     */
    public IBinder onBind(Intent intent) {
        Toast.makeText(this, "onBind", Toast.LENGTH_LONG).show();
        return new MusicBinder();
    }

    public class MusicBinder extends Binder {

        public PlayMusicService getService() {
            return PlayMusicService.this;
        }
    }

    public void play(String url) {
        myPlayThread.setUrl(url);
        myPlayThread.start();
    }

    //後臺播放音樂的執行緒定義
    private class PlayThread extends Thread {
        //歌曲的url
        private String url = null;

        public PlayThread() {
        }

        public PlayThread(String url) {
            this.url = url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public void run() {
            if (mPlayer.isPlaying()) {
                mPlayer.stop();
            }
            try {
                mPlayer.reset();
                Log.d("MusicService", "play reset ");
                mPlayer.setDataSource(url);
                Log.d("MusicService", "play setDataSource ");
                mPlayer.prepare();
                Log.d("MusicService", "play prepare ");
                mPlayer.start();
                Log.d("MusicService", "play start ");
                mPlayer.setOnCompletionListener(new OnCompletionListener() {

                    @Override
                    public void onCompletion(MediaPlayer player) {

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

        }
    }

}

然後不要忘了在manifest檔案裡面註冊service和新增許可權(媒體庫查詢外部儲存的音樂)

<service android:name="com.sprd.easymusic.service.PlayMusicService"></service>

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

該文章只介紹這些內容,後續會更新進度;程式碼有問題或錯誤的地方歡迎指出和給出修改意見。

相關推薦

基於android網路音樂播放-本地音樂載入後臺播放

作為android初學者,最近把瘋狂android講義和瘋狂Java講義看了一遍,看到書中介紹的知識點非常多,很難全部記住,為了更好的掌握基礎知識點,我將開發一個網路音樂播放器-EasyMusic來鞏固下,也當作是練練手。感興趣的朋友可以看看,有設計不足的地方也

Android 音視頻深入 十三 OpenSL ES 制作音樂播放,能暫停調整音量附源碼下載

音視頻 OpenSL ES 項目地址https://github.com/979451341/OpenSLAudio OpenSL ES 是基於NDK也就是c語言的底層開發音頻的公開API,通過使用它能夠做到標準化, 高性能,低響應時間的音頻功能實現方法。 這次是使用OpenSL ES來做一個音樂播

Squid代理服務的了解與基本配置

使用 poll() 處理 nologin fec 隱藏 了解 情況下 chown 前言Squid(Squid cache,簡稱Squid)是Linux系統中最常用的一款開源代理服務軟件,可以很好地實現HTTP和FTP,以及DNS查詢、SSL等應用的緩存代理,功能十分強大。搭

專案實戰——基於計算機視覺的物體位姿定位及機械臂矯正

專案實戰——基於計算機視覺的物體位姿定位及機械臂矯正(一) 思路 經過這幾天的資料查詢,我逐步有了思路,現整理如下: 抓取物品定為牛奶盒,主要優勢在於,質量輕、體積小、稜角分明,便於識別抓取; 工作環境設定在傳送帶上,人工隨機將牛奶盒以不同方向隨機放入; 在攝

開發實戰:基於深度學習+maven+SSM+EasyUI的高校共享汽車管理系統

基於深度學習+maven+SSM+EasyUI的高校共享汽車管理系統 1.專案簡介   在現在,共享汽車在中國各地方開始熱起來,於是本人想做一個基於maven+SSM+EasyUI的高校共享汽車管理系統,當然該專案是博主本人2019年的畢業設計,除了javaweb部分,本專案還

讀《基於文件主題結構的關鍵詞抽取方法研究》有感

沒錯,這是一篇讀後感。今天拜讀了劉知遠老師的博士畢業論文。 一、研究內容: 1、基於文件內部資訊,利用文件的詞聚類演算法構建文件主題,進行關鍵詞抽取。 2、基於文件外部資訊,利用隱含主題模型構建文件主題,進行關鍵詞抽取。 3、綜合利用隱含主題模型和文件結構資訊,進行關鍵詞抽取。 4、

Android程序守護,讓APP在系統記憶體中常駐

       其實我們開發者並不想讓自己做的應用變成流氓軟體,但是沒辦法, 你的老闆需要,你要不想讓你的應用常駐,那咱就常駐不了了。。。所以說,言歸正傳。。。       第一篇準備使用系統的服務保活。如果想看提高app的程序等級來實現應用保活,可以直接進行點選Androi

Android應用中使用百度地圖API並新增標註

網上一些資料這種的內容已經過時了,這裡是最新的內容,如果哪裡不對,請吐槽。。。 1)下載百度地圖移動版API(Android)開發包       要在Android應用中使用百度地圖API,就需要在工程中引用百度地圖API開發包,這個開發包包含兩個檔案: 2)申請A

基於bootstrap table分頁資料及行內編輯匯出資料

第一步,匯入相應的css和js檔案      <link href="~/Content/bootstrap.min.css" rel="stylesheet" />     <!-----swich按鈕需要的css檔案-->     <

HTML 播放視訊的embed標籤Object標籤

原文地址:https://blog.csdn.net/qq_19865749/article/details/65631472 一、object元素 標籤用於包含物件,比如影象、音訊、視訊、Java applets、ActiveX、PDF 以及 Flash。 1、object標籤屬

神經網路深度學習——初識神經網路

神經網路和深度學習 神經網路:一種可以通過觀測資料使計算機學習的仿生語言範例 深度學習:一組強大的神經網路學習技術 神經網路和深度學習目前提供了針對影象識別,語音識別和自然語言處理領域諸多問題的最佳解決方案。傳統的程式設計方法中,我們告訴計算機如何去做,將

Android OTA升級原理流程分析

這篇及以後的篇幅將通過分析update.zip包在具體Android系統升級的過程,來理解Android系統中Recovery模式服務的工作原理。我們先從update.zip包的製作開始,然後是Android系統的啟動模式分析,Recovery工作原理,如何從

Android 巧用Itent.ACTION_PICKIntent.ACTION_GET_CONTENT

       你是不是很多時候,想從彈出的電話本姓名列表中中查詢到某個人,然後再獲取該人的詳細資訊呢?       你是不是想選擇從彈出的列表中選擇一張圖片,然後將其進行進一步的操作呢?       如果,你想,那你是不是很像知道,我們應該怎麼讓其彈出來一張選擇列表,又應該

Android上傳檔案到Web伺服器,PHP接收檔案

      Android上傳檔案到伺服器,通常採用構造http協議的方法,模擬網頁POST方法傳輸檔案,伺服器端可以採用JavaServlet或者PHP來接收要傳輸的檔案。使用JavaServlet來接收檔案的方法比較常見,在這裡給大家介紹一個簡單的伺服器端使用PHP語言

【cocos2dx網路遊戲】搭建CS架構的基本通訊框架server

#include <iostream> using namespace std; #include "comm.h" void proc_data(socket_type sock) { //輸出客戶端的地址的字串 cout<<"client connected :"<&

Android P版本 新功能介紹相容性處理

Android P版本已經到來,首篇我們當然要先看下Android P版本的搭建和模擬器的使用 1: Android studio的版本請選用 Android Studio 3.1 或者 Android Studio 3.2 Canary; Androi

Android在標準linux基礎上對休眠喚醒的實現【轉】

說明: 1. Based on linux 2.6.32 and android 2.2,only support SDR(mem). 2. 參考文章: 一、新增特性介紹 實際上,android仍然是利用了標準linux的休眠喚醒系統,只不過添加了一些使用

Android開發之最新Recyclerview控制元件的使用詳解

    本篇博文主要給大家分享關於RecyclerView控制元件的使用及通過繼承RecyclerView來實現滑動時載入圖片的優化方案,也同樣能解決防止圖片亂序的問題,之前有在網上有看到大神對Android中ListView非同步載入圖片亂序問題進行過分析,並深入剖析原理

網路遊戲《叢林戰爭》開發與學習之網路程式設計的基礎知識

《叢林戰爭》是一款完整的網路遊戲案例,運用U3D開發客戶端,Socket開發服務端,其中涉及到了網路程式設計、資料庫和Unity的功能實現,之前通過U3D開發了一個單機遊戲《黑暗之光》,並沒有涉及網路程式設計的知識,通過《叢林戰爭》這個完整的遊戲,系統性地學習網路程式設計,並

淺析函式裝飾閉包

函式裝飾器用於在原始碼中”標記”函式,以某種方式增強函式的行為。這是一項強大的功能,但是若想掌握,必須理解閉包。 裝飾器基礎知識 裝飾器是可呼叫的物件,其引數是另一個函式(被裝飾的函式)。裝飾器可能會處理被裝飾的函式,然後把它返回,或者將其替換成另一個函