播放列表功能开发

This commit is contained in:
litingting 2024-09-30 16:45:21 +08:00
parent 90564a274c
commit 72bf148ad5
17 changed files with 801 additions and 235 deletions

View File

@ -7,7 +7,6 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission <uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE" android:name="android.permission.READ_EXTERNAL_STORAGE"

View File

@ -21,11 +21,36 @@ import com.hi.music.player.javabean.response.ResponsePlayListInfo;
import com.hi.music.player.media3.MyMediaControllerManager; import com.hi.music.player.media3.MyMediaControllerManager;
public class AdapterPlayList extends BaseAdapter<ResponsePlayListInfo, ItemPlayListBinding> { public class AdapterPlayList extends BaseAdapter<ResponsePlayListInfo, ItemPlayListBinding> {
private String mCurVideId;
private String lastVideId;
private int curMusicPos = 0;
private MyMediaControllerManager instance = MyMediaControllerManager.getInstance();
@Override @Override
protected ItemPlayListBinding getViewBinding(ViewGroup parent) { protected ItemPlayListBinding getViewBinding(ViewGroup parent) {
return ItemPlayListBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); return ItemPlayListBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
} }
public void setCurVideId(String curVideId) {
lastVideId = mCurVideId;
this.mCurVideId = curVideId;
for (int i = 0; i < data.size(); i++) {
ResponsePlayListInfo listInfo = data.get(i);
if (listInfo.getVideoId().equals(curVideId)) {
notifyItemChanged(i);
}
if (listInfo.getVideoId().equals(lastVideId)) {
notifyItemChanged(i);
}
}
}
public void updateCurMusicAnimation(){
notifyItemChanged(curMusicPos);
}
@Override @Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
@ -40,20 +65,32 @@ public class AdapterPlayList extends BaseAdapter<ResponsePlayListInfo, ItemPlayL
.into(vb.imCovert); .into(vb.imCovert);
vb.songName.setText(listInfo.getSongTitle()); vb.songName.setText(listInfo.getSongTitle());
vb.artistName.setText(listInfo.getSingerName()); vb.artistName.setText(listInfo.getSingerName());
MyMediaControllerManager instance = MyMediaControllerManager.getInstance();
MediaItem currentMediaItem = instance.getMediaController().getCurrentMediaItem(); MediaItem currentMediaItem = instance.getMediaController().getCurrentMediaItem();
if (currentMediaItem != null && currentMediaItem.mediaId.equals(listInfo.getVideoId())) { if (currentMediaItem != null && currentMediaItem.mediaId.equals(listInfo.getVideoId())) {
vb.lottieAnimationView.setVisibility(View.VISIBLE); vb.viewPlaying.setVisibility(View.VISIBLE);
vb.getRoot().setBackgroundColor(CommonUtils.getMyColor(R.color.cur_play_music));
if (instance.getMediaController().isPlaying()) { if (instance.getMediaController().isPlaying()) {
vb.lottieAnimationView.playAnimation(); vb.viewPlaying.startAnimating();
lastVideId = listInfo.getVideoId();
CommonUtils.LogMsg("-------playAnimation"); CommonUtils.LogMsg("-------playAnimation");
} else { } else {
vb.lottieAnimationView.pauseAnimation(); vb.viewPlaying.pauseAnimating();
CommonUtils.LogMsg("-------pauseAnimation"); CommonUtils.LogMsg("-------pauseAnimation");
} }
} else { } else {
vb.lottieAnimationView.setVisibility(View.GONE); vb.viewPlaying.setVisibility(View.GONE);
CommonUtils.LogMsg("-------GONE"); // CommonUtils.LogMsg("-------GONE");
} }
vb.itemLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CommonUtils.LogMsg("-------onClick curMusicPos="+itemHolder.getAbsoluteAdapterPosition());
setCurVideId(listInfo.getVideoId());
instance.playPositionMusic(itemHolder.getAbsoluteAdapterPosition());
}
});
} }
} }

View File

@ -0,0 +1,158 @@
package com.hi.music.player.customerview;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;
import com.hi.music.player.helper.CommonUtils;
import java.util.Random;
public class AnimaPlayingView extends View {
private Paint paint;
private int barColor = Color.GREEN; // 音量条的颜色
private int numBars = 5; // 音量条的数量
private float[] barHeights; // 每个音量条的高度
private int maxHeight = CommonUtils.dpToPx(20); // 音量条的最大高度
private int minHeight = CommonUtils.dpToPx(4); // 音量条的最小高度
// 每个柱子的宽度
private int barWidth =CommonUtils. dpToPx(4);
// 柱子之间的间距
private int barSpacing = CommonUtils.dpToPx(2);
private int cornerRadius = CommonUtils.dpToPx(16);
private Random random;
private ValueAnimator animator;
public AnimaPlayingView(Context context) {
super(context);
init();
}
public AnimaPlayingView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AnimaPlayingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
paint = new Paint();
paint.setColor(barColor);
paint.setStyle(Paint.Style.FILL);
barHeights = new float[numBars];
random = new Random();
// 初始化音量条高度
for (int i = 0; i < numBars; i++) {
barHeights[i] = 0;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int height = getHeight();
int width = getWidth();
int barCount = barHeights.length;
int totalWidth = barCount * barWidth + (barCount - 1) * barSpacing;
int startX = (width - totalWidth) / 2;
for (int i = 0; i < numBars; i++) {
float left = startX + i * (barWidth + barSpacing);
float top = height - barHeights[i];
float right = left + barWidth;
float bottom = height;
canvas.drawRoundRect(left, top, right, bottom, cornerRadius, cornerRadius, paint);
}
}
// 启动固定动画使音量条的高度变化
public void startAnimating() {
for (int i = 0; i < numBars; i++) {
animator = ValueAnimator.ofFloat(0, 1);
animator.setDuration(1000); // 每0.5秒更新一次
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.setInterpolator(new LinearInterpolator());
int finalI = i;
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 更新每个音量条的高度使其不断变化
float animatedValue = (Float) animation.getAnimatedValue();
float v = animatedValue * maxHeight;
barHeights[finalI] = v;
invalidate(); // 重绘视图
}
});
animator.setStartDelay(i* 200L);
animator.start();
}
}
public void pauseAnimating(){
if(animator!= null){
animator.pause();
}
for (int i = 0; i < numBars; i++) {
barHeights[i] = minHeight;
}
invalidate();
}
// 随机生成音量条的高度
private float randomHeight() {
return minHeight + random.nextFloat() * (maxHeight - minHeight);
}
// 设置音量条的颜色
public void setBarColor(int color) {
barColor = color;
paint.setColor(barColor);
invalidate();
}
// 设置音量条的最大高度
public void setMaxHeight(int maxHeight) {
this.maxHeight = maxHeight;
invalidate();
}
// 设置音量条的最小高度
public void setMinHeight(int minHeight) {
this.minHeight = minHeight;
invalidate();
}
// 设置音量条数量
public void setNumBars(int numBars) {
this.numBars = numBars;
barHeights = new float[numBars];
invalidate();
}
}

View File

