Android?Studio實(shí)現(xiàn)音樂播放器的全過程(簡(jiǎn)單易上手)
前言
我們大家平時(shí)長(zhǎng)時(shí)間打代碼的時(shí)候肯定會(huì)感到疲憊和乏味,這個(gè)時(shí)候一邊播放自己喜歡的音樂,一邊繼續(xù)打代碼,心情自然也愉快很多。音樂帶給人的聽覺享受是無可比擬的,動(dòng)聽的音樂可以愉悅?cè)说纳硇?,讓人更加積極地去熱愛生活。大家平常應(yīng)該會(huì)用QQ音樂、網(wǎng)易云音樂或者酷狗音樂等音樂APP來聽歌,想不想擁有屬于自己的音樂播放器。那么接下來就教大家如何用Android Studio自己制作一個(gè)音樂播放器APP。
一、項(xiàng)目概述
1、需求分析
綜合運(yùn)用UI界面設(shè)計(jì)、數(shù)據(jù)存儲(chǔ)、Activity(活動(dòng))、Service(服務(wù))、MusicPlayer、ListView等知識(shí),設(shè)計(jì)開發(fā)一款具有音樂列表的音樂播放器。

2、設(shè)計(jì)分析
整個(gè)項(xiàng)目包含五個(gè)類和五個(gè)布局文件:
其中frag1、frag2為java文件,
MusicActivity為Activity文件,
MusicService為Service文件,
MainActivity為項(xiàng)目創(chuàng)建時(shí)自動(dòng)生成的Activity文件。

activity_main為MainActivity的布局文件,顯示運(yùn)行APP時(shí)的主界面。
activity_music為MusicActivity的布局文件,顯示音樂播放器界面。
music_list和item_layout一起組成frag1的布局文件,
就是音樂列表界面(打開APP默認(rèn)顯示音樂列表界面)。
frag2_layout就是frag2的布局文件,主要顯示的是專輯封面圖片。

3、資源文件分析
在res文件夾下創(chuàng)建了raw文件夾,放了三首音樂文件,在drawable文件夾中粘貼了音樂封面圖片bg.jpg和播放器背景圖片music_bg.jpg,還有背景選擇器的btn_bg_selector.xml文件,如圖所示:

二、開發(fā)環(huán)境

三、準(zhǔn)備工具
1、選擇幾首自己下載好的音樂文件,命名為music0、music1、music2等,這里歌曲都要是mp3類型的,數(shù)量隨意。歌曲名的下標(biāo)是從0開始的,因?yàn)榇a中我設(shè)置的url地址是從0開始的,否則會(huì)閃退。
2、選擇每首歌對(duì)應(yīng)的歌手圖片,剪成圓形并且保存好,命名為music0、music1、music2等。
圖片一定要剪成圓形,橢圓會(huì)影響運(yùn)行效果,導(dǎo)致閃退,如果不太清楚圖片如何剪成圓形,可以拉到文末學(xué)習(xí)。
3、準(zhǔn)備一張音樂播放器的背景圖片,命名為music_bg,再找一張圖片用作專輯圖片,命名為bg。
四、詳細(xì)設(shè)計(jì)
1、搭建主界面布局
首先打開Android Studio,并新建一個(gè)工程,F(xiàn)ile——>New——>New Project——>Empty Project,工程名稱叫做Music_List。
包名自己隨意設(shè)定,這里博主用的是zj.dzh;工程文件的保存路徑要修改一下,不要放在C盤,博主這里選擇的是放在E盤的一個(gè)Projects文件夾中,養(yǎng)成項(xiàng)目統(tǒng)一放在英文路徑下的好習(xí)慣。
最后選擇API 18:Android 4.3,因?yàn)檫@樣它就擁有了99.5%的跨平臺(tái)性(兼容性非常好),因?yàn)樗姹竞艿停旧夏M器API版本都是高于20的,所以這個(gè)軟件可以運(yùn)行其他各種設(shè)備上。點(diǎn)擊Finish完成創(chuàng)建。

