基於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_PICK和Intent.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開發了一個單機遊戲《黑暗之光》,並沒有涉及網路程式設計的知識,通過《叢林戰爭》這個完整的遊戲,系統性地學習網路程式設計,並
淺析函式裝飾器和閉包(一)
函式裝飾器用於在原始碼中”標記”函式,以某種方式增強函式的行為。這是一項強大的功能,但是若想掌握,必須理解閉包。 裝飾器基礎知識 裝飾器是可呼叫的物件,其引數是另一個函式(被裝飾的函式)。裝飾器可能會處理被裝飾的函式,然後把它返回,或者將其替換成另一個函