Android简易音乐重构MVVM Java版-解决播放界面旋转动画卡顿及播放异常崩溃问题(二十一)
关于
本篇主要解决播放界面歌曲封面旋转不平滑问题及、部分歌曲需要在失败后调用获取音乐来源重新播放并添加进播放队列中,以及解决部分歌曲封面加载导致背景过亮看不清其余东西。ps(最近工作上比较忙,简易音乐的功能开发及博客项目编写更新频率会降低。)
简易音乐app仅作为学习用,禁止用于商业及非法用途,如产生法律纠纷与本人无关
效果图
修改ApiService
@GET("song/url") //获取歌曲信息
LiveData<ApiResponse<SongEntity>> getSongUrl(@Query("id") long songUrl);
歌曲实体类SongEntity
@NoArgsConstructor
@Data
public class SongEntity {
private List<DataEntity> data;
private int code;
@NoArgsConstructor
@Data
public static class DataEntity {
private int id;
private String url;
private int br;
private int size;
private String md5;
private int code;
private int expi;
private String type;
private double gain;
private int fee;
private Object uf;
private int payed;
private int flag;
private boolean canExtend;
private Object freeTrialInfo;
private String level;
private String encodeType;
private FreeTrialPrivilegeEntity freeTrialPrivilege;
private FreeTimeTrialPrivilegeEntity freeTimeTrialPrivilege;
private int urlSource;
private int rightSource;
@NoArgsConstructor
@Data
public static class FreeTrialPrivilegeEntity {
private boolean resConsumable;
private boolean userConsumable;
private Object listenType;
}
@NoArgsConstructor
@Data
public static class FreeTimeTrialPrivilegeEntity {
private boolean resConsumable;
private boolean userConsumable;
private int type;
private int remainTime;
}
}
}
修改播放界面
修改activity_current_song_play.xml
<!--添加背景灰色值,降低图片亮度-->
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/grays_0350" />
修改CurrentSongPlayActivity
public class CurrentSongPlayActivity extends BaseActivity {
private ActivityCurrentSongPlayBinding binding;
private ObjectAnimator rotationAnim;
private MusicInfo musicInfo;
private SongPlayViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityCurrentSongPlayBinding.inflate(getLayoutInflater());
viewModel = new ViewModelProvider(this).get(SongPlayViewModel.class);
binding.setVm(viewModel);
binding.setLifecycleOwner(this);
setContentView(binding.getRoot());
initView();
initAnim();
initObserver();
}
private void initObserver() {
viewModel.getLyric()
.observe(this, lyricEntityApiResponse -> {
ViewExtensionKt.printLog("当前"+lyricEntityApiResponse.getMessage());
if (lyricEntityApiResponse.getStatus() == Status.SUCCESS){
if (lyricEntityApiResponse.getData().getLrc() != null){
if (lyricEntityApiResponse.getData().getTlyric() != null){
binding.lrc.loadLrc(lyricEntityApiResponse.getData().getLrc().getLyric(),lyricEntityApiResponse.getData().getTlyric().getLyric());
}else {
binding.lrc.loadLrc(lyricEntityApiResponse.getData().getLrc().getLyric(),"");
}
}else {
binding.lrc.loadLrc("","");
}
}
});
}
private void initView() {
musicInfo = getIntent().getParcelableExtra(MUSIC_INFO);
initImageBg(musicInfo);
initListener();
binding.viewBody.setOnClickListener(view -> {
if (ClickUtil.enableClick()){
viewModel.isShowLrc = !viewModel.isShowLrc;
showLyrics(viewModel.isShowLrc);
}
});
//进度
binding.seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
MusicPlay.seekTo(seekBar.getProgress(),true);
binding.lrc.updateTime(seekBar.getProgress());
}
});
binding.ivPlayMode.setOnClickListener(v -> {
if (ClickUtil.enableClick()){
changeRepeatMode();
}
});
binding.lrc.setListener(time -> {
MusicPlay.seekTo(time,true);
return true;
});
binding.lrc.setCoverChangeListener(()->{
viewModel.isShowLrc = false;
showLyrics(false);
});
binding.ivList.setOnClickListener(view -> {
//MusicPlay.getPlayList()
});
binding.ivPlay.setOnClickListener(v -> {
if (MusicPlay.isPlaying()){
MusicPlay.pauseMusic();
rotationAnim.pause();
}else {
MusicPlay.restoreMusic();
rotationAnim.resume();
}
});
}
private void initImageBg(MusicInfo musicInfo) {
viewModel.currentSongUrl.set(musicInfo.getSongCover());
RequestOptions options = new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.bitmapTransform(new BlurTransformation(25, 30));
viewModel.currentSongId.set(Long.parseLong(musicInfo.getSongId()));
initObserver();
Glide.with(this)
.asBitmap()
.load(musicInfo.getSongCover())
//.placeholder()
.transition(BitmapTransitionOptions.withCrossFade(1500))
.apply(options)
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
Drawable drawable = ImageUtils.createBlurredImageFromBitmap(resource, 15);
binding.imgBc.setImageDrawable(drawable);
Palette.from(resource)
.setRegion(0,0,getScreenWidth(),getStatusBarHeight())
.maximumColorCount(6)
.generate(palette -> {
Palette.Swatch mostPopularSwatch = null;
for (Palette.Swatch swatch: palette.getSwatches()){
if (mostPopularSwatch == null
|| swatch.getPopulation() > mostPopularSwatch.getPopulation()){
mostPopularSwatch = swatch;
}
}
if (mostPopularSwatch!= null){
double luminance =ColorUtils.calculateLuminance(mostPopularSwatch.getRgb());
// 当luminance小于0.5时,我们认为这是一个深色值.
if (luminance < 0.5){
setDarkStatusBar();
}else {
setLightStatusBar();
}
}
});
StatusBarUtil.setTranslucentForImageView(CurrentSongPlayActivity.this,0,binding.viewTitleBg);
}
});
binding.tvTitle.setText(musicInfo.getSongName());
binding.tvSinger.setText(musicInfo.getArtist());
}
private int getScreenWidth(){
DisplayMetrics displayMetrics =new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
private int getStatusBarHeight(){
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0){
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
private void initListener() {
MusicPlay.onPlayStateListener(this, new OnMusicPlayStateListener() {
@Override
public void onPlayState(@NonNull PlayManger playManger) {
switch (playManger.getStage()){
case PlayManger.PAUSE:
case PlayManger.IDLE:
rotationAnim.pause();
binding.ivPlay.setImageResource(R.drawable.shape_play_white);
break;
case PlayManger.PLAYING:
resumeRotateAnimation();
binding.ivPlay.setImageResource(R.drawable.shape_pause_white);
break;
case PlayManger.BUFFERING:
ViewExtensionKt.printLog("缓冲");
break;
case PlayManger.SWITCH:
if (playManger.getSongInfo() != null){
initImageBg(playManger.getSongInfo());
}
break;
case PlayManger.ERROR:
//获取当前歌曲播放失败的歌曲信息
MusicInfo musicInfo = playManger.getSongInfo();
int index = MusicPlay.getNowPlayingIndex();
viewModel.getSongInfo(Long.parseLong(playManger.getSongInfo().getSongId()))
.observe(CurrentSongPlayActivity.this, songEntityApiResponse -> {
if (songEntityApiResponse.getStatus() == Status.SUCCESS){
if (songEntityApiResponse.getData().getData()!= null && songEntityApiResponse.getData().getData().get(0).getUrl() != null){
musicInfo.setSongUrl(songEntityApiResponse.getData().getData().get(0).getUrl());
MusicPlay.addSongInfo(musicInfo,index);
MusicPlay.playMusicByInfo(musicInfo);
}else {
//歌曲无版权
ToastUtils.show(getString(R.string.no_copyright));
MusicPlay.removeSongInfoById(playManger.getSongInfo().getSongId());
}
}
});
break;
}
}
});
MusicPlay.onPlayProgressListener(new OnMusicPlayProgressListener() {
@Override
public void onPlayProgress(long curP, long duration) {
if (binding.seekBar.getMax() != duration){
binding.seekBar.setMax((int) duration);
binding.tvTotalTime.setText(TimeUtil.getTimeNoYMDH(duration));
}
binding.tvPastTime.setText(TimeUtil.getTimeNoYMDH(curP));
binding.lrc.updateTime(curP);
binding.seekBar.setProgress((int) curP);
}
});
}
//根据isShowLyrics来判断是否展示歌词
private void showLyrics(boolean isShowLyrics) {
binding.ivMusicCover.setVisibility(isShowLyrics ? View.GONE : View.VISIBLE);
binding.lrc.setVisibility(isShowLyrics ? View.VISIBLE : View.GONE);
}
//使状态栏图标黑
private void setLightStatusBar(){
binding.tvTitle.setTextColor(getColor(R.color.black80));
binding.tvSinger.setTextColor(getColor(R.color.black70));
int flags = getWindow().getDecorView().getSystemUiVisibility();
getWindow().getDecorView().setSystemUiVisibility(flags | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
//使状态栏图标白
private void setDarkStatusBar(){
binding.tvTitle.setTextColor(getColor(R.color.white));
binding.tvSinger.setTextColor(getColor(R.color.white80));
int flags = getWindow().getDecorView().getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
getWindow().getDecorView().setSystemUiVisibility(flags^View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
private void changeRepeatMode(){
int currentModel = MusicPlay.getRepeatMode();
switch (currentModel){
case SpConstant.REPEAT_MODE_NONE:
MusicPlay.setRepeatMode(SpConstant.REPEAT_MODE_ONE,true);
ToastUtils.show(getString(R.string.repeat_one));
break;
case SpConstant.REPEAT_MODE_ONE:
MusicPlay.setRepeatMode(SpConstant.REPEAT_MODE_SHUFFLE,false);
ToastUtils.show(getString(R.string.repeat_random));
break;
case SpConstant.REPEAT_MODE_SHUFFLE:
MusicPlay.setRepeatMode(SpConstant.REPEAT_MODE_NONE,true);
ToastUtils.show(getString(R.string.repeat_none));
break;
}
}
private void initAnim() {
rotationAnim = ObjectAnimator.ofFloat(binding.ivMusicCover, "rotation", 0F, 359F);
rotationAnim.setDuration(20 * 1000);
rotationAnim.setInterpolator(new LinearInterpolator());
rotationAnim.setRepeatCount(-1);
rotationAnim.setRepeatMode(ValueAnimator.RESTART);
rotationAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//更新歌曲封面旋转度同步
binding.ivMusicCover.setRotation((Float) animation.getAnimatedValue());
}
});
rotationAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation, boolean isReverse) {
super.onAnimationEnd(animation, isReverse);
rotationAnim.start();
}
});
if (MusicPlay.isPlaying()){
rotationAnim.pause();
rotationAnim.start();
}
}
private void resumeRotateAnimation(){
if (rotationAnim != null && rotationAnim.isStarted()){
rotationAnim.resume();
}else {
rotationAnim.start();
}
}
@Override
protected void onResume() {
super.onResume();
if (rotationAnim != null && rotationAnim.isPaused() && MusicPlay.isPlaying()){
rotationAnim.resume();
}
}
@Override
protected void onStop() {
super.onStop();
rotationAnim.pause();
}
@Override
protected void onDestroy() {
super.onDestroy();
rotationAnim.cancel();
rotationAnim.removeAllListeners();
rotationAnim = null;
}
}
本篇文章到此结束,有问题欢迎批评指正。