Android简易音乐重构MVVM Java版-解决播放界面旋转动画卡顿及播放异常崩溃问题(二十一)

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;
    }
}

  本篇文章到此结束,有问题欢迎批评指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪の星空朝酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值