Android简易音乐重构MVVM Java版-新增推荐、雷达歌单详情列表界面(十八)

关于

  本篇主要实现首页发现中推荐歌单和雷达歌单的点击跳转歌单列表界面和播放功能。
简易音乐app仅作为学习用,禁止用于商业及非法用途,如产生法律纠纷与本人无关

效果

在这里插入图片描述

修改ApiService

  增加歌单详情接口

 @GET("playlist/detail")//获取歌单详情列表
    LiveData<ApiResponse<RecommendListEntity>> getPlayList(@Query("id") long creativeId);

增加歌单列表实体类RecommendListEntity

@NoArgsConstructor
@Data
public class RecommendListEntity {

    private int code;
    private Object relatedVideos;
    private PlaylistEntity playlist;
    private Object urls;
    private List<PrivilegesEntity> privileges;
    private Object sharedPrivilege;
    private Object resEntrance;

    @NoArgsConstructor
    @Data
    public static class PlaylistEntity {
        private long id;
        private String name;
        private long coverImgId;
        private String coverImgUrl;
        private String coverImgId_str;
        private int adType;
        private long userId;
        private long createTime;
        private int status;
        private boolean opRecommend;
        private boolean highQuality;
        private boolean newImported;
        private long updateTime;
        private int trackCount;
        private int specialType;
        private int privacy;
        private long trackUpdateTime;
        private String commentThreadId;
        private long playCount;
        private long trackNumberUpdateTime;
        private int subscribedCount;
        private int cloudTrackCount;
        private boolean ordered;
        private String description;
        private List<String> tags;
        private Object updateFrequency;
        private long backgroundCoverId;
        private Object backgroundCoverUrl;
        private long titleImage;
        private Object titleImageUrl;
        private Object englishTitle;
        private Object officialPlaylistType;
        private List<SubscribersEntity> subscribers;
        private boolean subscribed;
        private CreatorEntity creator;
        private List<TracksEntity> tracks;
        private Object videoIds;
        private Object videos;
        private List<TrackIdsEntity> trackIds;
        private int shareCount;
        private int commentCount;
        private Object remixVideo;
        private Object sharedUsers;
        private Object historySharedUsers;
        private String gradeStatus;
        private Object score;
        private Object algTags;

        @NoArgsConstructor
        @Data
        public static class CreatorEntity {
            private boolean defaultAvatar;
            private int province;
            private int authStatus;
            private boolean followed;
            private String avatarUrl;
            private int accountStatus;
            private int gender;
            private int city;
            private int birthday;
            private long userId;
            private int userType;
            private String nickname;
            private String signature;
            private String description;
            private String detailDescription;
            private long avatarImgId;
            private long backgroundImgId;
            private String backgroundUrl;
            private int authority;
            private boolean mutual;
            private List<String> expertTags;
            private ExpertsEntity experts;
            private int djStatus;
            private int vipType;
            private Object remarkName;
            private int authenticationTypes;
            private AvatarDetailEntity avatarDetail;
            private String avatarImgIdStr;
            private String backgroundImgIdStr;
            private boolean anchor;
            private String avatarImgId_str;

            @NoArgsConstructor
            @Data
            public static class ExpertsEntity {
                @SerializedName("1")
                private String _$1;
                @SerializedName("2")
                private String _$2;
            }

            @NoArgsConstructor
            @Data
            public static class AvatarDetailEntity {
                private int userType;
                private int identityLevel;
                private String identityIconUrl;
            }
        }

        @NoArgsConstructor
        @Data
        public static class SubscribersEntity {
            private boolean defaultAvatar;
            private int province;
            private int authStatus;
            private boolean followed;
            private String avatarUrl;
            private int accountStatus;
            private int gender;
            private int city;
            private int birthday;
            private long userId;
            private int userType;
            private String nickname;
            private String signature;
            private String description;
            private String detailDescription;
            private long avatarImgId;
            private long backgroundImgId;
            private String backgroundUrl;
            private int authority;
            private boolean mutual;
            private Object expertTags;
            private Object experts;
            private int djStatus;
            private int vipType;
            private Object remarkName;
            private int authenticationTypes;
            private Object avatarDetail;
            private String avatarImgIdStr;
            private String backgroundImgIdStr;
            private boolean anchor;
            private String avatarImgId_str;
        }

        @NoArgsConstructor
        @Data
        public static class TracksEntity {
            private String name;
            private int id;
            private int pst;
            private int t;
            private List<ArEntity> ar;
            private List<String> alia;
            private int pop;
            private int st;
            private String rt;
            private int fee;
            private int v;
            private Object crbt;
            private String cf;
            private AlEntity al;
            private int dt;
            private HEntity h;
            private MEntity m;
            private LEntity l;
            private Object sq;
            private Object hr;
            private Object a;
            private String cd;
            private int no;
            private Object rtUrl;
            private int ftype;
            private List<?> rtUrls;
            private int djId;
            private int copyright;
            private int s_id;
            private long mark;
            private int originCoverType;
            private Object originSongSimpleData;
            private Object tagPicList;
            private boolean resourceState;
            private int version;
            private Object songJumpInfo;
            private Object entertainmentTags;
            private int single;
            private Object noCopyrightRcmd;
            private Object alg;
            private int mst;
            private int cp;
            private int mv;
            private int rtype;
            private Object rurl;
            private long publishTime;