@ -6,13 +6,16 @@ import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
import android.net.Uri;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.widget.ImageView; import android.widget.ImageView;
import androidx.media3.common.MediaItem;
import androidx.palette.graphics.Palette; import androidx.palette.graphics.Palette;
import com.hi.music.player.MusicApplication; import com.hi.music.player.MusicApplication;
import com.hi.music.player.R;
import com.hi.music.player.api.onImageColorListener; import com.hi.music.player.api.onImageColorListener;
import org.json.JSONException; import org.json.JSONException;
@ -51,6 +54,7 @@ public class CommonUtils {
public static int dpToPx(int dp) { public static int dpToPx(int dp) {
return Math.round(dp * (MusicApplication.myApplication.getResources().getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT)); return Math.round(dp * (MusicApplication.myApplication.getResources().getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT));
} }
public static int pxToDp(int px) { public static int pxToDp(int px) {
return Math.round(px / (MusicApplication.myApplication.getResources().getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT)); return Math.round(px / (MusicApplication.myApplication.getResources().getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT));
} }
@ -65,7 +69,7 @@ public class CommonUtils {
return navigationBarHeight; return navigationBarHeight;
} }
public static int getStatusBarHeight(Context context) { public static int getStatusBarHeight(Context context) {
int statusBarHeight = 0; int statusBarHeight = 0;
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) { if (resourceId > 0) {
@ -75,7 +79,6 @@ public class CommonUtils {
} }
//time 3:45 //time 3:45
public static long convertToMilliseconds(String time) { public static long convertToMilliseconds(String time) {
String[] parts = time.split(":"); String[] parts = time.split(":");
@ -92,37 +95,42 @@ public class CommonUtils {
return String.format("%d:%02d", minutes, seconds); // 格式化为 mm:ss return String.format("%d:%02d", minutes, seconds); // 格式化为 mm:ss
} }
public static int getMyColor(int resId) {
return MusicApplication.myApplication.getColor(resId);
}
// 使用 Palette 提取深色主色调 // 使用 Palette 提取深色主色调
public static void getDominantDarkColor1(Drawable imDraw, onImageColorListener listener) { public static void getDominantDarkColor1(Drawable imDraw, onImageColorListener listener) {
// 异步生成 Palette // 异步生成 Palette
BitmapDrawable drawable = (BitmapDrawable)imDraw; BitmapDrawable drawable = (BitmapDrawable) imDraw;
if(drawable!=null){ if (drawable != null) {
Bitmap bitmap = drawable.getBitmap(); Bitmap bitmap = drawable.getBitmap();
Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() { Palette.from(bitmap)
@Override .generate(new Palette.PaletteAsyncListener() {
public void onGenerated(Palette palette) { @Override
// 首先尝试获取深色活力色 public void onGenerated(Palette palette) {
Palette.Swatch darkVibrantSwatch = palette.getDarkVibrantSwatch(); // 首先尝试获取深色活力色
Palette.Swatch darkVibrantSwatch = palette.getDarkVibrantSwatch();
// 如果没有深色活力色尝试获取深色柔和色 // 如果没有深色活力色尝试获取深色柔和色
if (darkVibrantSwatch == null) { if (darkVibrantSwatch == null) {
darkVibrantSwatch = palette.getDarkMutedSwatch(); darkVibrantSwatch = palette.getDarkMutedSwatch();
} }
// 如果存在深色样本则获取其 RGB 颜色值 // 如果存在深色样本则获取其 RGB 颜色值
if (darkVibrantSwatch != null) { if (darkVibrantSwatch != null) {
int dominantDarkColor = darkVibrantSwatch.getRgb(); int dominantDarkColor = darkVibrantSwatch.getRgb();
listener.onImageColor(dominantDarkColor); listener.onImageColor(dominantDarkColor);
String dominantColorHex = String.format("#%06X", (0xFFFFFF & dominantDarkColor)); String dominantColorHex = String.format("#%06X", (0xFFFFFF & dominantDarkColor));
Log.d("Dominant Dark Color", "主色调: " + dominantColorHex); // 打印主色调 Log.d("Dominant Dark Color", "主色调: " + dominantColorHex); // 打印主色调
} else { } else {
Log.d("Dominant Dark Color", "未找到深色主色调"); Log.d("Dominant Dark Color", "未找到深色主色调");
listener.onImageColor(-1); listener.onImageColor(-1);
} }
} }
}); });
}else { } else {
listener.onImageColor(-1); listener.onImageColor(-1);
} }
@ -142,7 +150,7 @@ public class CommonUtils {
} }
public static Drawable getNewDrawable(int color,float RadiusTopLeft,float RadiusTopRight,float RadiusBottomRight,float RadiusBottomLeft){ public static Drawable getNewDrawable(int color, float RadiusTopLeft, float RadiusTopRight, float RadiusBottomRight, float RadiusBottomLeft) {
// 创建 GradientDrawable // 创建 GradientDrawable
GradientDrawable drawable = new GradientDrawable(); GradientDrawable drawable = new GradientDrawable();
@ -162,4 +170,34 @@ public class CommonUtils {
drawable.setCornerRadii(radii); drawable.setCornerRadii(radii);
return drawable; return drawable;
} }
/**
* 当前媒体项是否有有效的播放地址
* @param mediaItem
* @return
*/
public static boolean hasValidUri(MediaItem mediaItem) {
MediaItem.LocalConfiguration localConfiguration = mediaItem.localConfiguration;
if(localConfiguration != null){
if(CommonUtils.isUriFormat(localConfiguration.uri)){
return true;
}
}
return false;
}
private static boolean isUriFormat(Uri parsedUri) {
// 3. 检查 URI 是否具有正确的格式
try {
if (parsedUri.getScheme() == null) {
LogMsg( "URI has no valid scheme.");
return false;
}
} catch (Exception e) {
LogMsg( "URI parsing failed: " + e.getMessage());
return false;
}
return true;
}
} }

View File

@ -13,5 +13,7 @@ public class MyValue {
//暂停或者停止 //暂停或者停止
public final static int PLAY_STATUS_CODE_PAUSE = -3; public final static int PLAY_STATUS_CODE_PAUSE = -3;
//-----------------------------PlayActivity //-----------------------------PlayActivity
} }

View File

@ -0,0 +1,169 @@
package com.hi.music.player.media3;
import android.net.Uri;
import androidx.media3.common.MediaItem;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DataSpec;
import androidx.media3.datasource.ResolvingDataSource;
import androidx.media3.datasource.cache.CacheDataSource;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.drm.DrmSessionManagerProvider;
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
import androidx.media3.exoplayer.source.MediaSource;
import androidx.media3.exoplayer.source.MediaSourceFactory;
import androidx.media3.exoplayer.source.ProgressiveMediaSource;
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;
import com.hi.music.player.api.RequestListener;
import com.hi.music.player.helper.CommonUtils;
import com.hi.music.player.javabean.response.ResponsePlayUrl;
import com.hi.music.player.network.JsonHelper;
import com.hi.music.player.network.RetrofitManager;
import org.json.JSONObject;
import java.io.IOException;
import okhttp3.ResponseBody;
public class DynamicMediaSourceFactory implements MediaSource.Factory {
// private final CacheDataSource.Factory cacheDataSourceFactory;
// private final ExoPlayer player;
private DefaultMediaSourceFactory mediaSourceFactory;
// public DynamicMediaSourceFactory(DefaultMediaSourceFactory factory,CacheDataSource.Factory cacheDataSourceFactory, ExoPlayer exoPlayer) {
// this.cacheDataSourceFactory = cacheDataSourceFactory;
// this.player = exoPlayer;
// this.mediaSourceFactory = factory;
// }
public DynamicMediaSourceFactory(DefaultMediaSourceFactory factory) {
this.mediaSourceFactory = factory;
}
@UnstableApi
@Override
public MediaSource.Factory setDrmSessionManagerProvider(DrmSessionManagerProvider drmSessionManagerProvider) {
return null;
}
@UnstableApi
@Override
public MediaSource.Factory setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
return null;
}
@UnstableApi
@Override
public int[] getSupportedTypes() {
return new int[0];
}
@UnstableApi
@Override
public MediaSource createMediaSource(MediaItem mediaItem) {
CommonUtils.LogMsg("------createMediaSource----------=" + mediaItem.mediaId + "---------" + mediaItem.mediaMetadata.title);
// MediaSource realMediaSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
// .createMediaSource(MediaItem.fromUri(""));
// RetrofitManager.getInstance().getPlayUrl(mediaItem.mediaId, new RequestListener<ResponseBody>() {
//
// @Override
// public void onFail(String errorMsg) {
//
// }
//
// @Override
// public void onSuccess(ResponseBody data) {
// JSONObject jsonObject = CommonUtils.toJsonObject(data);
// if (jsonObject != null) {
// ResponsePlayUrl responsePlayUrl = JsonHelper.ResolvePlayUrlJson(jsonObject);
// if (responsePlayUrl == null) {
// // TODO: 2024/9/27
// return;
// }
// String uri = "";
// if (responsePlayUrl.getAudioUrlMedium() != null) {
// uri = responsePlayUrl.getAudioUrlMedium();
// } else {
// uri = responsePlayUrl.getAudioUrlLow();
// }
// CommonUtils.LogMsg("------createMediaSource----------="+mediaItem.mediaId+"---------"+uri);
// ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
// .createMediaSource(MediaItem.fromUri(uri));
// player.setMediaSource(mediaSource);
// player.prepare();
//
// }
//
//
// }
// });
// return new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
// .createMediaSource(MediaItem.fromUri(responsePlayUrl.getAudioUrlMedium()));
// 可以在这里根据 mediaItem ID 动态生成新的 URI
String updatedUri = "https://rr1---sn-tt1e7nlz.googlevideo.com/videoplayback?expire=1727628605&ei=3TD5ZuWFEe-yzN0P27WuqQ4&ip=146.19.167.8&id=o-ANGM0PjEvsfYH7TmYV_DFuD-65tipJeeLe2URDOk90sL&itag=140&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&mh=xj&mm=31%2C29&mn=sn-tt1e7nlz%2Csn-vgqsknsk&ms=au%2Crdu&mv=m&mvi=1&pl=24&pcm2=no&gcr=us&initcwndbps=7610000&vprv=1&svpuc=1&mime=audio%2Fmp4&rqh=1&gir=yes&clen=5440168&dur=335.973&lmt=1709326903801285&mt=1727606690&fvip=5&keepalive=yes&fexp=51299152&c=ANDROID_MUSIC&txp=2318224&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cpcm2%2Cgcr%2Cvprv%2Csvpuc%2Cmime%2Crqh%2Cgir%2Cclen%2Cdur%2Clmt&sig=AJfQdSswRQIhALmM_S8Cmagr60muB3wDOby0OdcjF-x6f7TcEenixH0KAiAnR0-hmA03MeVzSg2wi5ncJ4Ve5FFlpZnlSoRNGWgGhQ%3D%3D&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=ABPmVW0wRQIhAPv5slfEnf8_E7o6yjEkussQ6JIFFaSY6QtP9HXncTTcAiAjlhMa71t76Wu1R1rcmsHoO6pyxjhGYouio4D0deJqEA%3D%3D";
Uri updateUri = null;
MediaItem.Builder builder = mediaItem.buildUpon();
if (mediaItem.localConfiguration != null) {
updateUri = mediaItem.localConfiguration.uri;
builder.setUri(updateUri);
CommonUtils.LogErrorMsg("----updateUri=成功 builder="+mediaItem.mediaId+"--updateUri="+updateUri);
}else {
CommonUtils.LogErrorMsg("----updateUri=null builder="+mediaItem.mediaId);
}
return mediaSourceFactory.createMediaSource(builder.build());
}
// @UnstableApi
// @Override
// public DataSource createDataSource() {
//
//
//
//
//// RetrofitManager.getInstance().getPlayUrl(mediaItem.mediaId, new RequestListener<ResponseBody>() {
////
//// @Override
//// public void onFail(String errorMsg) {
////
//// }
////
//// @Override
//// public void onSuccess(ResponseBody data) {
//// JSONObject jsonObject = CommonUtils.toJsonObject(data);
//// if (jsonObject != null) {
//// ResponsePlayUrl responsePlayUrl = JsonHelper.ResolvePlayUrlJson(jsonObject);
//// if (responsePlayUrl == null) {
//// // TODO: 2024/9/27
//// return;
//// }
//// String uri = "";
//// if (responsePlayUrl.getAudioUrlMedium() != null) {
//// uri = responsePlayUrl.getAudioUrlMedium();
//// } else {
//// uri = responsePlayUrl.getAudioUrlLow();
//// }
//// CommonUtils.LogMsg("------createMediaSource----------="+mediaItem.mediaId+"---------"+uri);
//// ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
//// .createMediaSource(MediaItem.fromUri(uri));
//// player.setMediaSource(mediaSource);
//// player.prepare();
////
//// }
////
////
//// }
//// });
// return null;
// }
}

View File