設(shè)計(jì)一個(gè)app的時(shí)候,一定要先設(shè)計(jì)layout文件,再設(shè)計(jì)java文件,因?yàn)椴季钟辛?,才能在上面進(jìn)行代碼的編寫。我們來看一下activity_main布局文件,它主要顯示主界面。什么是主界面,就是一個(gè)APP運(yùn)行后默認(rèn)顯示的界面。
最外層用的是LinearLayout線性布局,然后設(shè)置的是垂直排列。里面放了兩個(gè)小的LinearLayout,分別是最上面的一個(gè)TextView,內(nèi)容設(shè)置的是“我喜歡”,接著第二個(gè)小的LinearLayout放兩個(gè)水平的TextView控件,內(nèi)容顯示的是“歌曲”和“專輯”。
最下面的剩余空間全部給了Fragment,它的id是content,這里不知道Fragment沒關(guān)系,反正就曉得它和TextView一樣可以顯示內(nèi)容就行。效果如圖:
Fragment是一種可以嵌入在活動(dòng)中的UI片段,能夠讓程序更加合理和充分地利用大屏幕的空間,出現(xiàn)的初衷是為了適應(yīng)大屏幕的平板電腦,可以將其看成一個(gè)小型Activity,又稱作Activity片段。

完整代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="我喜歡"
android:textSize="35dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/menu1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="歌曲"
android:textSize="25dp"/>
<TextView
android:id="@+id/menu2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="專輯"
android:textSize="25dp"/>
</LinearLayout>
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="9">
</FrameLayout>
</LinearLayout>
然后回到我們的Activity文件。MainActivity類是整個(gè)工程的主類,首先創(chuàng)建需要用到的控件,然后綁定控件,再設(shè)置監(jiān)聽器,底部導(dǎo)航欄設(shè)置的是兩個(gè)菜單文件:frag1(歌曲菜單)和frag2(專輯菜單),默認(rèn)情況下展示frag1歌曲菜單,點(diǎn)擊切換顯示frag2專輯菜單。代碼如下:
package zj.dzh.music_list;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
//創(chuàng)建需要用到的控件的變量
private TextView tv1,tv2;
private FragmentManager fm;
private FragmentTransaction ft;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//綁定控件
tv1=(TextView)findViewById(R.id.menu1);
tv2=(TextView)findViewById(R.id.menu2);
//設(shè)置監(jiān)聽器,固定寫法
tv1.setOnClickListener(this);
tv2.setOnClickListener(this);
//若是繼承FragmentActivity,fm=getFragmentManger();
fm=getSupportFragmentManager();
//fm可以理解為Fragment顯示的管理者,ft就是它的改變者
ft=fm.beginTransaction();
//默認(rèn)情況下就顯示frag1
ft.replace(R.id.content,new frag1());
//提交改變的內(nèi)容
ft.commit();
}
@Override
//控件的點(diǎn)擊事件
public void onClick(View v){
ft=fm.beginTransaction();
//切換選項(xiàng)卡
switch (v.getId()){
case R.id.menu1:
ft.replace(R.id.content,new frag1());
break;
case R.id.menu2:
ft.replace(R.id.content,new frag2());
break;
default:
break;
}
ft.commit();
}
}
2、創(chuàng)建服務(wù)類
2.1、服務(wù)概述

2.2、服務(wù)的創(chuàng)建

創(chuàng)建MusicService文件,右擊包名——>New——>Service——>Service,如圖:

命名為MusicService,然后Finish。

2.3、服務(wù)的啟動(dòng)方式

2.4、服務(wù)的生命周期

MusicService代碼:
package zj.dzh.music_list;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import java.util.Timer;
import java.util.TimerTask;
//這是一個(gè)Service服務(wù)類
public class MusicService extends Service {
//聲明一個(gè)MediaPlayer引用
private MediaPlayer player;
//聲明一個(gè)計(jì)時(shí)器引用
private Timer timer;
//構(gòu)造函數(shù)
public MusicService() {}
@Override
public IBinder onBind(Intent intent){
return new MusicControl();
}
@Override
public void onCreate(){
super.onCreate();
//創(chuàng)建音樂播放器對(duì)象
player=new MediaPlayer();
}
//添加計(jì)時(shí)器用于設(shè)置音樂播放器中的播放進(jìn)度條
public void addTimer(){
//如果timer不存在,也就是沒有引用實(shí)例
if(timer==null){
//創(chuàng)建計(jì)時(shí)器對(duì)象
timer=new Timer();
TimerTask task=new TimerTask() {
@Override
public void run() {
if (player==null) return;
int duration=player.getDuration();//獲取歌曲總時(shí)長(zhǎng)
int currentPosition=player.getCurrentPosition();//獲取播放進(jìn)度
Message msg= MusicActivity.handler.obtainMessage();//創(chuàng)建消息對(duì)象
//將音樂的總時(shí)長(zhǎng)和播放進(jìn)度封裝至bundle中
Bundle bundle=new Bundle();
bundle.putInt("duration",duration);
bundle.putInt("currentPosition",currentPosition);
//再將bundle封裝到msg消息對(duì)象中
msg.setData(bundle);
//最后將消息發(fā)送到主線程的消息隊(duì)列
MusicActivity.handler.sendMessage(msg);
}
};
//開始計(jì)時(shí)任務(wù)后的5毫秒,第一次執(zhí)行task任務(wù),以后每500毫秒(0.5s)執(zhí)行一次
timer.schedule(task,5,500);
}
}
//Binder是一種跨進(jìn)程的通信方式
class MusicControl extends Binder{
public void play(int i){//String path
Uri uri=Uri.parse("android.resource://"+getPackageName()+"/raw/"+"music"+i);
try{
//重置音樂播放器
player.reset();
//加載多媒體文件
player=MediaPlayer.create(getApplicationContext(),uri);
player.start();//播放音樂
addTimer();//添加計(jì)時(shí)器
}catch(Exception e){
e.printStackTrace();
}
}
//下面的暫停繼續(xù)和退出方法全部調(diào)用的是MediaPlayer自帶的方法
public void pausePlay(){
player.pause();//暫停播放音樂
}
public void continuePlay(){
player.start();//繼續(xù)播放音樂
}
public void seekTo(int progress){
player.seekTo(progress);//設(shè)置音樂的播放位置
}
}
//銷毀多媒體播放器
@Override
public void onDestroy(){
super.onDestroy();
if(player==null) return;
if(player.isPlaying()) player.stop();//停止播放音樂
player.release();//釋放占用的資源
player=null;//將player置為空
}
}
3、搭建音樂播放界面布局

右擊包名,新建一個(gè)Activity,命名為MusicActivity,點(diǎn)擊Finish,它會(huì)生成一個(gè)activity_music文件,用來顯示音樂播放界面,如圖所示:


(1)MusicActivity類:通過onClick方法控制著音樂的播放、暫停、繼續(xù)播放和退出功能。它和MusicService進(jìn)行綁定連接。在音樂播放時(shí)顯示歌曲總時(shí)長(zhǎng),還有歌曲當(dāng)前播放時(shí)長(zhǎng),控制歌曲進(jìn)度條的移動(dòng)。代碼如下:
package zj.dzh.music_list;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.animation.ObjectAnimator;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import static java.lang.Integer.parseInt;
public class MusicActivity extends AppCompatActivity implements View.OnClickListener{
//進(jìn)度條
private static SeekBar sb;
private static TextView tv_progress,tv_total,name_song;
//動(dòng)畫
private ObjectAnimator animator;
private MusicService.MusicControl musicControl;
private String name;
private Intent intent1,intent2;
private MyServiceConn conn;
//記錄服務(wù)是否被解綁,默認(rèn)沒有
private boolean isUnbind =false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music);
//獲取從frag1傳來的信息
intent1=getIntent();
init();
}
private void init(){
//進(jìn)度條上小綠點(diǎn)的位置,也就是當(dāng)前已播放時(shí)間
tv_progress=(TextView)findViewById(R.id.tv_progress);
//進(jìn)度條的總長(zhǎng)度,就是總時(shí)間
tv_total=(TextView)findViewById(R.id.tv_total);
//進(jìn)度條的控件
sb=(SeekBar)findViewById(R.id.sb);
//歌曲名顯示的控件
name_song=(TextView)findViewById(R.id.song_name);
//綁定控件的同時(shí)設(shè)置點(diǎn)擊事件監(jiān)聽器
findViewById(R.id.btn_play).setOnClickListener(this);
findViewById(R.id.btn_pause).setOnClickListener(this);
findViewById(R.id.btn_continue_play).setOnClickListener(this);
findViewById(R.id.btn_exit).setOnClickListener(this);
name=intent1.getStringExtra("name");
name_song.setText(name);
//創(chuàng)建一個(gè)意圖對(duì)象,是從當(dāng)前的Activity跳轉(zhuǎn)到Service
intent2=new Intent(this,MusicService.class);
conn=new MyServiceConn();//創(chuàng)建服務(wù)連接對(duì)象
bindService(intent2,conn,BIND_AUTO_CREATE);//綁定服務(wù)
//為滑動(dòng)條添加事件監(jiān)聽,每個(gè)控件不同果然點(diǎn)擊事件方法名都不同
sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
//這一行注解是保證API在KITKAT以上的模擬器才能順利運(yùn)行,也就是19以上
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
//進(jìn)當(dāng)滑動(dòng)條到末端時(shí),結(jié)束動(dòng)畫
if (progress==seekBar.getMax()){
animator.pause();//停止播放動(dòng)畫
}
}
@Override
//滑動(dòng)條開始滑動(dòng)時(shí)調(diào)用
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
//滑動(dòng)條停止滑動(dòng)時(shí)調(diào)用
public void onStopTrackingTouch(SeekBar seekBar) {
//根據(jù)拖動(dòng)的進(jìn)度改變音樂播放進(jìn)度
int progress=seekBar.getProgress();//獲取seekBar的進(jìn)度
musicControl.seekTo(progress);//改變播放進(jìn)度
}
});
//聲明并綁定音樂播放器的iv_music控件
ImageView iv_music=(ImageView)findViewById(R.id.iv_music);
String position= intent1.getStringExtra("position");
//praseInt()就是將字符串變成整數(shù)類型
int i=parseInt(position);
iv_music.setImageResource(frag1.icons[i]);
//rotation和0f,360.0f就設(shè)置了動(dòng)畫是從0°旋轉(zhuǎn)到360°
animator=ObjectAnimator.ofFloat(iv_music,"rotation",0f,360.0f);
animator.setDuration(10000);//動(dòng)畫旋轉(zhuǎn)一周的時(shí)間為10秒
animator.setInterpolator(new LinearInterpolator());//勻速
animator.setRepeatCount(-1);//-1表示設(shè)置動(dòng)畫無限循環(huán)
}
//handler機(jī)制,可以理解為線程間的通信,我獲取到一個(gè)信息,然后把這個(gè)信息告訴你,就這么簡(jiǎn)單
public static Handler handler=new Handler(){//創(chuàng)建消息處理器對(duì)象
//在主線程中處理從子線程發(fā)送過來的消息
@Override
public void handleMessage(Message msg){
Bundle bundle=msg.getData();//獲取從子線程發(fā)送過來的音樂播放進(jìn)度
//獲取當(dāng)前進(jìn)度currentPosition和總時(shí)長(zhǎng)duration
int duration=bundle.getInt("duration");
int currentPosition=bundle.getInt("currentPosition");
//對(duì)進(jìn)度條進(jìn)行設(shè)置
sb.setMax(duration);
sb.setProgress(currentPosition);
//歌曲是多少分鐘多少秒鐘
int minute=duration/1000/60;
int second=duration/1000%60;
String strMinute=null;
String strSecond=null;
if(minute<10){//如果歌曲的時(shí)間中的分鐘小于10
strMinute="0"+minute;//在分鐘的前面加一個(gè)0
}else{
strMinute=minute+"";
}
if (second<10){//如果歌曲中的秒鐘小于10
strSecond="0"+second;//在秒鐘前面加一個(gè)0
}else{
strSecond=second+"";
}
//這里就顯示了歌曲總時(shí)長(zhǎng)
tv_total.setText(strMinute+":"+strSecond);
//歌曲當(dāng)前播放時(shí)長(zhǎng)
minute=currentPosition/1000/60;
second=currentPosition/1000%60;
if(minute<10){//如果歌曲的時(shí)間中的分鐘小于10
strMinute="0"+minute;//在分鐘的前面加一個(gè)0
}else{
strMinute=minute+" ";
}
if (second<10){//如果歌曲中的秒鐘小于10
strSecond="0"+second;//在秒鐘前面加一個(gè)0
}else{
strSecond=second+" ";
}
//顯示當(dāng)前歌曲已經(jīng)播放的時(shí)間
tv_progress.setText(strMinute+":"+strSecond);
}
};
//用于實(shí)現(xiàn)連接服務(wù),比較模板化,不需要詳細(xì)知道內(nèi)容
class MyServiceConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service){
musicControl=(MusicService.MusicControl) service;
}
@Override
public void onServiceDisconnected(ComponentName name){
}
}
//判斷服務(wù)是否被解綁
private void unbind(boolean isUnbind){
//如果解綁了
if(!isUnbind){
musicControl.pausePlay();//音樂暫停播放
unbindService(conn);//解綁服務(wù)
}
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_play://播放按鈕點(diǎn)擊事件
String position=intent1.getStringExtra("position");
int i=parseInt(position);
musicControl.play(i);
animator.start();
break;
case R.id.btn_pause://暫停按鈕點(diǎn)擊事件
musicControl.pausePlay();
animator.pause();
break;
case R.id.btn_continue_play://繼續(xù)播放按鈕點(diǎn)擊事件
musicControl.continuePlay();
animator.start();
break;
case R.id.btn_exit://退出按鈕點(diǎn)擊事件
unbind(isUnbind);
isUnbind=true;
finish();
break;
}
}
@Override
protected void onDestroy(){
super.onDestroy();
unbind(isUnbind);//解綁服務(wù)
}
}
(2)activity_music: 顯示音樂播放器界面,包括圖片轉(zhuǎn)動(dòng),歌曲名傳值,還有播放、暫停播放、繼續(xù)播放和退出四個(gè)控制按鈕。效果如圖:

activity_music代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/music_bg"
tools:context=".Music_Activity"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_music"
android:layout_width="240dp"
android:layout_height="240dp"
android:layout_gravity="center_horizontal"
android:layout_margin="15dp"
android:src="@drawable/music0"/>
<TextView
android:id="@+id/song_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="歌曲名"
android:textSize="20sp"/>
<SeekBar
android:id="@+id/sb"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="8dp"
android:paddingRight="8dp">
<TextView
android:id="@+id/tv_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00"/>
<TextView
android:id="@+id/tv_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="00:00"/>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_play"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_margin="8dp"
android:layout_weight="1"
android:background="@drawable/btn_bg_selector"
android:text="播放音樂"/>
<Button
android:id="@+id/btn_pause"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_margin="8dp"
android:layout_weight="1"
android:background="@drawable/btn_bg_selector"
android:text="暫停播放"/>
<Button
android:id="@+id/btn_continue_play"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_margin="8dp"
android:layout_weight="1"
android:background="@drawable/btn_bg_selector"
android:text="繼續(xù)播放"/>
<Button
android:id="@+id/btn_exit"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_margin="8dp"
android:layout_weight="1"
android:background="@drawable/btn_bg_selector"
android:text="退出"/>
</LinearLayout>
</LinearLayout>
(3)右擊drawable文件夾,New——>Drawable Resource File,命名為btn_bg_selector,如圖:

該文件為按鈕顏色選擇器,是當(dāng)播放等按鈕按下的時(shí)候變成灰色,未按下顯示白色。代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="10dp"/>
<solid android:color="#d4d4d4"/>
</shape>
</item>
<item android:state_pressed="false">
<shape android:shape="rectangle">
<corners android:radius="10dp"/>
<solid android:color="#ffffff"/>
</shape>
</item>
</selector>
4、搭建音樂列表界面布局
右擊包名——>New——>Java Class,命名為frag1,點(diǎn)擊OK。如圖:

(1)frag1類:顯示歌曲列表,手機(jī)模擬器運(yùn)行出來的默認(rèn)界面,就是將歌曲名、歌曲圖片以列表的形式顯示出來,注釋很詳細(xì),代碼如下:
package zj.dzh.music_list;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
public class frag1 extends Fragment {
private View view;
//創(chuàng)建歌曲的String數(shù)組和歌手圖片的int數(shù)組
public String[] name={"鄧紫棋——光年之外","蔡健雅——紅色高跟鞋","Taylor Swift——Love Story"};
public static int[] icons={R.drawable.music0,R.drawable.music1,R.drawable.music2};
@Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
//綁定布局,只不過這里是用inflate()方法
view=inflater.inflate(R.layout.music_list,null);
//創(chuàng)建listView列表并且綁定控件
ListView listView=view.findViewById(R.id.lv);
//實(shí)例化一個(gè)適配器
MyBaseAdapter adapter=new MyBaseAdapter();
//列表設(shè)置適配器
listView.setAdapter(adapter);
//列表元素的點(diǎn)擊監(jiān)聽器
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//創(chuàng)建Intent對(duì)象,參數(shù)就是從frag1跳轉(zhuǎn)到MusicActivity
Intent intent=new Intent(frag1.this.getContext(), MusicActivity.class);
//將歌曲名和歌曲的下標(biāo)存入Intent對(duì)象
intent.putExtra("name",name[position]);
intent.putExtra("position",String.valueOf(position));
//開始跳轉(zhuǎn)
startActivity(intent);
}
});
return view;
}
//這里是創(chuàng)建一個(gè)自定義適配器,可以作為模板
class MyBaseAdapter extends BaseAdapter{
@Override
public int getCount(){return name.length;}
@Override
public Object getItem(int i){return name[i];}
@Override
public long getItemId(int i){return i;}
@Override
public View getView(int i ,View convertView, ViewGroup parent) {
//綁定好VIew,然后綁定控件
View view=View.inflate(frag1.this.getContext(),R.layout.item_layout,null);
TextView tv_name=view.findViewById(R.id.item_name);
ImageView iv=view.findViewById(R.id.iv);
//設(shè)置控件顯示的內(nèi)容,就是獲取的歌曲名和歌手圖片
tv_name.setText(name[i]);
iv.setImageResource(icons[i]);
return view;
}
}
}
(2)右擊layout文件夾——>New———>Layout Resource File,新建兩個(gè)layout文件,分別命名為music_list和item_layout,這兩個(gè)布局文件和frag1對(duì)應(yīng),顯示歌曲列表。如圖所示:

music_list:歌曲列表布局文件,和QQ好友列表功能相同,垂直顯示多條記錄。效果如圖:

music_list代碼如下:
<?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:orientation="vertical">
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
item_layout: 就是條目布局,和上面的music_list列表一起組合使用,它就是相當(dāng)于列表中每一行的布局,布局效果如圖:

item_layout代碼如下:
<?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="match_parent"
android:padding="16dp">
<ImageView
android:id="@+id/iv"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerVertical="true"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@+id/iv"
android:layout_centerVertical="true">
<TextView
android:id="@+id/item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="歌曲"
android:textSize="15sp"
android:textColor="#000000"/>
</RelativeLayout>
</RelativeLayout>
5、搭建專輯界面布局
右擊包名,New——>Java Class,命名為frag2,點(diǎn)擊OK。如圖:

(1)frag2類:展示的封面專輯圖片,在主界面點(diǎn)擊專輯按鈕跳轉(zhuǎn)到此界面。代碼如下:
package zj.dzh.music_list;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
public class frag2 extends Fragment {
//創(chuàng)建一個(gè)View
private View zj;
//顯示布局
public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
zj = inflater.inflate(R.layout.frag2_layout, null);
return zj;
}
}
(2)再新建一個(gè)layout文件,命名為frag2_layout,如圖:

frag2_layout用來設(shè)置一個(gè)ImageView,顯示專輯圖片,代碼如下:
<?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">
<ImageView
android:id="@+id/zj"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg"/>
</LinearLayout>
當(dāng)然frag2可以自由發(fā)揮,比如說設(shè)置成歌手資料、MV列表或者排行榜等等。
6、導(dǎo)入資源文件
在res文件夾下新建一個(gè)raw文件夾,將剛剛準(zhǔn)備好的音樂文件復(fù)制粘貼到raw文件夾中。對(duì)應(yīng)的封面圓形圖片、背景圖片和專輯圖片都復(fù)制粘貼到drawable中,這里博主只選擇了三首歌曲和三張封面圓形圖片,歌曲數(shù)量由大家自己設(shè)置,沒有限制。
再次提醒下,注意命名哦;mp3歌曲文件在Android中打開是亂碼,不用擔(dān)心,也不需要打開它。

至此,完整的音樂播放器項(xiàng)目創(chuàng)建完成。
五、項(xiàng)目效果
1、創(chuàng)建模擬器
選擇自己的模擬器運(yùn)行,如果沒有模擬器可以點(diǎn)擊AVD,選擇新建模擬器:

選擇高于API 21的版本進(jìn)行下載,如圖:

2、運(yùn)行演示
(1)運(yùn)行手機(jī)模擬器,顯示主界面:

(2)點(diǎn)擊專輯選項(xiàng)卡:

(3)再選擇歌曲選項(xiàng)卡,選擇第一首歌《光年之外》并打開,跳轉(zhuǎn)到音樂播放頁面,歌手的封面圖片顯示在正中間,發(fā)現(xiàn)《光年之外》的歌名也傳遞過來了:

(4)點(diǎn)擊播放音樂按鈕,音樂開始播放,進(jìn)度條開始滑動(dòng),圖片開始旋轉(zhuǎn):

(5)點(diǎn)擊暫停播放按鈕,音樂停止播放,而且進(jìn)度條停止滑動(dòng),圖片也停止旋轉(zhuǎn):

(6)點(diǎn)擊繼續(xù)播放按鈕,音樂繼續(xù)播放,歌手圖片也繼續(xù)旋轉(zhuǎn):

(7)點(diǎn)擊退出按鈕,會(huì)退回到主界面:

(8)選擇第二首歌《紅色高跟鞋》并播放,這里進(jìn)度條可以自由拖動(dòng),歌曲也會(huì)隨之播放到對(duì)應(yīng)位置:

(9)選擇第三首歌《Love Story》并播放:

運(yùn)行效果和功能很完整,至此完成了音樂播放器的實(shí)現(xiàn),喜歡的朋友們可以自己動(dòng)手做一下,放上自己喜歡的愛豆照片,還有喜歡的歌,體驗(yàn)感真的不要太好!
六、項(xiàng)目總結(jié)
這次音樂播放器工程,可以讓大家熟練掌握Android程序開發(fā)的基本技術(shù),涉及Android 基礎(chǔ)知識(shí)、UI界面、數(shù)據(jù)存儲(chǔ)、四大組件、網(wǎng)絡(luò)編程、高級(jí)編程等。大家熟練掌握可以對(duì)以后的Android開發(fā)有很大的幫助。
附如何將圖片剪成圓形
1、將要裁剪的圖片(寬高一致的矩形圖片)復(fù)制到WPS文檔中:

2、點(diǎn)擊右邊豎排工具欄中的裁剪圖片選項(xiàng),如圖:

3、選擇橢圓選項(xiàng)(矩陣圖片剪出來就是圓形),如圖:

4、點(diǎn)擊上方工具欄中的裁剪選項(xiàng),圖片裁剪成圓形:

5、右擊圓形區(qū)域,點(diǎn)擊另存為圖片,將圖片保存到本地使用。

到此這篇關(guān)于Android Studio實(shí)現(xiàn)音樂播放器的文章就介紹到這了,更多相關(guān)Android Studio實(shí)現(xiàn)音樂播放器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android對(duì)圖片Drawable實(shí)現(xiàn)變色示例代碼
這篇文章主要給大家介紹了關(guān)于Android對(duì)圖片Drawable實(shí)現(xiàn)變色的相關(guān)資料,文中通過示例代碼將實(shí)現(xiàn)的方法介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-08-08
Android編程使用sax解析xml數(shù)據(jù)的方法詳解
這篇文章主要介紹了Android編程使用sax解析xml數(shù)據(jù)的方法,結(jié)合實(shí)例形式詳細(xì)分析了Android使用sax解析xml數(shù)據(jù)的操作步驟及界面布局、單元測(cè)試等相關(guān)操作技巧,需要的朋友可以參考下2017-07-07
Android網(wǎng)絡(luò)開發(fā)中GET與POST請(qǐng)求詳解
這篇文章主要介紹了android實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求的get和post請(qǐng)求的簡(jiǎn)單封裝與使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧<BR>2022-12-12
Android實(shí)現(xiàn)一個(gè)比相冊(cè)更高大上的左右滑動(dòng)特效(附源碼)
這篇文章主要介紹了Android實(shí)現(xiàn)一個(gè)比相冊(cè)更高大上的左右滑動(dòng)特效(附源碼),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02
Android Activity的生命周期與啟動(dòng)模式全面解讀
雖然說我們天天都在使用Activity,但是你真的對(duì)Activity的生命機(jī)制完全了解了嗎?Activity的生命周期方法只有七個(gè),但是其實(shí)那只是默認(rèn)的情況。也就是說在其他情況下,Activity的生命周期可能不會(huì)是按照我們以前所知道的流程,這就要說到Activity的啟動(dòng)模式2021-10-10
深入學(xué)習(xí)Android?ANR?的原理分析及解決辦法
Android系統(tǒng)中,AMS和WMS會(huì)檢測(cè)App的響應(yīng)時(shí)間,如果App在特定時(shí)間無法相應(yīng)屏幕觸摸或鍵盤輸入時(shí)間,或者特定事件沒有處理完畢,就會(huì)出現(xiàn)ANR。本文將帶領(lǐng)大學(xué)深入學(xué)習(xí)一下ANR的原理及解決辦法,感興趣的同學(xué)可以學(xué)習(xí)一下2021-11-11
android?studio數(shù)據(jù)存儲(chǔ)建立SQLite數(shù)據(jù)庫實(shí)現(xiàn)增刪查改
這篇文章主要介紹了vandroid?studio數(shù)據(jù)存儲(chǔ)建立SQLite數(shù)據(jù)庫實(shí)現(xiàn)增刪查改,分別使用sqlite3工具和Android代碼的方式建立SQLite數(shù)據(jù)庫,具體內(nèi)容,需要的小伙伴可以參考下面文章得詳細(xì)內(nèi)容2021-12-12
詳解Android?Flutter如何使用相機(jī)實(shí)現(xiàn)拍攝照片
在app中使用相機(jī)肯定是再平常不過的一項(xiàng)事情了,相機(jī)肯定涉及到了底層原生代碼的調(diào)用,那么在flutter中如何快速簡(jiǎn)單的使用上相機(jī)的功能呢?一起來看看吧2023-04-04
詳細(xì)分析android的MessageQueue.IdleHandler
這篇文章主要介紹了android的MessageQueue.IdleHandler用法,很有參考價(jià)值,歡迎大家在下方留言區(qū)討論。2017-11-11
使用Fragment來處理Andoird app的UI布局的實(shí)例分享
這篇文章主要介紹了使用Fragment來處理Andoird appUI布局的實(shí)例分享,Fragment的出現(xiàn)緩解了代碼依賴于Activity而造成的臃腫狀況,需要的朋友可以參考下2016-02-02