            @NoArgsConstructor
            @Data
            public static class AlEntity {
                private int id;
                private String name;
                private String picUrl;
                private List<?> tns;
                private String pic_str;
                private long pic;
            }

            @NoArgsConstructor
            @Data
            public static class HEntity {
                private int br;
                private int fid;
                private int size;
                private int vd;
                private int sr;
            }

            @NoArgsConstructor
            @Data
            public static class MEntity {
                private int br;
                private int fid;
                private int size;
                private int vd;
                private int sr;
            }

            @NoArgsConstructor
            @Data
            public static class LEntity {
                private int br;
                private int fid;
                private int size;
                private int vd;
                private int sr;
            }

            @NoArgsConstructor
            @Data
            public static class ArEntity {
                private int id;
                private String name;
                private List<?> tns;
                private List<?> alias;
            }
        }

        @NoArgsConstructor
        @Data
        public static class TrackIdsEntity {
            private int id;
            private int v;
            private int t;
            private long at;
            private Object alg;
            private long uid;
            private String rcmdReason;
            private Object sc;
        }
    }

    @NoArgsConstructor
    @Data
    public static class PrivilegesEntity {
        private int id;
        private int fee;
        private int payed;
        private int realPayed;
        private int st;
        private int pl;
        private int dl;
        private int sp;
        private int cp;
        private int subp;
        private boolean cs;
        private int maxbr;
        private int fl;
        private Object pc;
        private boolean toast;
        private int flag;
        private boolean paidBigBang;
        private boolean preSell;
        private int playMaxbr;
        private int downloadMaxbr;
        private String maxBrLevel;
        private String playMaxBrLevel;
        private String downloadMaxBrLevel;
        private String plLevel;
        private String dlLevel;
        private String flLevel;
        private Object rscl;
        private FreeTrialPrivilegeEntity freeTrialPrivilege;
        private List<ChargeInfoListEntity> chargeInfoList;

        @NoArgsConstructor
        @Data
        public static class FreeTrialPrivilegeEntity {
            private boolean resConsumable;
            private boolean userConsumable;
            private Object listenType;
        }

        @NoArgsConstructor
        @Data
        public static class ChargeInfoListEntity {
            private int rate;
            private Object chargeUrl;
            private Object chargeMessage;
            private int chargeType;
        }
    }
}

新增歌单列表界面

  新增页面activity_mine_play_list.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".ui.daily.MinePlayListActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/app_bar_height"
        android:fitsSystemWindows="true"
        android:theme="@style/Theme.PersonalMusic.AppBarOverlay">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/toolbar_layout"
            style="@style/Widget.MaterialComponents.Toolbar.Primary"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            app:toolbarId="@+id/toolbar">

            <ImageView
                android:id="@+id/img_bg"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layout_collapseMode="parallax"
                />

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_gravity="top"
                android:layout_width="match_parent"
                android:layout_height="@dimen/dp_45"
                app:layout_collapseMode="pin">

                <include
                    android:id="@+id/title"
                    layout="@layout/ui_common_play_title"
                    app:layout_collapseMode="pin"/>
            </androidx.appcompat.widget.Toolbar>

        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>

    <include layout="@layout/content_scrolling"
        android:id="@+id/content"/>



</androidx.coordinatorlayout.widget.CoordinatorLayout>

  对应content_scrolling.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context=".ui.daily.MinePlayListActivity"
    tools:showIn="@layout/activity_mine_play_list">

   <androidx.constraintlayout.widget.ConstraintLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent">

       <RelativeLayout
           android:id="@+id/rv_play_top"
           android:layout_width="match_parent"
           android:layout_height="@dimen/dp_40"
           app:layout_constraintTop_toTopOf="parent"
           tools:ignore="RtlSymmetry">

           <TextView
               android:id="@+id/img_play"
               android:layout_width="@dimen/dp_24"
               android:layout_height="@dimen/dp_24"
               android:layout_centerVertical="true"
               android:layout_marginStart="@dimen/dp_13"
               android:background="@drawable/ic_daily_play_all" />

           <TextView
               android:id="@+id/daily_play"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_centerVertical="true"
               android:layout_marginStart="@dimen/dp_8"
               android:layout_toEndOf="@+id/img_play"
               android:gravity="center"
               android:text="@string/daily_play"
               android:textColor="@color/pureBlack"
               android:textSize="@dimen/sp_18"
               android:textStyle="bold" />

       </RelativeLayout>

       <ImageView
           android:id="@+id/img_loading"
           android:layout_width="@dimen/dp_40"
           android:layout_height="@dimen/dp_40"
           android:layout_marginTop="@dimen/dp_50"
           app:layout_constraintStart_toStartOf="parent"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintTop_toBottomOf="@id/rv_play_top"
           />


       <androidx.recyclerview.widget.RecyclerView
           android:id="@+id/rv_play_list"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           app:layout_constraintTop_toBottomOf="@id/rv_play_top"
           android:orientation="vertical"
           />
   </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.core.widget.NestedScrollView>

新增MinePlayListViewModel.java

public class MinePlayListViewModel extends ViewModel {

    private SavedStateHandle state;

    public Long currentPlayId = 0L;

    public MinePlayListViewModel(SavedStateHandle savedStateHandle) {
        this.state = savedStateHandle;
    }

    public LiveData<ApiResponse<RecommendListEntity>> getPlayList(){
        return RetrofitUtils.getmApiUrl().getPlayList(currentPlayId);
    }
}

修改Constant

public static final String PLAYLIST_ID = "PLAYLIST_ID";

public static final String PLAY_NAME = "PLAY_NAME";

修改MinePlayListActivity(歌单界面)

public class MinePlayListActivity extends BaseActivity {

    private ActivityMinePlayListBinding binding;
    private MinePlayListViewModel viewModel;
    private PlayListAdapter adapter;
    private ArrayList<MusicInfo> songList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMinePlayListBinding.inflate(getLayoutInflater());
        viewModel  = new ViewModelProvider(this).get(MinePlayListViewModel.class);
        setContentView(binding.getRoot());
        viewModel.currentPlayId = getIntent().getLongExtra(PLAYLIST_ID,0L);
        loadGif();
        initRecycle();
        initObserver();
        initView();
    }

    private void loadGif() {
        Glide.with(this)
                .asGif()
                .load(R.drawable.play_list_loading)
                .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
                .into(binding.content.imgLoading);
    }

    private void initView() {
        binding.content.rvPlayTop.setOnClickListener(v -> {
            if (ClickUtil.enableClick()){
                MusicPlay.playMusicByList(songList,0);
                startActivity(new Intent(this, CurrentSongPlayActivity.class)
                        .putExtra(MUSIC_INFO,songList.get(0)));
            }
        });
        binding.title.ivBack.setOnClickListener(view -> {
            if (ClickUtil.enableClick()){
                finish();
            }
        });
        binding.title.tvTitle.setText(getIntent().getStringExtra(PLAY_NAME));
    }

    private void initRecycle() {
        adapter = new PlayListAdapter(this);
        LinearLayoutManager manager = new LinearLayoutManager(this);
        manager.setOrientation(LinearLayoutManager.VERTICAL);
        binding.content.rvPlayList.setLayoutManager(manager);
        binding.content.rvPlayList.setAdapter(adapter);
        binding.content.rvPlayList.setHasFixedSize(true);
    }

    private void initObserver() {
        viewModel.getPlayList().observe(this, playList -> {
            ViewExtensionKt.printLog(playList.getMessage());
            if (playList.getStatus() == Status.SUCCESS){
                binding.content.imgLoading.setVisibility(View.GONE);
                adapter.setDataList(playList.getData().getPlaylist().getTracks());
                for (RecommendListEntity.PlaylistEntity.TracksEntity data:playList.getData().getPlaylist().getTracks()){
                    MusicInfo musicInfo = new MusicInfo();
                    musicInfo.setSongId(String.valueOf(data.getId()));
                    musicInfo.setSongUrl(Constant.SONG_URL+data.getId());
                    musicInfo.setSongCover(data.getAl().getPicUrl());
                    musicInfo.setSongName(data.getName());
                    musicInfo.setArtist(data.getAr().get(0).getName());
                    songList.add(musicInfo);
                }
            }
        });
    }
}

修改推荐歌单适配器RecommendAdapter

holder.itemView.setOnClickListener(view -> {
            if (ClickUtil.enableClick()){
                mContext.startActivity(new Intent(mContext, MinePlayListActivity.class)
                        .putExtra(PLAYLIST_ID,Long.valueOf(bean.getCreativeId()))
                        .putExtra(PLAY_NAME,bean.getUiElement().getMainTitle().getTitle()));
            }
        });

修改雷达歌单适配器MgcAdapter

 holder.itemView.setOnClickListener(view -> {
            if (ClickUtil.enableClick()){
                mContext.startActivity(new Intent(mContext, MinePlayListActivity.class)
                        .putExtra(PLAYLIST_ID,Long.valueOf(bean.getCreativeId()))
                        .putExtra(PLAY_NAME,bean.getUiElement().getMainTitle().getTitle()));
            }
        });

  本篇到此结束了,有问题欢迎批评指正,觉得不错的也请点个赞

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

雪の星空朝酱

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

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

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

打赏作者

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

抵扣说明:

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

余额充值