@ -24,6 +24,7 @@ import com.hi.music.player.javabean.response.ResponsePlayListInfo;
import com.hi.music.player.javabean.response.ResponsePlayUrl; import com.hi.music.player.javabean.response.ResponsePlayUrl;
import com.hi.music.player.network.RetrofitManager; import com.hi.music.player.network.RetrofitManager;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -61,7 +62,6 @@ public class MyMediaControllerManager {
// playerView.setPlayer(controllerFuture.get()); // playerView.setPlayer(controllerFuture.get());
try { try {
mediaController = controllerFuture.get(); mediaController = controllerFuture.get();
statusListener.onMediaControllerComplete(true); statusListener.onMediaControllerComplete(true);
CommonUtils.LogMsg("=-----mediaController+" + mediaController); CommonUtils.LogMsg("=-----mediaController+" + mediaController);
} catch (ExecutionException | InterruptedException e) { } catch (ExecutionException | InterruptedException e) {
@ -85,7 +85,7 @@ public class MyMediaControllerManager {
@Override @Override
public void onMediaItemTransition(@Nullable MediaItem mediaItem, int reason) { public void onMediaItemTransition(@Nullable MediaItem mediaItem, int reason) {
//当前媒体项发生变化切歌 //当前媒体项发生变化切歌
if(mediaItem == null){ if (mediaItem == null) {
//第二次进入PlayActitivity 调用resetPlayList这里为null //第二次进入PlayActitivity 调用resetPlayList这里为null
return; return;
} }
@ -98,19 +98,16 @@ public class MyMediaControllerManager {
if (isPlaying) { if (isPlaying) {
mListener.onPlayStatus(MyValue.PLAY_STATUS_CODE_PLAYING); mListener.onPlayStatus(MyValue.PLAY_STATUS_CODE_PLAYING);
// TODO: 2024/9/26 自动播放完成切歌到下一首播放没有触发这里请求下一首 // TODO: 2024/9/26 自动播放完成切歌到下一首播放没有触发这里请求下一首
// 播放器开始播放 if (mediaController.hasNextMediaItem()) {
MediaItem currentItem = mediaController.getCurrentMediaItem(); MediaItem mediaItemAt = mediaController.getMediaItemAt(mediaController.getNextMediaItemIndex());
int currentMediaItemIndex = mediaController.getCurrentMediaItemIndex(); if (!CommonUtils.hasValidUri(mediaItemAt)) {
if (currentMediaItemIndex < playList.size() - 1) {
//代表有下一首
if (!mediaController.hasNextMediaItem()) {
//没有更新下一首的uri
CommonUtils.LogMsg("----0000000000-请求下一首的uri" + mediaController.getMediaItemCount()); CommonUtils.LogMsg("----0000000000-请求下一首的uri" + mediaController.getMediaItemCount());
int nextIndex = currentMediaItemIndex + 1; int nextIndex = mediaController.getNextMediaItemIndex();
mListener.onRequestNextUri(playList.get(nextIndex).getVideoId(), nextIndex,false); mListener.onRequestNextUri(mediaController.getMediaItemAt(nextIndex).mediaId, nextIndex, false);
} }
} }
} else { } else {
// 播放器暂停或停止 // 播放器暂停或停止
mListener.onPlayStatus(MyValue.PLAY_STATUS_CODE_PAUSE); mListener.onPlayStatus(MyValue.PLAY_STATUS_CODE_PAUSE);
@ -119,7 +116,6 @@ public class MyMediaControllerManager {
@Override @Override
public void onPlaybackStateChanged(int playbackState) { public void onPlaybackStateChanged(int playbackState) {
CommonUtils.LogMsg("----playbackState" + playbackState + "------------" + mediaController.getMediaItemCount());
mListener.onPlayStatus(playbackState); mListener.onPlayStatus(playbackState);
} }
@ -149,56 +145,54 @@ public class MyMediaControllerManager {
} }
// /** // /**
// * 更新播放列表中的音频url // * 更新播放列表中的音频url
// * // *
// * @param playUrl // * @param playUrl
// */ // */
// public void UpdateAudioUrl(ResponsePlayUrl playUrl) { public void UpdateAudioUrl(ResponsePlayUrl playUrl, int index) {
// CommonUtils.LogMsg("-------------更新播放列表中的音频url= index=" + index);
// CommonUtils.LogMsg("-------------更新播放列表中的音频 mediaController.getMediaItemCount()=" + mediaController.getMediaItemCount()); for (int i = 0; i < mediaController.getMediaItemCount(); i++) {
// for (int i = 0; i < mediaController.getMediaItemCount(); i++) { MediaItem mediaItemAt = mediaController.getMediaItemAt(i);
// MediaItem mediaItemAt = mediaController.getMediaItemAt(i); if (mediaItemAt.mediaId.equals(playUrl.getVideoId())) {
// if (mediaItemAt.mediaId.equals(playUrl.getVideoId())) {
// MediaItem.Builder builder = mediaItemAt.buildUpon();
// MediaItem.Builder builder = mediaItemAt.buildUpon(); builder.setMediaId(playUrl.getVideoId());
//// mediaController.removeMediaItem(i); if (playUrl.getAudioUrlMedium() != null) {
//// MediaItem.Builder builder = new MediaItem.Builder(); builder.setUri(playUrl.getAudioUrlMedium());
// builder.setMediaId(playUrl.getVideoId()); } else {
// if (playUrl.getAudioUrlMedium() != null) { builder.setUri(playUrl.getAudioUrlLow());
// builder.setUri(playUrl.getAudioUrlMedium()); }
// } else { CharSequence title = mediaController.getMediaItemAt(i).mediaMetadata.title;
// builder.setUri(playUrl.getAudioUrlLow()); CommonUtils.LogMsg("-------------更新播放列表中的音频url= i=" + i + "---id=" + playUrl.getVideoId() + "----mediaController.size=" + mediaController.getMediaItemCount());
// } mediaController.replaceMediaItem(i, builder.build());
// mediaController.replaceMediaItem(i, builder.build()); break;
// CharSequence title = mediaController.getMediaItemAt(i).mediaMetadata.title; }
// CommonUtils.LogMsg("-------------更新播放列表中的音频url= i=" + i + "---title=" + title + "----mediaController.size=" + mediaController.getMediaItemCount() + "---" + mediaController); }
// break; }
// }
// }
// }
public void setPlayList(List<ResponsePlayListInfo> playList) { public void setPlayList(List<ResponsePlayListInfo> playList) {
this.playList = playList; this.playList = playList;
addMusicPlayList(playList);
} }
public List<ResponsePlayListInfo> getPlayList() { public List<ResponsePlayListInfo> getPlayList() {
return playList; return playList;
} }
public void resetPlayList(){ public void resetPlayList() {
mediaController.clearMediaItems(); mediaController.clearMediaItems();
} }
/** /**
* 添加播放列表不带音频url * 添加播放列表不带音频url
* 注意没有更新有效uri的不会被实际添加到mediaController * 注意没有setUri的不会被实际添加到mediaController,
* *
* @param playUrl * @param playUrl
*/ */
@OptIn(markerClass = UnstableApi.class) @OptIn(markerClass = UnstableApi.class)
public void addMusicToPlayList(ResponsePlayUrl playUrl, int playListIndex) { public void addMusicToPlayList(ResponsePlayUrl playUrl, int playListIndex) {
if (playListIndex < playList.size()&& playListIndex>=mediaController.getMediaItemCount()) { if (playListIndex < playList.size() && playListIndex >= mediaController.getMediaItemCount()) {
ResponsePlayListInfo listInfo = playList.get(playListIndex); ResponsePlayListInfo listInfo = playList.get(playListIndex);
if (listInfo.getVideoId().equals(playUrl.getVideoId())) { if (listInfo.getVideoId().equals(playUrl.getVideoId())) {
MediaItem.Builder builder = new MediaItem.Builder(); MediaItem.Builder builder = new MediaItem.Builder();
@ -214,7 +208,6 @@ public class MyMediaControllerManager {
MediaMetadata.Builder MediaMetadata_builder = new MediaMetadata.Builder(); MediaMetadata.Builder MediaMetadata_builder = new MediaMetadata.Builder();
MediaMetadata_builder.setArtist(listInfo.getSingerName()); MediaMetadata_builder.setArtist(listInfo.getSingerName());
/** /**
* 这里使用setDescription保存歌曲时长的分秒字符串 * 这里使用setDescription保存歌曲时长的分秒字符串
*/ */
@ -228,49 +221,53 @@ public class MyMediaControllerManager {
// MediaMetadata_builder.setRecordingYear(Integer.parseInt(playInfo.getYear())); // MediaMetadata_builder.setRecordingYear(Integer.parseInt(playInfo.getYear()));
builder.setMediaMetadata(MediaMetadata_builder.build()); builder.setMediaMetadata(MediaMetadata_builder.build());
mediaController.addMediaItem(builder.build()); mediaController.addMediaItem(builder.build());
} }
} }
} }
// /** /**
// * 添加播放列表不带音频url * 添加播放列表不带音频url
// * 注意没有更新有效uri的不会被实际添加到mediaController * 注意没有setUri的不会被实际添加到mediaController(mediaController.getMediaItemCount())
// * * 这里setUri 一个占位
// * @param listInfo *
// */ * @param listInfo
// @OptIn(markerClass = UnstableApi.class) */
// public void addMusicPlayList(List<ResponsePlayListInfo> listInfo) { @OptIn(markerClass = UnstableApi.class)
// playList = listInfo; public void addMusicPlayList(List<ResponsePlayListInfo> listInfo) {
// List<MediaItem> mediaItems = new ArrayList<>(); playList = listInfo;
// for (int i = 0; i < listInfo.size(); i++) { List<MediaItem> mediaItems = new ArrayList<>();
// ResponsePlayListInfo playInfo = listInfo.get(i); for (int i = 0; i < listInfo.size(); i++) {
// ResponsePlayListInfo playInfo = listInfo.get(i);
// MediaItem.Builder builder = new MediaItem.Builder();
// MediaItem.Builder builder = new MediaItem.Builder();
// //唯一标识符
// builder.setMediaId(playInfo.getVideoId()); //唯一标识符
// builder.setMediaId(playInfo.getVideoId());
// MediaMetadata.Builder MediaMetadata_builder = new MediaMetadata.Builder(); builder.setUri("-------test-----");
// MediaMetadata.Builder MediaMetadata_builder = new MediaMetadata.Builder();
// MediaMetadata_builder.setArtist(playInfo.getSingerName());
// MediaMetadata_builder.setDurationMs(playInfo.getDurationMs()); MediaMetadata_builder.setArtist(playInfo.getSingerName());
//// MediaMetadata_builder.setArtworkUri(Uri.parse(playInfo.getCovert())); MediaMetadata_builder.setDescription(playInfo.getDuration());
// MediaMetadata_builder.setArtworkUri(Uri.parse("https://t7.baidu.com/it/u=2604797219,1573897854&fm=193&f=GIF")); MediaMetadata_builder.setDurationMs(playInfo.getDurationMs());
// MediaMetadata_builder.setTitle(playInfo.getSongTitle()); MediaMetadata_builder.setArtworkUri(Uri.parse(playInfo.getCovert()));
// MediaMetadata_builder.setTitle(playInfo.getSongTitle());
// CommonUtils.LogMsg("----------添加播放列表 i=" + i + "---" + playInfo.getSongTitle() + "-------VideoId=" + playInfo.getVideoId());
//// MediaMetadata_builder.setRecordingYear(Integer.parseInt(playInfo.getYear())); CommonUtils.LogMsg("----------添加播放列表 i=" + i + "---" + playInfo.getSongTitle() + "-------VideoId=" + playInfo.getVideoId());
// builder.setMediaMetadata(MediaMetadata_builder.build()); // MediaMetadata_builder.setRecordingYear(Integer.parseInt(playInfo.getYear()));
// mediaController.addMediaItem(builder.build()); builder.setMediaMetadata(MediaMetadata_builder.build());
//// mediaItems.add(builder.build()); mediaController.addMediaItem(builder.build());
// }
//// mediaController.setMediaItems(mediaItems); }
// }
}
public void play() { public void play() {
if (!mediaController.isPlaying()) { if (!mediaController.isPlaying()) {
CommonUtils.LogMsg("-----------prepare");
mediaController.prepare(); mediaController.prepare();
mediaController.play(); mediaController.play();
} }
} }
@ -279,21 +276,32 @@ public class MyMediaControllerManager {
if (mediaController.isPlaying()) if (mediaController.isPlaying())
mediaController.pause(); mediaController.pause();
} }
public void stop() { public void stop() {
if (mediaController.isPlaying()) if (mediaController.isPlaying())
mediaController.stop(); mediaController.stop();
} }
public void playNext() { public void playNext() {
if (mediaController.hasNextMediaItem()) { if (mediaController.hasNextMediaItem()) {
mediaController.seekToNextMediaItem(); int nextMediaItemIndex = mediaController.getNextMediaItemIndex();
} else { MediaItem mediaItemAt = mediaController.getMediaItemAt(nextMediaItemIndex);
int currentMediaItemIndex = mediaController.getCurrentMediaItemIndex(); boolean b = CommonUtils.hasValidUri(mediaItemAt);
if (currentMediaItemIndex < playList.size() - 1) { if (b) {
//应该有下一首可能是歌曲url请求失败需要重新请求 mediaController.seekToNextMediaItem();
int nextIndex = currentMediaItemIndex + 1; return;
mListener.onRequestNextUri(playList.get(nextIndex).getVideoId(), nextIndex,true);
CommonUtils.LogMsg("-------------应该有下一首可能是歌曲url请求失败需要重新请求");
} }
CommonUtils.LogMsg("-------------有下一首但是歌曲url请求失败需要重新请求");
mListener.onRequestNextUri(mediaController.getMediaItemAt(nextMediaItemIndex).mediaId, nextMediaItemIndex, true);
} else {
// int currentMediaItemIndex = mediaController.getCurrentMediaItemIndex();
// if (currentMediaItemIndex < playList.size() - 1) {
// //应该有下一首可能是歌曲url请求失败需要重新请求
// int nextIndex = currentMediaItemIndex + 1;
// mListener.onRequestNextUri(playList.get(nextIndex).getVideoId(), nextIndex, true);
// CommonUtils.LogMsg("-------------应该有下一首可能是歌曲url请求失败需要重新请求");
// }
} }
} }
@ -305,4 +313,29 @@ public class MyMediaControllerManager {
mediaController.play(); mediaController.play();
} }
} }
/**
* 播放指定播放列表位置的歌曲
*
* @param index
*/
public void playPositionMusic(int index) {
if (index >= mediaController.getMediaItemCount()) {
CommonUtils.LogErrorMsg("-------------数组越界");
return;
}
stop();
mediaController.prepare();
mediaController.seekTo(index);
MediaItem mediaItemAt = mediaController.getMediaItemAt(index);
boolean b = CommonUtils.hasValidUri(mediaItemAt);
if (!b) {
CommonUtils.LogMsg("-------------播放指定播放列表位置的歌曲,需要重新请求");
mListener.onRequestNextUri(mediaItemAt.mediaId, index, true);
}
}
} }

View File

@ -5,48 +5,59 @@ import android.content.Intent;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.OptIn; import androidx.annotation.OptIn;
import androidx.media3.common.AudioAttributes;
import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaMetadata;
import androidx.media3.common.Player; import androidx.media3.common.Player;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.database.StandaloneDatabaseProvider;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DataSpec;
import androidx.media3.datasource.DefaultDataSource;
import androidx.media3.datasource.DefaultHttpDataSource;
import androidx.media3.datasource.ResolvingDataSource;
import androidx.media3.datasource.cache.CacheDataSource;
import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor;
import androidx.media3.datasource.cache.SimpleCache;
import androidx.media3.exoplayer.DefaultLoadControl;
import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory; import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.extractor.ExtractorsFactory;
import androidx.media3.extractor.mkv.MatroskaExtractor;
import androidx.media3.session.MediaSession; import androidx.media3.session.MediaSession;
import androidx.media3.session.MediaSessionService; import androidx.media3.session.MediaSessionService;
import com.google.common.util.concurrent.ListenableFuture; import com.hi.music.player.MusicApplication;
import com.hi.music.player.R;
import com.hi.music.player.helper.CommonUtils; import com.hi.music.player.helper.CommonUtils;
import com.hi.music.player.javabean.response.ResponsePlayUrl;
import java.util.ArrayList; import java.io.File;
import java.util.List; import java.io.IOException;
public class PlaybackService extends MediaSessionService { public class PlaybackService extends MediaSessionService {
private MediaSession mediaSession = null; private MediaSession mediaSession = null;
private ExoPlayer player; private ExoPlayer player;
@OptIn(markerClass = UnstableApi.class)
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
player = new ExoPlayer.Builder(this).build();
DynamicMediaSourceFactory customMediaSourceFactory = new DynamicMediaSourceFactory(new DefaultMediaSourceFactory(new DefaultHttpDataSource.Factory()));
DefaultMediaSourceFactory defaultMediaSourceFactory1 = new DefaultMediaSourceFactory(getUrlFactory());
// 创建 DefaultLoadControl配置缓冲参数
DefaultLoadControl loadControl = new DefaultLoadControl.Builder()
.setBufferDurationsMs(10000, // minBufferMs: 播放前的最小缓冲时间毫秒
60000, // maxBufferMs: 最大缓冲时间毫秒
10000, // bufferForPlaybackMs: 播放时的目标缓冲时间毫秒
5000) // bufferForPlaybackAfterRebufferMs: 重新缓冲后的缓冲时间毫秒)
.build();
player = new ExoPlayer.Builder(this)
// .setMediaSourceFactory(customMediaSourceFactory)
// .setLoadControl(loadControl)
.build();
mediaSession = new MediaSession.Builder(this, player) mediaSession = new MediaSession.Builder(this, player)
.setCallback(new MediaSession.Callback() {
@Override
public ListenableFuture<List<MediaItem>> onAddMediaItems(MediaSession mediaSession, MediaSession.ControllerInfo controller, List<MediaItem> mediaItems) {
CommonUtils.LogMsg("--------实际添加的媒体项="+mediaItems.size()+"----"+mediaSession.getPlayer().getMediaItemCount());
return MediaSession.Callback.super.onAddMediaItems(mediaSession, controller, mediaItems);
}
})
.build(); .build();
// player = new ExoPlayer.Builder(this) // player = new ExoPlayer.Builder(this)
@ -69,12 +80,39 @@ public class PlaybackService extends MediaSessionService {
// .build(); // .build();
}
@OptIn(markerClass = UnstableApi.class)
private DataSource.Factory getUrlFactory() {
CommonUtils.LogMsg("--------getUrlFactory");
return new ResolvingDataSource.Factory(getCacheDataSource(), new ResolvingDataSource.Resolver() {
@Override
public DataSpec resolveDataSpec(DataSpec dataSpec) {
CommonUtils.LogMsg("--------resolveDataSpec=" + dataSpec.key);
return null;
}
});
} }
@OptIn(markerClass = UnstableApi.class)
private CacheDataSource.Factory getCacheDataSource() {
// 1. 创建缓存对象
SimpleCache simpleCache = new SimpleCache(
new File(MusicApplication.myApplication.getCacheDir(), "media3_cache"), // 设置缓存目录
new LeastRecentlyUsedCacheEvictor(100 * 1024 * 1024), // 设置最大缓存大小例如 100MB
new StandaloneDatabaseProvider(MusicApplication.myApplication));
// 2. 创建 DataSource.Factory用于加载媒体资源
DataSource.Factory dataSourceFactory = new DefaultDataSource.Factory(MusicApplication.myApplication);
// 3. 创建 CacheDataSource.Factory包含缓存功能
return new CacheDataSource.Factory()
.setCache(simpleCache)
.setUpstreamDataSourceFactory(dataSourceFactory) // 用于从网络加载的工厂
.setCacheWriteDataSinkFactory(null); // 默认写入缓存
}
@Nullable @Nullable
@Override @Override

View File

@ -0,0 +1,73 @@
package com.hi.music.player.media3;
import androidx.media3.common.MediaItem;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.datasource.DataSource;
import androidx.media3.exoplayer.drm.DrmSessionManagerProvider;
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
import androidx.media3.exoplayer.source.MediaSource;
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;
import com.hi.music.player.helper.CommonUtils;
public class testSourceFactory implements DataSource.Factory {
// private final CacheDataSource.Factory cacheDataSourceFactory;
// private final ExoPlayer player;
private DefaultMediaSourceFactory mediaSourceFactory;
// public DynamicMediaSourceFactory(DefaultMediaSourceFactory factory,CacheDataSource.Factory cacheDataSourceFactory, ExoPlayer exoPlayer) {
// this.cacheDataSourceFactory = cacheDataSourceFactory;
// this.player = exoPlayer;
// this.mediaSourceFactory = factory;
// }
public testSourceFactory(DefaultMediaSourceFactory factory) {
this.mediaSourceFactory = factory;
}
@UnstableApi
@Override
public DataSource createDataSource() {
// RetrofitManager.getInstance().getPlayUrl(mediaItem.mediaId, new RequestListener<ResponseBody>() {
//
// @Override
// public void onFail(String errorMsg) {
//
// }
//
// @Override
// public void onSuccess(ResponseBody data) {
// JSONObject jsonObject = CommonUtils.toJsonObject(data);
// if (jsonObject != null) {
// ResponsePlayUrl responsePlayUrl = JsonHelper.ResolvePlayUrlJson(jsonObject);
// if (responsePlayUrl == null) {
// // TODO: 2024/9/27
// return;
// }
// String uri = "";
// if (responsePlayUrl.getAudioUrlMedium() != null) {
// uri = responsePlayUrl.getAudioUrlMedium();
// } else {
// uri = responsePlayUrl.getAudioUrlLow();
// }
// CommonUtils.LogMsg("------createMediaSource----------="+mediaItem.mediaId+"---------"+uri);
// ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
// .createMediaSource(MediaItem.fromUri(uri));
// player.setMediaSource(mediaSource);
// player.prepare();
//
// }
//
//
// }
// });
return null;
}
}

View File

@ -244,7 +244,6 @@ public class JsonHelper {
if (mimeType.contains("audio/mp4")) { if (mimeType.contains("audio/mp4")) {
String url = jsonIndex.getString("url"); String url = jsonIndex.getString("url");
boolean audioQuality1 = jsonIndex.has("audioQuality"); boolean audioQuality1 = jsonIndex.has("audioQuality");
CommonUtils.LogMsg("------------itag="+itag+"---------audioQuality1="+audioQuality1);
if (jsonIndex.has("audioQuality")) { if (jsonIndex.has("audioQuality")) {
String audioQuality = jsonIndex.getString("audioQuality"); String audioQuality = jsonIndex.getString("audioQuality");
if (audioQuality.equals("AUDIO_QUALITY_MEDIUM")) { if (audioQuality.equals("AUDIO_QUALITY_MEDIUM")) {

View File

@ -15,12 +15,12 @@ public class ObserverWrapper<T> implements Observer<T> {
@Override @Override
public void onSubscribe(Disposable d) { public void onSubscribe(Disposable d) {
CommonUtils.LogMsg("----------onSubscribe");
} }
@Override @Override
public void onNext(T t) { public void onNext(T t) {
CommonUtils.LogMsg("----------onNext");
requestListener.onSuccess(t); requestListener.onSuccess(t);
} }
@ -32,7 +32,7 @@ public class ObserverWrapper<T> implements Observer<T> {
@Override @Override
public void onComplete() { public void onComplete() {
CommonUtils.LogMsg("----------onComplete");
} }
} }

View File

@ -57,8 +57,6 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
//接口返回的播放列表(没有音频数据) //接口返回的播放列表(没有音频数据)
private List<ResponsePlayListInfo> mPlayList; private List<ResponsePlayListInfo> mPlayList;
//播放列对应的音频数据
private List<ResponsePlayUrl> mPlayUrls;
private ResponsePlayUrl mCurPlayInfo; private ResponsePlayUrl mCurPlayInfo;
private ResponsePlayListInfo musicInfo; private ResponsePlayListInfo musicInfo;
@ -66,12 +64,14 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
private Runnable mRunnable; private Runnable mRunnable;
private MyMediaControllerManager mediaControllerManager; private MyMediaControllerManager mediaControllerManager;
private AdapterPlayList adapterPlayList;
//播放列表ui初始化 //播放列表ui初始化
private boolean initPlayList = false; private boolean initPlayList = false;
private GradientDrawable gradientDrawable; private GradientDrawable gradientDrawable;
private int lighterColor,darkerColor; private int lighterColor, darkerColor;
@Override @Override
@ -137,12 +137,12 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
mediaControllerManager = MyMediaControllerManager.getInstance(); mediaControllerManager = MyMediaControllerManager.getInstance();
String videoId = responseSingle.getVideoId(); String videoId = responseSingle.getVideoId();
MediaItem currentMediaItem = mediaControllerManager.getMediaController().getCurrentMediaItem(); MediaItem currentMediaItem = mediaControllerManager.getMediaController().getCurrentMediaItem();
if(currentMediaItem != null){ if (currentMediaItem != null) {
if(currentMediaItem.mediaId.equals(videoId)){ if (currentMediaItem.mediaId.equals(videoId)) {
// TODO: 2024/9/27 正在播放当前歌曲又点进来 // TODO: 2024/9/27 正在播放当前歌曲又点进来
// mediaControllerManager.getMediaController().seekTo(0); // mediaControllerManager.getMediaController().seekTo(0);
} }
if(mediaControllerManager.getMediaController().isPlaying()){ if (mediaControllerManager.getMediaController().isPlaying()) {
mediaControllerManager.stop(); mediaControllerManager.stop();
} }
mediaControllerManager.resetPlayList(); mediaControllerManager.resetPlayList();
@ -170,6 +170,7 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
break; break;
case Player.STATE_ENDED: case Player.STATE_ENDED:
//播放完成
vb.btnPlay.setSelected(false); vb.btnPlay.setSelected(false);
CommonUtils.LogMsg("-------------playStatus=STATE_ENDED 播放完成"); CommonUtils.LogMsg("-------------playStatus=STATE_ENDED 播放完成");
mHandler.removeCallbacks(mRunnable); // 停止更新 mHandler.removeCallbacks(mRunnable); // 停止更新
@ -199,7 +200,7 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
@Override @Override
public void onChangeMusic(MediaItem mediaItem) { public void onChangeMusic(MediaItem mediaItem) {
CommonUtils.LogMsg("111111111-------22222---"+mediaItem.mediaMetadata.title +"---id="+mediaItem.mediaId); CommonUtils.LogMsg("歌曲切换-" + mediaItem.mediaMetadata.title + "---id=" + mediaItem.mediaId);
loadInfo(mediaItem); loadInfo(mediaItem);
} }
@ -250,7 +251,7 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
private void loadInfo(MediaItem mediaItem) { private void loadInfo(MediaItem mediaItem) {
MediaMetadata mediaMetadata = mediaItem.mediaMetadata; MediaMetadata mediaMetadata = mediaItem.mediaMetadata;
CommonUtils.LogMsg("--------------加载当前播放歌曲信息 " + mediaMetadata.description); CommonUtils.LogMsg("--------------加载当前播放歌曲信息 ");
if (mediaMetadata.artworkUri != null) { if (mediaMetadata.artworkUri != null) {
loadCovert(mediaMetadata.artworkUri.toString()); loadCovert(mediaMetadata.artworkUri.toString());
} }
@ -263,7 +264,9 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
vb.playProgress.setMax((int) durationMs); vb.playProgress.setMax((int) durationMs);
vb.progressBarBuffer.setMax((int) durationMs); vb.progressBarBuffer.setMax((int) durationMs);
} }
if (vb.layoutPlayList.linearLayout.getVisibility() == View.VISIBLE) {
updatePlayListUi();
}
} }
@ -289,14 +292,19 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
if (color == -1) { if (color == -1) {
return; return;
} }
lighterColor = CommonUtils.adjustBrightness(color, 1.2f); // 比原始颜色亮 20% lighterColor = CommonUtils.adjustBrightness(color, 1.2f); // 比原始颜色亮 20%
darkerColor = CommonUtils.adjustBrightness(color, 0.8f); // 比原始颜色暗 20% darkerColor = CommonUtils.adjustBrightness(color, 0.8f); // 比原始颜色暗 20%
gradientDrawable = new GradientDrawable( gradientDrawable = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM, GradientDrawable.Orientation.TOP_BOTTOM,
new int[]{lighterColor, darkerColor} // 浅到深渐变 new int[]{lighterColor, darkerColor} // 浅到深渐变
); );
vb.rootLayout.setBackground(gradientDrawable); vb.rootLayout.setBackground(gradientDrawable);
if (vb.layoutPlayList.linearLayout.getVisibility() == View.VISIBLE) {
updatePlayListColor();
}
} }
}); });
@ -355,6 +363,9 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
} else { } else {
mediaControllerManager.pause(); mediaControllerManager.pause();
} }
if(adapterPlayList!= null){
adapterPlayList.updateCurMusicAnimation();
}
} }
} }
@ -374,52 +385,14 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
if (!initPlayList) { if (!initPlayList) {
List<ResponsePlayListInfo> playList = mediaControllerManager.getPlayList(); List<ResponsePlayListInfo> playList = mediaControllerManager.getPlayList();
AdapterPlayList adapterPlayList = new AdapterPlayList(); adapterPlayList = new AdapterPlayList();
vb.layoutPlayList.recyclerList.setLayoutManager(new LinearLayoutManager(MusicApplication.myApplication)); vb.layoutPlayList.recyclerList.setLayoutManager(new LinearLayoutManager(MusicApplication.myApplication));
adapterPlayList.addData(playList); adapterPlayList.addData(playList);
vb.layoutPlayList.recyclerList.setAdapter(adapterPlayList); vb.layoutPlayList.recyclerList.setAdapter(adapterPlayList);
vb.layoutPlayList.imPlay.setOnClickListener(this); vb.layoutPlayList.imPlay.setOnClickListener(this);
initPlayList = true; initPlayList = true;
} }
updatePlayListUi();
MediaItem currentMediaItem = mediaControllerManager.getMediaController().getCurrentMediaItem();
if (currentMediaItem != null) {
Uri artworkUri = currentMediaItem.mediaMetadata.artworkUri;
vb.layoutPlayList.topSongName.setText(currentMediaItem.mediaMetadata.title);
vb.layoutPlayList.topSingerName.setText(currentMediaItem.mediaMetadata.artist);
vb.layoutPlayList.topLayout.setBackgroundColor(darkerColor);
GradientDrawable gradientDrawable = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,
new int[]{darkerColor, darkerColor}
);
vb.rootLayout.setBackground(gradientDrawable);
Drawable newDrawable = CommonUtils.getNewDrawable(lighterColor, 24f, 24f, 0, 0);
vb.layoutPlayList.listLayout.setBackground(newDrawable);
Glide.with(MusicApplication.myApplication)
.asDrawable()
.apply(RequestOptions.bitmapTransform(new RoundedCorners(CommonUtils.dpToPx(10))))
.load(artworkUri)
.placeholder(R.mipmap.ic_launcher)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
CommonUtils.LogMsg(e.getMessage());
return false;
}
@OptIn(markerClass = UnstableApi.class)
@Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
return false;
}
})
.into(vb.layoutPlayList.topIm);
}
vb.layoutPlayList.imPlay.setSelected(mediaControllerManager.getMediaController().isPlaying());
} else { } else {
@ -434,6 +407,56 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
} }
/**
* 更新播放列表的显示
*/
private void updatePlayListUi() {
CommonUtils.LogMsg("----------更新播放列表的显示");
MediaItem currentMediaItem = mediaControllerManager.getMediaController().getCurrentMediaItem();
if (currentMediaItem != null) {
if (adapterPlayList != null) {
adapterPlayList.setCurVideId(currentMediaItem.mediaId);
}
Uri artworkUri = currentMediaItem.mediaMetadata.artworkUri;
vb.layoutPlayList.topSongName.setText(currentMediaItem.mediaMetadata.title);
vb.layoutPlayList.topSingerName.setText(currentMediaItem.mediaMetadata.artist);
updatePlayListColor();
Glide.with(MusicApplication.myApplication)
.asDrawable()
.apply(RequestOptions.bitmapTransform(new RoundedCorners(CommonUtils.dpToPx(10))))
.load(artworkUri)
.placeholder(R.mipmap.ic_launcher)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
CommonUtils.LogMsg(e.getMessage());
return false;
}
@OptIn(markerClass = UnstableApi.class)
@Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
return false;
}
})
.into(vb.layoutPlayList.topIm);
}
vb.layoutPlayList.imPlay.setSelected(mediaControllerManager.getMediaController().isPlaying());
}
private void updatePlayListColor() {
vb.layoutPlayList.topLayout.setBackgroundColor(darkerColor);
GradientDrawable gradientDrawable = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,
new int[]{darkerColor, darkerColor}
);
vb.rootLayout.setBackground(gradientDrawable);
Drawable newDrawable = CommonUtils.getNewDrawable(lighterColor, 24f, 24f, 0, 0);
vb.layoutPlayList.listLayout.setBackground(newDrawable);
}
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
@ -443,7 +466,7 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements S
@Override @Override
public void onBackPressed() { public void onBackPressed() {
if (vb.layoutPlayList.linearLayout.getVisibility()==View.VISIBLE) { if (vb.layoutPlayList.linearLayout.getVisibility() == View.VISIBLE) {
initShowPlayList(false); initShowPlayList(false);
} else { } else {
super.onBackPressed(); // 调用系统默认的返回行为 super.onBackPressed(); // 调用系统默认的返回行为

View File

@ -37,9 +37,6 @@ public class VMPlay extends ViewModel {
String videoId = responseSingle.getVideoId(); String videoId = responseSingle.getVideoId();
String params = responseSingle.getParams(); String params = responseSingle.getParams();
String musicVideoType = responseSingle.getMusicVideoType(); String musicVideoType = responseSingle.getMusicVideoType();
CommonUtils.LogMsg("111111111-------0000---"+responseSingle.getSongTitle() +"---id="+videoId);
RetrofitManager.getInstance().getPlayList(params, playlistId, videoId, musicVideoType, new RequestListener<ResponseBody>() { RetrofitManager.getInstance().getPlayList(params, playlistId, videoId, musicVideoType, new RequestListener<ResponseBody>() {
@Override @Override
@ -54,7 +51,6 @@ public class VMPlay extends ViewModel {
List<ResponsePlayListInfo> responsePlayListInfos = JsonHelper.ResolvePlayListJson(jsonObject); List<ResponsePlayListInfo> responsePlayListInfos = JsonHelper.ResolvePlayListJson(jsonObject);
MyMediaControllerManager.getInstance().setPlayList(responsePlayListInfos); MyMediaControllerManager.getInstance().setPlayList(responsePlayListInfos);
_playList.setValue(responsePlayListInfos); _playList.setValue(responsePlayListInfos);
CommonUtils.LogMsg("111111111-------1111----"+responsePlayListInfos.get(0).getSongTitle() +"---id="+responsePlayListInfos.get(0).getVideoId());
getPlayUrl(responseSingle.getVideoId(),0,true); getPlayUrl(responseSingle.getVideoId(),0,true);
} else { } else {
_playList.setValue(null); _playList.setValue(null);
@ -83,7 +79,8 @@ public class VMPlay extends ViewModel {
// TODO: 2024/9/27 // TODO: 2024/9/27
return; return;
} }
MyMediaControllerManager.getInstance().addMusicToPlayList(responsePlayUrl,playListIndex); MyMediaControllerManager.getInstance().UpdateAudioUrl(responsePlayUrl,playListIndex);
// MyMediaControllerManager.getInstance().addMusicToPlayList(responsePlayUrl,playListIndex);
customerUrlInfo.setPlayUrl(responsePlayUrl); customerUrlInfo.setPlayUrl(responsePlayUrl);
customerUrlInfo.setPlayMusicIndex(playListIndex); customerUrlInfo.setPlayMusicIndex(playListIndex);

View File

@ -2,15 +2,15 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:id="@+id/root_layout"
android:background="@color/black" android:background="@color/black"
tools:context=".ui.activity.PlayActivity"> tools:context=".ui.activity.PlayActivity">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:id="@+id/content_layout" android:id="@+id/content_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<ImageView <ImageView
@ -51,16 +51,6 @@
app:show_shuffle_button="true" /> app:show_shuffle_button="true" />
<ProgressBar
android:id="@+id/progressBarLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateTint="@color/white"
app:layout_constraintBottom_toBottomOf="@id/im_covert"
app:layout_constraintLeft_toLeftOf="@id/im_covert"
app:layout_constraintRight_toRightOf="@id/im_covert"
app:layout_constraintTop_toTopOf="@id/im_covert" />
<TextView <TextView
android:id="@+id/tv_song_name" android:id="@+id/tv_song_name"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -186,4 +176,13 @@
<include <include
android:id="@+id/layout_playList" android:id="@+id/layout_playList"
layout="@layout/dialog_play_list" /> layout="@layout/dialog_play_list" />
<ProgressBar
android:id="@+id/progressBarLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
android:indeterminateTint="@color/white" />
</FrameLayout> </FrameLayout>

View File

@ -25,6 +25,7 @@
android:id="@+id/top_im" android:id="@+id/top_im"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="60dp" android:layout_height="60dp"
android:scaleType="fitXY"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:src="@mipmap/ic_launcher" /> android:src="@mipmap/ic_launcher" />
@ -64,11 +65,11 @@
<ImageView <ImageView
android:id="@+id/im_play" android:id="@+id/im_play"
android:layout_width="16dp" android:layout_width="60dp"
android:layout_height="16dp" android:layout_height="60dp"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_centerVertical="true" android:layout_marginEnd="22dp"
android:layout_marginEnd="42dp" android:padding="20dp"
android:src="@drawable/selector_small_play" /> android:src="@drawable/selector_small_play" />
</RelativeLayout> </RelativeLayout>

View File

@ -1,39 +1,38 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dp"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="70dp"
android:id="@+id/item_layout"
android:paddingStart="20dp"> android:paddingStart="20dp">
<ImageView <ImageView
android:layout_width="60dp"
android:id="@+id/im_covert" android:id="@+id/im_covert"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_height="60dp" /> android:src="@mipmap/ic_launcher" />
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottieAnimationView" <com.hi.music.player.customerview.AnimaPlayingView
android:layout_width="0dp" android:id="@+id/view_playing"
android:layout_height="0dp" android:layout_width="wrap_content"
android:layout_gravity="center" android:layout_height="wrap_content"
android:padding="5dp"
android:layout_alignTop="@id/im_covert"
android:layout_alignBottom="@id/im_covert"
android:layout_alignStart="@id/im_covert" android:layout_alignStart="@id/im_covert"
android:layout_alignTop="@id/im_covert"
android:layout_alignEnd="@id/im_covert" android:layout_alignEnd="@id/im_covert"
app:lottie_fileName="music_bounce.json" android:layout_alignBottom="@id/im_covert"
app:lottie_autoPlay="false" android:layout_marginBottom="10dp" />
app:lottie_loop="true"/>
<LinearLayout <LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_toEndOf="@id/im_covert"
android:layout_marginStart="12dp"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginStart="12dp"
android:layout_toEndOf="@id/im_covert"
android:orientation="vertical"> android:orientation="vertical">
<TextView <TextView
android:id="@+id/song_name" android:id="@+id/song_name"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@ -10,6 +10,7 @@
<color name="white_60_color">#99FFFFFF</color> <color name="white_60_color">#99FFFFFF</color>
<color name="progress_buffer_color">#59FFFFFF</color> <color name="progress_buffer_color">#59FFFFFF</color>
<color name="default_play_list_color">#1A1A1A</color> <color name="default_play_list_color">#1A1A1A</color>
<color name="cur_play_music">#4DFFFFFF</color>
<color name="test">#2D9C31</color> <color name="test">#2D9C31</color>
</resources> </resources>