Este es un proyecto de reproductor de música simple que hice en mi segundo año el año pasado: fue escrito tanto como sea posible para imitar Kugou Music, y las funciones específicas son las siguientes:
1: Animación de inicio: haga clic para ejecutar el programa y aparecerá un video de dos segundos, similar a la animación de inicio de Kugou Music, ¡muy impresionante!
2: Interfaz de registro de inicio de sesión: ¡Ingrese el número de cuenta y la contraseña para verificar la información para iniciar sesión!
3: Carrusel: exactamente igual que Kugou Music, hay un carrusel de ciclo automático sobre la interfaz principal, haga clic en la información de cada imagen del carrusel para ingresar al servicio específico correspondiente, ¡muy puntos extra!
4: giradiscos de grabación de música, barra de progreso de sincronización de canciones y cambio de canción de pausa/reproducción/continuación/arriba y abajo de música.
5: ¡Se realiza la búsqueda de música!
6: ¡Reproduce la columna de video!
7; Se realiza el diseño de la interfaz de información personal, como comentarios, calificación, más, apodo de edad de género, colección, etc.
El tocadiscos del disco de música, la barra de progreso de sincronización de canciones y el código de cambio de canción pausa/reproducción/continuación/arriba y abajo de música son los siguientes:
MusicService.java
package com.ypc.xiaoxiongmusic;
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;
public class MusicService extends Service {
private MediaPlayer player;
private Timer timer;//引入⏲
@Override
//构造
public IBinder onBind(Intent intent){
return new MusicControl();
}
@Override
public void onCreate(){
super.onCreate();
player=new MediaPlayer();//创建音乐播放器对象
}
public void addTimer(){ //添加计时器用于设置音乐播放器中的播放进度条
if(timer==null){
timer=new Timer();//创建计时器对象
TimerTask task=new TimerTask() {
@Override
public void run() {
if (player==null) return;
int duration=player.getDuration();//获取歌曲总时长
int currentPosition=player.getCurrentPosition();//获取当前播放进度
Message msg=Music_Activity.handler.obtainMessage();//创建消息对象
//将音乐的总时长和播放进度封装至消息对象中
//用getcurrentduration,和getduration获取时间,用bundle封装,handler线程传递
Bundle bundle=new Bundle();
bundle.putInt("duration",duration);
bundle.putInt("currentPosition",currentPosition);
msg.setData(bundle);
//将消息发送到主线程的消息队列
Music_Activity.handler.sendMessage(msg);
}
};
//开始计时任务后的5毫秒,第一次执行task任务,以后每500毫秒执行一次
timer.schedule(task,5,500);
}
}
class MusicControl extends Binder{//Binder是一种跨进程的通信方式
public void play(int i){//String path
Uri uri=null;
switch(i) {
case 0:uri = Uri.parse("http://music.163.com/song/media/outer/url?id=5316513.mp3");
break;
case 1:uri = Uri.parse("http://music.163.com/song/media/outer/url?id=409646185.mp3");
break;
case 2:uri= Uri.parse("http://music.163.com/song/media/outer/url?id=26125687.mp3");
break;
case 3:uri = Uri.parse("http://music.163.com/song/media/outer/url?id=516358417.mp3");
break;
case 4: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1492886765.mp3");
break;
case 5: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1436910205.mp3");
break;
case 6: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1399533630.mp3");
break;
case 7: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=32835565.mp3");
break;
case 8: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1422992414.mp3");
break;
case 9: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=29004400.mp3");
break;
case 10: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1439111141.mp3");
break;
case 11: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=29418041.mp3");
break;
case 12: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=472137749.mp3");
break;
case 13: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=507364050.mp3");
break;
case 14: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=426291338.mp3");
break;
case 15: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=34228112.mp3");
break;
case 16: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1428605192.mp3");
break;
case 17: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=33190545.mp3");
break;
case 18: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=32619105.mp3");
break;
case 19: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1425643256.mp3");
break;
case 20: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1305366556.mp3");
break;
case 21: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=481859794.mp3");
break;
case 22: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1424537185.mp3");
break;
case 23: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1403445370.mp3");
break;
case 24: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=36668004.mp3");
break;
case 25: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=548650088.mp3");
break;
case 26: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1409296047.mp3");
break;
case 27: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1389152878.mp3");
break;
case 28: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=475279382.mp3");
break;
case 29: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1464390595.mp3");
break;
case 30: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1464389589.mp3");
break;
case 31: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1464446728.mp3");
break;
case 32: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=1464389585.mp3");
break;
case 33: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=29343374.mp3");
break;
case 34: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=187564.mp3");
break;
case 35: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=26075355.mp3");
break;
case 36: uri = Uri.parse("http://music.163.com/song/media/outer/url?id=187374.mp3");
break;
}
try {
player.reset();//重置音乐播放器
//加载多媒体文件
player = MediaPlayer.create(getApplicationContext(), uri);
player.start();//播放音乐
addTimer();//添加计时器
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean pausePlay(){
player.pause();//暂停播放音乐
return false;
}
public void continuePlay(){
player.start();//继续播放音乐
}
public void seekTo(int progress){
player.seekTo(progress);//设置音乐的播放位置
}
}
@Override
public void onDestroy(){
super.onDestroy();
if(player==null) return;
if(player.isPlaying()) player.stop();//停止播放音乐
player.release();//释放占用的资源
player=null;//将player置为空
}
}
Music_Activity.java
package com.ypc.xiaoxiongmusic;
import android.animation.ObjectAnimator;
import android.app.Activity;
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.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.annotation.RequiresApi;
import static java.lang.Integer.parseInt;
public class Music_Activity extends Activity implements View.OnClickListener{
private static SeekBar sb;
private static TextView tv_progress,tv_total;
private ObjectAnimator animator;//
private MusicService .MusicControl musicControl;//
private ImageView bt_1;
private ImageView iv_music;
private TextView tv_name;
private int change;
String name;
Intent intent1,intent2;
MyServiceConn conn;//
private boolean isUnbind =false;//记录服务是否被解绑
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music);
intent1=getIntent();
init();
View v=findViewById(R.id.bg_1);
// v.getBackground().setAlpha(180);
tv_name=findViewById(R.id.song_name);
iv_music=findViewById(R.id.iv_music);
bt_1=findViewById(R.id.bt_1);
bt_1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
private void init(){
tv_progress=(TextView)findViewById(R.id.tv_progress);
tv_total=(TextView)findViewById(R.id.tv_total);
sb=(SeekBar)findViewById(R.id.sb);
TextView tv_name=(TextView)findViewById(R.id.song_name);
ImageView iv_music=(ImageView)findViewById(R.id.iv_music);
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_next).setOnClickListener(this);
findViewById(R.id.btn_jixu).setOnClickListener(this);
name=intent1.getStringExtra("name");
tv_name.setText(name);
intent2=new Intent(this,MusicService.class);//创建意图对象
conn=new MyServiceConn();//创建服务连接对象
bindService(intent2,conn,BIND_AUTO_CREATE);//绑定服务
//为滑动条添加事件监听
sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
//进度条改变时,会调用此方法
if (progress==seekBar.getMax()){//当滑动条到末端时,结束动画
animator.pause();//停止播放动画
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {//滑动条开始滑动时调用
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {//滑动条停止滑动时调用
//根据拖动的进度改变音乐播放进度
int progress=seekBar.getProgress();//获取seekBar的进度
musicControl.seekTo(progress);//改变播放进度
}
});
animator= ObjectAnimator.ofFloat(iv_music,"rotation",0f,360.0f);
animator.setDuration(15000);//动画旋转一周的时间为10秒
animator.setInterpolator(new LinearInterpolator());//匀速
animator.setRepeatCount(-1);//-1表示设置动画无限循环
}
public static Handler handler=new Handler(){//创建消息处理器对象
//在主线程中处理从子线程发送过来的消息
@Override
public void handleMessage(Message msg){
Bundle bundle=msg.getData();//获取从子线程发送过来的音乐播放进度
int duration=bundle.getInt("duration");
int currentPosition=bundle.getInt("currentPosition");
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){//如果歌曲的时间中的分钟小于10
strMinute="0"+minute;//在分钟的前面加一个0
}else{
strMinute=minute+"";
}
if (second<10){//如果歌曲中的秒钟小于10
strSecond="0"+second;//在秒钟前面加一个0
}else{
strSecond=second+"";
}
tv_total.setText(strMinute+":"+strSecond);
//歌曲当前播放时长
minute=currentPosition/1000/60;
second=currentPosition/1000%60;
if(minute<10){//如果歌曲的时间中的分钟小于10
strMinute="0"+minute;//在分钟的前面加一个0
}else{
strMinute=minute+" ";
}
if (second<10){//如果歌曲中的秒钟小于10
strSecond="0"+second;//在秒钟前面加一个0
}else{
strSecond=second+" ";
}
tv_progress.setText(strMinute+":"+strSecond);
}
};
class MyServiceConn implements ServiceConnection {//创建一个自定义类用于实现连接服务
@Override
public void onServiceConnected(ComponentName name, IBinder service){
musicControl=(MusicService.MusicControl) service;
}
@Override
public void onServiceDisconnected(ComponentName name){
}
}
private void unbind(boolean isUnbind){
if(!isUnbind){//判断服务是否被解绑
musicControl.pausePlay();//暂停播放音乐
unbindService(conn);//解绑服务
}
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)//如果注释掉,则需要手动在grideMouble里面把api从15调到更高如19
@Override
public void onClick(View v) {
String position=intent1.getStringExtra("position");
int i=parseInt(position);
switch (v.getId()){
case R.id.btn_play://播放按钮点击事件
musicControl.play(i);
animator.start();
break;
case R.id.btn_pause://暂停按钮点击事件
musicControl.pausePlay();
animator.pause();
break;
case R.id.btn_jixu://继续按钮点击事件
musicControl.continuePlay();
animator.resume();
break;
case R.id.btn_continue_play://上一首
if(( i +change)<1) {
change=name.length()-1-i;
musicControl.play(i+change);
animator.resume();
tv_name.setText(name);
}
else {
change--;
musicControl.play(i+change);
animator.resume();
break;
}
case R.id.btn_next://下一首按钮点击事件
if((i+change)==name.length()-1) {//这里Name.length-1表示的最后一首歌的下标,即歌曲总数-1
change=-i;
musicControl.play(i+change);
iv_music.setImageResource(musicFragment.icons[i+change]);
// name_song.setText(name);
animator.start();
tv_name.setText((String)musicFragment.name[i+change]);
}
else {
change++;
iv_music.setImageResource(musicFragment.icons[i+change]);
tv_name.setText(musicFragment.name[i+change]);
musicControl.play(i+change);
animator.resume();
break;
}
}
}
//不注释,则返回上一界面,会摧毁暂停音乐
/* @Override
protected void onDestroy(){
super.onDestroy();
unbind(isUnbind);//解绑服务
}*/
}
actividad_musica.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".Music_Activity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@drawable/tpbj"
android:id="@+id/bg_1">
<ImageView
android:src="@drawable/back1"
android:id="@+id/bt_1"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/back_layout"
android:paddingLeft="10dp">
</ImageView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="-100dp"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_music"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center_horizontal"
android:layout_margin="15dp"
android:src="@drawable/musicx" />
<TextView
android:id="@+id/song_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="歌曲名"
android:textSize="18sp" />
<SeekBar
android:id="@+id/sb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
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="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:orientation="horizontal">
<ImageButton
android:id="@+id/btn_continue_play"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_marginTop="8dp"
android:background="@drawable/music_play"
android:src="@drawable/xx1" />
<ImageButton
android:id="@+id/btn_play"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_marginLeft="40dp"
android:layout_marginTop="8dp"
android:background="@drawable/music_play"
android:src="@drawable/xx4" />
<ImageButton
android:id="@+id/btn_pause"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_marginLeft="40dp"
android:layout_marginTop="8dp"
android:background="@drawable/music_play"
android:src="@drawable/xx5" />
<ImageButton
android:id="@+id/btn_jixu"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_marginLeft="40dp"
android:layout_marginTop="8dp"
android:background="@drawable/music_nextplay"
android:src="@drawable/xx2" />
<ImageButton
android:id="@+id/btn_next"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_marginLeft="40dp"
android:layout_marginTop="8dp"
android:background="@drawable/music_nextplay"
android:src="@drawable/xx3" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
La captura de pantalla del efecto es la siguiente: