pl #5

Merged
px4lqzo5h merged 23 commits from pl into develop 1 year ago

@ -1,18 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- LitePal 配置文件 -->
<litepal>
<!-- 数据库名称 -->
<dbname value="SongList" />
<!-- 数据库版本 -->
<version value="27" />
<!-- 实体类映射列表 -->
<list>
<!-- 在线歌曲实体类 -->
<mapping class="com.example.musicplayer.entiy.OnlineSong" />
<!-- 本地歌曲实体类 -->
<mapping class="com.example.musicplayer.entiy.LocalSong" />
<!-- 搜索历史实体类 -->
<mapping class="com.example.musicplayer.entiy.SearchHistory" />
<!-- 喜欢的歌曲实体类 -->
<mapping class="com.example.musicplayer.entiy.Love" />
<!-- 历史歌曲实体类 -->
<mapping class="com.example.musicplayer.entiy.HistorySong" />
<!-- 专辑收藏实体类 -->
<mapping class="com.example.musicplayer.entiy.AlbumCollection" />
<!-- 下载歌曲实体类 -->
<mapping class="com.example.musicplayer.entiy.DownloadSong" />
<!-- 下载信息实体类 -->
<mapping class="com.example.musicplayer.entiy.DownloadInfo"/>
<!-- 歌曲实体类 -->
<mapping class="com.example.musicplayer.entiy.Song"/>
</list>
</litepal>

@ -1,5 +1,7 @@
package com.example.musicplayer.adapter;
// 导入所需的包和类
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.annotation.NonNull;
@ -19,38 +21,47 @@ import com.example.musicplayer.util.FileUtil;
import java.util.List;
/**
*
* <p>
* Created by on 2018/11/30.
*/
public class LoveSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = "LoveSongAdapter";
private int footerViewType = 1;
private int itemViewType = 0;
private List<Love> mLoveList;
private Context mContext;
private int mLastPosition = -1;
private OnItemClickListener onItemClickListener;
private static final String TAG = "LoveSongAdapter"; // 用于日志输出的标签
private int footerViewType = 1; // 底部视图类型标识
private int itemViewType = 0; // 列表项视图类型标识
private List<Love> mLoveList; // 存储喜欢的歌曲数据
private Context mContext; // 上下文对象
private int mLastPosition = -1; // 上一次点击的位置
private OnItemClickListener onItemClickListener; // 点击事件监听器
/**
*
* @param onItemClickListener
*/
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
/**
*
* @param context
* @param loveList
*/
public LoveSongAdapter(Context context, List<Love> loveList) {
mContext = context;
mLoveList = loveList;
}
// ViewHolder用于缓存视图提高列表滚动性能
class ViewHolder extends RecyclerView.ViewHolder {
TextView songNameTv;
TextView singerTv;
View playLine;
RippleView item;
TextView songNameTv; // 歌曲名称文本
TextView singerTv; // 歌手文本
View playLine; // 播放线条视图
RippleView item; // 带有水波纹效果的视图
public ViewHolder(View itemView) {
super(itemView);
songNameTv = itemView.findViewById(R.id.tv_title);
songNameTv = itemView.findViewById(R.id.tv_title); // 初始化视图
singerTv = itemView.findViewById(R.id.tv_artist);
playLine = itemView.findViewById(R.id.line_play);
item = itemView.findViewById(R.id.ripple);
@ -58,11 +69,10 @@ public class LoveSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
/**
* holder
* ViewHolder
*/
static class FooterHolder extends RecyclerView.ViewHolder {
TextView numTv;
TextView numTv; // 底部信息文本
public FooterHolder(View itemView) {
super(itemView);
@ -70,6 +80,12 @@ public class LoveSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
/**
* ViewHolder
* @param parent
* @param viewType
* @return ViewHolder
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == itemViewType) {
@ -85,6 +101,11 @@ public class LoveSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
/**
* ViewHolder
* @param viewHolder
* @param position
*/
@SuppressLint("SetTextI18n")
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
@ -95,7 +116,7 @@ public class LoveSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
holder.songNameTv.setText(love.getName());
holder.singerTv.setText(love.getSinger());
//根据点击显示
// 根据歌曲是否正在播放显示不同的样式
if (love.getSongId().equals(FileUtil.getSong().getSongId())) {
holder.playLine.setVisibility(View.VISIBLE);
mLastPosition = position;
@ -122,7 +143,10 @@ public class LoveSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
//判断点击的是否为上一个点击的项目
/**
*
* @param position
*/
public void equalPosition(int position) {
if (position != mLastPosition) {
notifyItemChanged(mLastPosition);
@ -131,13 +155,22 @@ public class LoveSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
notifyItemChanged(position);
}
/**
*
* @return
*/
@Override
public int getItemCount() {
return mLoveList.size() + 1;
return mLoveList.size() + 1; // 加1是为了显示底部视图
}
/**
*
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
return position + 1 == getItemCount() ? footerViewType : itemViewType;
}
}
}

@ -1,5 +1,7 @@
package com.example.musicplayer.adapter;
// 导入所需的包和类
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
@ -25,30 +27,32 @@ import java.util.ArrayList;
import java.util.List;
/**
*
* Created by on 2018/11/21.
*/
public class SearchContentAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = "SearchContentAdapter";
private ArrayList<SearchSong.DataBean.SongBean.ListBean> mSongListBeans;
private List<Album.DataBean.AlbumBean.ListBean> mAlbumList;
private static OnItemClickListener mItemClick;
private static OnAlbumItemClickListener mAlbumClick;
private String mSeek;
private Context mContext;
private int mLastPosition = -1;
private int mType;
private ArrayList<SearchSong.DataBean.SongBean.ListBean> mSongListBeans; // 单曲列表数据
private List<Album.DataBean.AlbumBean.ListBean> mAlbumList; // 专辑列表数据
private static OnItemClickListener mItemClick; // 单曲点击事件监听器
private static OnAlbumItemClickListener mAlbumClick; // 专辑点击事件监听器
private String mSeek; // 搜索关键字
private Context mContext; // 上下文对象
private int mLastPosition = -1; // 上一次点击的位置
private int mType; // 列表类型,单曲或专辑
// 设置单曲点击事件监听器
public static void setItemClick(OnItemClickListener itemClick) {
mItemClick = itemClick;
}
// 设置专辑点击事件监听器
public static void setAlbumClick(OnAlbumItemClickListener albumClick) {
mAlbumClick = albumClick;
}
// 构造函数,初始化专辑搜索适配器
public SearchContentAdapter(List<Album.DataBean.AlbumBean.ListBean> dataBeans, String seek, Context context, int type) {
mContext = context;
mSeek = seek;
@ -56,7 +60,7 @@ public class SearchContentAdapter extends RecyclerView.Adapter<RecyclerView.View
mType = type;
}
// 构造函数,初始化单曲搜索适配器
public SearchContentAdapter(ArrayList<SearchSong.DataBean.SongBean.ListBean> songListBeans, String seek, Context context, int type) {
mContext = context;
mSeek = seek;
@ -64,10 +68,11 @@ public class SearchContentAdapter extends RecyclerView.Adapter<RecyclerView.View
mType = type;
}
// 创建ViewHolder
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
final View view;
if (viewType == Constant.TYPE_SONG ) {
if (viewType == Constant.TYPE_SONG) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_song_search_item, parent, false);
return new ViewHolder(view);
@ -77,35 +82,37 @@ public class SearchContentAdapter extends RecyclerView.Adapter<RecyclerView.View
return new AlbumHolder(view);
}
return null;
}
// 将数据绑定到ViewHolder
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
// 根据ViewHolder类型进行不同的数据处理
if (holder instanceof ViewHolder) {
ViewHolder songHolder = (ViewHolder) holder;
SearchSong.DataBean.SongBean.ListBean songListBean = mSongListBeans.get(position);
//设置歌手,因为歌手可能有两个
// 设置歌手名称,可能存在多个歌手
String singer = songListBean.getSinger().get(0).getName();
for (int i = 1; i < songListBean.getSinger().size(); i++) {
singer+="、"+songListBean.getSinger().get(i).getName();
singer += "、" + songListBean.getSinger().get(i).getName();
}
songHolder.artistTv.setText(singer);
//设置与搜索一样的string的颜色
// 高亮显示搜索关键字
CommonUtil.showStringColor(mSeek, singer, songHolder.artistTv);
songHolder.titleTv.setText(songListBean.getSongname());
CommonUtil.showStringColor(mSeek, songListBean.getSongname(), songHolder.titleTv);
//根据点击显示
if(songListBean.getSongmid().equals(FileUtil.getSong().getSongId())){
// 根据歌曲是否正在播放显示不同的样式
if (songListBean.getSongmid().equals(FileUtil.getSong().getSongId())) {
songHolder.playLine.setVisibility(View.VISIBLE);
mLastPosition =position;
mLastPosition = position;
songHolder.mItemView.setBackgroundResource(R.color.translucent);
}else {
} else {
songHolder.playLine.setVisibility(View.INVISIBLE);
songHolder.mItemView.setBackgroundResource(R.color.transparent);
}
// 设置点击事件
songHolder.mItemView.setOnRippleCompleteListener(rippleView -> {
mItemClick.onClick(position);
equalPosition(position);
@ -113,21 +120,24 @@ public class SearchContentAdapter extends RecyclerView.Adapter<RecyclerView.View
} else {
AlbumHolder albumHolder = (AlbumHolder) holder;
Album.DataBean.AlbumBean.ListBean albumList = mAlbumList.get(position);
// 使用Glide加载专辑图片
Glide.with(mContext).load(albumList.getAlbumPic())
.apply(RequestOptions.errorOf(R.drawable.background)).into(albumHolder.albumIv);
albumHolder.albumName.setText(albumList.getAlbumName());
albumHolder.singerName.setText(albumList.getSingerName());
albumHolder.publicTime.setText(albumList.getPublicTime());
// 高亮显示搜索关键字
CommonUtil.showStringColor(mSeek, albumList.getAlbumName(), albumHolder.albumName);
CommonUtil.showStringColor(mSeek, albumList.getSingerName(), albumHolder.singerName);
CommonUtil.showStringColor(mSeek, albumList.getPublicTime(), albumHolder.publicTime);
// 设置点击事件
albumHolder.item.setOnRippleCompleteListener(rippleView -> {
mAlbumClick.onClick(position);
});
}
}
// 获取列表项的总数
@Override
public int getItemCount() {
if (mType == Constant.TYPE_SONG) {
@ -138,6 +148,7 @@ public class SearchContentAdapter extends RecyclerView.Adapter<RecyclerView.View
return 0;
}
// 内部类ViewHolder用于单曲列表项
class ViewHolder extends RecyclerView.ViewHolder {
TextView titleTv;
TextView artistTv;
@ -153,6 +164,7 @@ public class SearchContentAdapter extends RecyclerView.Adapter<RecyclerView.View
}
}
// 内部类AlbumHolder用于专辑列表项
class AlbumHolder extends RecyclerView.ViewHolder {
ImageView albumIv;
TextView singerName;
@ -170,12 +182,13 @@ public class SearchContentAdapter extends RecyclerView.Adapter<RecyclerView.View
}
}
// 获取列表项的视图类型
@Override
public int getItemViewType(int position) {
return mType;
}
//判断点击的是否为上一个点击的项目
// 判断点击的是否为上一个点击的项目,并更新视图
public void equalPosition(int position) {
if (position != mLastPosition) {
if (mLastPosition != -1) notifyItemChanged(mLastPosition);
@ -183,4 +196,4 @@ public class SearchContentAdapter extends RecyclerView.Adapter<RecyclerView.View
}
notifyItemChanged(position);
}
}
}

@ -1,5 +1,7 @@
package com.example.musicplayer.adapter;
// 导入所需的包和类
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@ -18,64 +20,72 @@ import com.example.musicplayer.entiy.SearchHistory;
import java.util.List;
/**
*
*
* Created by on 2018/11/29.
*/
public class SearchHistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<SearchHistory> mSearchHistoryList;
private static final int mHistoryType =0;
private static final int mFooterType = 1;
private OnItemClickListener mOnItemClickListener;
private OnDeleteClickListener mOnDeleteClickListener;
private OnFooterClickListener mFooterClickListener;
public SearchHistoryAdapter(List<SearchHistory> searchHistoryList){
private List<SearchHistory> mSearchHistoryList; // 搜索历史列表数据
private static final int mHistoryType = 0; // 历史记录项的视图类型
private static final int mFooterType = 1; // 底部删除按钮的视图类型
private OnItemClickListener mOnItemClickListener; // 列表项点击事件监听器
private OnDeleteClickListener mOnDeleteClickListener; // 删除按钮点击事件监听器
private OnFooterClickListener mFooterClickListener; // 底部删除所有按钮点击事件监听器
// 构造函数,初始化搜索历史列表
public SearchHistoryAdapter(List<SearchHistory> searchHistoryList) {
mSearchHistoryList = searchHistoryList;
}
// 创建ViewHolder
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if(viewType ==mHistoryType){
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_seek_history_item,
parent,false);
if (viewType == mHistoryType) {
// 历史记录项布局
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_seek_history_item, parent, false);
return new HistoryHolder(view);
}else{
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.footer_delete_all_history_item,
parent,false);
} else {
// 底部删除所有按钮布局
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.footer_delete_all_history_item, parent, false);
return new FooterHolder(view);
}
}
// 将数据绑定到ViewHolder
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
if(holder instanceof HistoryHolder){
HistoryHolder historyHolder =(HistoryHolder) holder;
if (holder instanceof HistoryHolder) {
HistoryHolder historyHolder = (HistoryHolder) holder;
// 设置历史记录文本
historyHolder.historyTv.setText(mSearchHistoryList.get(position).getHistory());
// 设置删除按钮点击事件
historyHolder.deleteIv.setOnClickListener(v -> mOnDeleteClickListener.onClick(position));
// 设置列表项点击事件
historyHolder.mItemView.setOnRippleCompleteListener(rippleView -> mOnItemClickListener.onClick(position));
}else{
FooterHolder footerHolder =(FooterHolder) holder;
} else {
FooterHolder footerHolder = (FooterHolder) holder;
// 设置底部删除所有按钮点击事件
footerHolder.deleteView.setOnClickListener(v -> mFooterClickListener.onClick());
}
}
// 获取列表项的总数
@Override
public int getItemCount() {
return mSearchHistoryList.size()+1;
return mSearchHistoryList.size() + 1; // 加1是为了显示底部删除所有按钮
}
// 获取列表项的视图类型
@Override
public int getItemViewType(int position) {
return position + 1 == getItemCount() ? mFooterType :mHistoryType;
return position + 1 == getItemCount() ? mFooterType : mHistoryType;
}
// 内部类HistoryHolder用于历史记录列表项
private class HistoryHolder extends RecyclerView.ViewHolder {
TextView historyTv;
ImageView deleteIv;
RippleView mItemView;
TextView historyTv; // 历史记录文本
ImageView deleteIv; // 删除按钮
RippleView mItemView; // 列表项背景
public HistoryHolder(View itemView) {
super(itemView);
@ -85,8 +95,9 @@ public class SearchHistoryAdapter extends RecyclerView.Adapter<RecyclerView.View
}
}
// 内部类FooterHolder用于底部删除所有按钮
private class FooterHolder extends RecyclerView.ViewHolder {
View deleteView;
View deleteView; // 删除所有按钮
public FooterHolder(View itemView) {
super(itemView);
@ -94,13 +105,18 @@ public class SearchHistoryAdapter extends RecyclerView.Adapter<RecyclerView.View
}
}
public void setOnItemClickListener(OnItemClickListener onItemClcikListener){
mOnItemClickListener =onItemClcikListener;
// 设置列表项点击事件监听器
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
}
public void setOnDeleteClickListener(OnDeleteClickListener onDeleteClickListener){
mOnDeleteClickListener =onDeleteClickListener;
// 设置删除按钮点击事件监听器
public void setOnDeleteClickListener(OnDeleteClickListener onDeleteClickListener) {
mOnDeleteClickListener = onDeleteClickListener;
}
public void setFooterClickListener(OnFooterClickListener onFooterClickListener){
mFooterClickListener =onFooterClickListener;
// 设置底部删除所有按钮点击事件监听器
public void setFooterClickListener(OnFooterClickListener onFooterClickListener) {
mFooterClickListener = onFooterClickListener;
}
}
}

@ -1,5 +1,7 @@
package com.example.musicplayer.adapter;
// 导入所需的包和类
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.annotation.NonNull;
@ -21,33 +23,35 @@ import java.util.List;
import java.util.Objects;
/**
*
* Created by on 2018/10/10.
*/
public class SongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = "SongAdapter";
private int footerViewType = 1;
private int itemViewType = 0;
private List<LocalSong> mMp3InfoList;
private Context mContext;
private int mLastPosition = -1;
private OnItemClickListener onItemClickListener;
private static final String TAG = "SongAdapter"; // 用于日志输出的标签
private int footerViewType = 1; // 底部视图类型标识
private int itemViewType = 0; // 列表项视图类型标识
private List<LocalSong> mMp3InfoList; // 本地歌曲列表数据
private Context mContext; // 上下文对象
private int mLastPosition = -1; // 上一次点击的位置
private OnItemClickListener onItemClickListener; // 点击事件监听器
// 设置点击事件监听器
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
// 构造函数,初始化上下文和本地歌曲列表
public SongAdapter(Context context, List<LocalSong> mp3InfoList) {
mContext = context;
mMp3InfoList = mp3InfoList;
}
// 内部类ViewHolder用于歌曲列表项
static class ViewHolder extends RecyclerView.ViewHolder {
TextView songNameTv;
TextView artistTv;
ImageView playingIv;
RippleView songView;
TextView songNameTv; // 歌曲名称文本
TextView artistTv; // 歌手文本
ImageView playingIv; // 播放状态图标
RippleView songView; // 歌曲项背景
public ViewHolder(View itemView) {
super(itemView);
@ -58,12 +62,9 @@ public class SongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
}
}
/**
* holder
*/
// 底部holder
static class FooterHolder extends RecyclerView.ViewHolder {
TextView numTv;
TextView numTv; // 底部信息文本
public FooterHolder(View itemView) {
super(itemView);
@ -71,6 +72,7 @@ public class SongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
}
}
// 创建ViewHolder
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == itemViewType) {
@ -86,6 +88,7 @@ public class SongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
}
}
// 将数据绑定到ViewHolder
@SuppressLint("SetTextI18n")
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
@ -95,20 +98,20 @@ public class SongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
holder.songNameTv.setText(mp3Info.getName());
holder.artistTv.setText(mp3Info.getSinger());
//根据播放的歌曲是否为当前列表的歌曲显示
// 根据播放的歌曲是否为当前列表的歌曲显示
String songId = Objects.requireNonNull(FileUtil.getSong()).getSongId();
if(songId!=null&&(mp3Info.getSongId().equals(songId))){
holder.songNameTv.setTextColor(App.getContext().
getResources().getColor(R.color.musicStyle_low));
holder.artistTv.setTextColor(App.getContext().
getResources().getColor(R.color.musicStyle_low));
if (songId != null && mp3Info.getSongId().equals(songId)) {
holder.songNameTv.setTextColor(App.getContext()
.getResources().getColor(R.color.musicStyle_low));
holder.artistTv.setTextColor(App.getContext()
.getResources().getColor(R.color.musicStyle_low));
holder.playingIv.setVisibility(View.VISIBLE);
mLastPosition = position;
}else {
holder.songNameTv.setTextColor(App.getContext().
getResources().getColor(R.color.white));
holder.artistTv.setTextColor(App.getContext().
getResources().getColor(R.color.white));
} else {
holder.songNameTv.setTextColor(App.getContext()
.getResources().getColor(R.color.white));
holder.artistTv.setTextColor(App.getContext()
.getResources().getColor(R.color.white));
holder.playingIv.setVisibility(View.GONE);
}
holder.songView.setOnRippleCompleteListener(rippleView -> {
@ -117,11 +120,11 @@ public class SongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
});
} else {
FooterHolder footerHolder = (FooterHolder) viewHolder;
footerHolder.numTv.setText("共" +mMp3InfoList.size()+ "首音乐");
footerHolder.numTv.setText("共" + mMp3InfoList.size() + "首音乐");
}
}
//判断点击的是否为上一个点击的项目
// 判断点击的是否为上一个点击的项目
public void equalPosition(int position) {
if (position != mLastPosition) {
notifyItemChanged(mLastPosition);
@ -130,17 +133,15 @@ public class SongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
notifyItemChanged(position);
}
// 获取列表项的总数
@Override
public int getItemCount() {
return mMp3InfoList.size() + 1;
return mMp3InfoList.size() + 1; // 加1是为了显示底部视图
}
// 获取列表项的视图类型
@Override
public int getItemViewType(int position) {
return position + 1 == getItemCount() ? footerViewType : itemViewType;
}
}
}

@ -1,5 +1,6 @@
package com.example.musicplayer.adapter;
// 导入所需的包和类
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
@ -7,31 +8,35 @@ import android.support.v4.app.FragmentPagerAdapter;
import java.util.List;
/**
* Fragment
* Created by on 2018/11/25.
*/
public class TabAdapter extends FragmentPagerAdapter {
private List<Fragment> mFragmentList;//顶部导航栏的内容即fragment
private List<String> mTitle;//顶部导航栏的标题
private List<Fragment> mFragmentList; // 顶部导航栏的内容,即 Fragment 列表
private List<String> mTitle; // 顶部导航栏的标题列表
public TabAdapter(FragmentManager fragmentManager, List<Fragment>fragments, List<String>title){
// 构造函数,初始化 FragmentManager、Fragment 列表和标题列表
public TabAdapter(FragmentManager fragmentManager, List<Fragment> fragments, List<String> title) {
super(fragmentManager);
mFragmentList=fragments;
mTitle=title;
mFragmentList = fragments;
mTitle = title;
}
// 获取指定位置的 Fragment
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
// 获取 Fragment 的总数
@Override
public int getCount() {
return mFragmentList.size();
}
// 获取指定位置的标题
@Override
public CharSequence getPageTitle(int position) {
return mTitle.get(position);
}
}
}

@ -3,42 +3,41 @@ package com.example.musicplayer.app;
import android.os.Environment;
/**
* 使API
* Created by on 2018/10/26.
*/
public class Api {
//根据歌手获取歌手图片的baseUrl
public static final String SINGER_PIC_BASE_URL ="http://music.163.com/";
public static final String SINGER_PIC="api/search/get/web?csrf_token=&type=100";
//获取歌手图片需要添加user-agent的表头
public static final String HEADER_USER_AGENT="User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36";
// 根据歌手获取歌手图片的baseUrl
public static final String SINGER_PIC_BASE_URL = "http://music.163.com/";
public static final String SINGER_PIC = "api/search/get/web?csrf_token=&type=100";
// 获取歌手图片需要添加user-agent的表头
public static final String HEADER_USER_AGENT = "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36";
/**
*
*
*/
public static String STORAGE_IMG_FILE= App.getContext().getExternalFilesDir("") + "/yuanmusic/img/";
public static String STORAGE_LRC_FILE= App.getContext().getExternalFilesDir("") + "/yuanmusic/lrc/";
public static String STORAGE_SONG_FILE= Environment.getExternalStorageDirectory() + "/Sxmusic/download/";
//Fiddler抓包qq音乐网站后的地址
public static final String FIDDLER_BASE_QQ_URL ="https://c.y.qq.com/";
public static final String FIDDLER_BASE_SONG_URL="https://u.y.qq.com/"; //获取播放地址的baseUrl
//搜索功能
public static final String SEARCH_SONG ="soso/fcgi-bin/client_search_cp?n=30&format=json"; //歌曲n为一页30首
public static final String SEARCH_ALBUM="soso/fcgi-bin/client_search_cp?n=20&format=json&t=8";//专辑n为一页20张
//得到歌曲的播放地址
public static final String SONG_URL="cgi-bin/musicu.fcg?format=json";
public static final String SONG_URL_DATA_LEFT="%7B%22req_0%22%3A%7B%22module%22%3A%22vkey.GetVkeyServer%22%2C%22method%22%3A%22CgiGetVkey%22%2C%22param%22%3A%7B%22guid%22%3A%22358840384%22%2C%22songmid%22%3A%5B%22";
public static final String SONG_URL_DATA_RIGHT="%22%5D%2C%22songtype%22%3A%5B0%5D%2C%22uin%22%3A%221443481947%22%2C%22loginflag%22%3A1%2C%22platform%22%3A%2220%22%7D%7D%2C%22comm%22%3A%7B%22uin%22%3A%221443481947%22%2C%22format%22%3A%22json%22%2C%22ct%22%3A24%2C%22cv%22%3A0%7D%7D";
public static final String MP4 =".mp4";
//专辑照片
public static final String ALBUM_PIC="http://y.gtimg.cn/music/photo_new/T002R180x180M000";
public static final String JPG=".jpg";
//专辑详细
public static final String ALBUM_DETAIL="v8/fcg-bin/fcg_v8_album_info_cp.fcg?format=json";
//歌词
public static final String SONG_LRC ="soso/fcgi-bin/client_search_cp?p=1&n=30&format=json&t=7";//搜索歌词
public static final String ONLINE_SONG_LRC="https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg?format=json&nobase64=1";//根据qq音乐的mid获取歌词
public static final String HEADER_REFERER="Referer:https://y.qq.com/portal/player.html";//得到歌词需要添加Referer的表头
public static String STORAGE_IMG_FILE = App.getContext().getExternalFilesDir("") + "/yuanmusic/img/";
public static String STORAGE_LRC_FILE = App.getContext().getExternalFilesDir("") + "/yuanmusic/lrc/";
public static String STORAGE_SONG_FILE = Environment.getExternalStorageDirectory() + "/Sxmusic/download/";
}
// Fiddler抓包qq音乐网站后的地址
public static final String FIDDLER_BASE_QQ_URL = "https://c.y.qq.com/";
public static final String FIDDLER_BASE_SONG_URL = "https://u.y.qq.com/"; // 获取播放地址的baseUrl
// 搜索功能
public static final String SEARCH_SONG = "soso/fcgi-bin/client_search_cp?n=30&format=json"; // 歌曲n为一页30首
public static final String SEARCH_ALBUM = "soso/fcgi-bin/client_search_cp?n=20&format=json&t=8"; // 专辑n为一页20张
// 得到歌曲的播放地址
public static final String SONG_URL = "cgi-bin/musicu.fcg?format=json";
public static final String SONG_URL_DATA_LEFT = "%7B%22req_0%22%3A%7B%22module%22%3A%22vkey.GetVkeyServer%22%2C%22method%22%3A%22CgiGetVkey%22%2C%22param%22%3A%7B%22guid%22%3A%22358840384%22%2C%22songmid%22%3A%5B%22";
public static final String SONG_URL_DATA_RIGHT = "%22%5D%2C%22songtype%22%3A%5B0%5D%2C%22uin%22%3A%221443481947%22%2C%22loginflag%22%3A1%2C%22platform%22%3A%2220%22%7D%7D%2C%22comm%22%3A%7B%22uin%22%3A%221443481947%22%2C%22format%22%3A%22json%22%2C%22ct%22%3A24%2C%22cv%22%3A0%7D%7D";
public static final String MP4 = ".mp4";
// 专辑照片
public static final String ALBUM_PIC = "http://y.gtimg.cn/music/photo_new/T002R180x180M000";
public static final String JPG = ".jpg";
// 专辑详细
public static final String ALBUM_DETAIL = "v8/fcg-bin/fcg_v8_album_info_cp.fcg?format=json";
// 歌词
public static final String SONG_LRC = "soso/fcgi-bin/client_search_cp?p=1&n=30&format=json&t=7"; // 搜索歌词
public static final String ONLINE_SONG_LRC = "https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg?format=json&nobase64=1"; // 根据qq音乐的mid获取歌词
public static final String HEADER_REFERER = "Referer:https://y.qq.com/portal/player.html"; // 得到歌词需要添加Referer的表头
}

@ -1,5 +1,6 @@
package com.example.musicplayer.app;
// 导入所需的包和类
import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
@ -7,22 +8,30 @@ import android.content.Context;
import org.litepal.LitePal;
/**
* Context
* Context
* <p>
* Created by on 2018/7/17.
*/
public class App extends Application {
// 使用SuppressLint注解来抑制静态字段可能引起的内存泄漏警告
@SuppressLint("StaticFieldLeak")
private static Context context;
private static Context context; // 静态变量用于存储全局Context对象
/**
* ContextLitePal
*/
@Override
public void onCreate(){
super.onCreate();
context=getApplicationContext();
LitePal.initialize(this);
public void onCreate() {
super.onCreate(); // 调用父类的onCreate方法
context = getApplicationContext(); // 初始化全局Context对象
LitePal.initialize(this); // 初始化LitePal数据库
}
public static Context getContext(){
/**
* Context
* @return Context
*/
public static Context getContext() {
return context;
}
}
}

@ -1,82 +1,82 @@
package com.example.musicplayer.app;
/**
* 使
* Created by on 2018/11/23.
*/
public class Constant {
// 日志标签
public static final String TAG = "jsyjst";
// 分页加载的偏移量
public static final int OFFSET = 30;
// 类型常量,用于区分歌曲和专辑
public static final int TYPE_SONG = 1;
public static final int TYPE_ALBUM = 2;
//播放列表
public static final int LIST_TYPE_LOCAL = 1; //本地列表
public static final int LIST_TYPE_ONLINE = 2; //专辑列表
public static final int LIST_TYPE_LOVE = 3; //我的收藏列表
public static final int LIST_TYPE_HISTORY = 4; //最近播放列表
public static final int LIST_TYPE_DOWNLOAD = 5; //下载列表
// 播放列表类型
public static final int LIST_TYPE_LOCAL = 1; // 本地列表
public static final int LIST_TYPE_ONLINE = 2; // 专辑列表
public static final int LIST_TYPE_LOVE = 3; // 我的收藏列表
public static final int LIST_TYPE_HISTORY = 4; // 最近播放列表
public static final int LIST_TYPE_DOWNLOAD = 5; // 下载列表
// 搜索历史最大条目数
public static final int HISTORY_MAX_SIZE = 100;
//布局
// 布局状态常量
public static final int NORMAL_STATE = 0;
public static final int LOADING_STATE = 1;
public static final int ERROR_STATE = 2;
//playerStatus
// 播放器状态常量
public static final String PLAYER_STATUS = "PlayerStatus";
public static final int SONG_PLAY = 0;
public static final int SONG_PAUSE = 1;
public static final int SONG_RESUME = 2;
public static final int SONG_CHANGE = 3;
//KEY
// 键值对常量
public static final String ALBUM_ID_KEY = "id";
public static final String ALBUM_NAME_KEY = "albumName";
public static final String SINGER_NAME_KEY = "singerName";
public static final String ALBUM_PIC_KEY = "albumPic";
public static final String PUBLIC_TIME_KEY = "publicTime";
//TAG
// 错误标签
public static final String TAG_ERROR = "error";
//网络与非网络歌曲
// 网络与非网络歌曲标识
public static final int SONG_ONLINE = 0;
public static final int SONG_LOCAL = 1;
//后缀
// 后缀常量
public static final String LRC = ".lrc";
//音乐id
// 音乐id未找到标识
public static final String SONG_ID_UNFIND = "unFind";
//播放顺序
public static final int PLAY_ORDER = 0;//顺序播放
public static final int PLAY_SINGLE = 1;//单曲循环
public static final int PLAY_RANDOM = 2;//随机播放
// 播放顺序常量
public static final int PLAY_ORDER = 0; // 顺序播放
public static final int PLAY_SINGLE = 1; // 单曲循环
public static final int PLAY_RANDOM = 2; // 随机播放
//Preferences
// Preferences常量
public static final String SHARED_PREFERENCES_NAME = "prefs";
public static final String PREFS_PLAY_MODE = "play_mode";//播放状态
public static final String PREFS_PLAY_MODE = "play_mode"; // 播放模式
//download
// 下载状态常量
public final static int TYPE_DOWNLOADING = 0;
public final static int TYPE_DOWNLOAD_PAUSED = 1;
public final static int TYPE_DOWNLOAD_CANCELED = 2;
public final static int TYPE_DOWNLOAD_SUCCESS = 3;
public final static int TYPE_DOWNLOAD_FAILED = 4;
public final static int TYPE_DOWNLOADED = 5;
public final static int TYPE_DOWNLOAD_ADD=6;
public final static int TYPE_DOWNLOAD_ADD = 6;
//正在下载歌曲列表的状态
// 正在下载歌曲列表的状态常量
public final static int DOWNLOAD_PAUSED = 0;
public final static int DOWNLOAD_WAIT=1;
public final static int DOWNLOAD_ING=2;
public final static int DOWNLOAD_READY=3;
}
public final static int DOWNLOAD_WAIT = 1;
public final static int DOWNLOAD_ING = 2;
public final static int DOWNLOAD_READY = 3;
}

@ -1,5 +1,6 @@
package com.example.musicplayer.base.activity;
// 导入所需的包和类
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
@ -12,63 +13,68 @@ import butterknife.ButterKnife;
import butterknife.Unbinder;
/**
* <pre>
* author :
* time : 2019/07/17
* desc :
* </pre>
*
* <p>
* author :
* time : 2019/07/17
* desc :
*/
public abstract class BaseActivity extends AppCompatActivity implements BaseView {
private Unbinder mBinder;
private Unbinder mBinder; // ButterKnife绑定对象用于解绑
protected abstract int getLayoutId(); //获取布局id
protected abstract void initView(); //初始化布局
protected abstract void initData(); //初始化数据
protected abstract void onClick();//点击事件
// 获取布局id
protected abstract int getLayoutId();
// 初始化布局
protected abstract void initView();
// 初始化数据
protected abstract void initData();
// 点击事件
protected abstract void onClick();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
ButterKnife.bind(this);
initView();
initData();
onClick();
setContentView(getLayoutId()); // 设置布局
ButterKnife.bind(this); // 绑定视图
initView(); // 初始化视图
initData(); // 初始化数据
onClick(); // 点击事件
}
@Override
protected void onDestroy() {
super.onDestroy();
// 解绑ButterKnife避免内存泄漏
if(mBinder != null && mBinder != mBinder.EMPTY){
mBinder.unbind();
mBinder = null;
}
}
// 显示提示信息
@Override
public void showToast(String message) {
CommonUtil.showToast(this,message);
CommonUtil.showToast(this, message);
}
// 显示正常视图
@Override
public void showNormalView() {
}
// 显示错误视图
@Override
public void showErrorView() {
}
// 显示加载视图
@Override
public void showLoading() {
}
// 重新加载数据
@Override
public void reload() {
}
}
}

@ -3,29 +3,36 @@ package com.example.musicplayer.base.activity;
import com.example.musicplayer.base.presenter.IPresenter;
/**
* <pre>
* author :
* time : 2019/07/17
* desc :
* </pre>
* MVPActivityMVPActivity
* <p>
* author :
* time : 2019/07/17
* desc : Presenter
*/
public abstract class BaseMvpActivity<T extends IPresenter> extends BaseActivity{
public abstract class BaseMvpActivity<T extends IPresenter> extends BaseActivity {
// 抽象方法用于获取具体的Presenter实例
protected abstract T getPresenter();
// Presenter成员变量用于与View进行交互
protected T mPresenter;
/**
* Presenter
*/
@Override
protected void initView() {
mPresenter = getPresenter();
mPresenter.attachView(this);
mPresenter = getPresenter(); // 获取Presenter实例
mPresenter.attachView(this); // 将当前Activity绑定到Presenter的View
}
/**
* ActivityPresenter
*/
@Override
protected void onDestroy() {
super.onDestroy();
if(mPresenter != null){
mPresenter.detachView();
mPresenter = null;
super.onDestroy(); // 调用父类的onDestroy方法
if (mPresenter != null) {
mPresenter.detachView(); // 从Presenter解绑当前Activity的View
mPresenter = null; // 置空引用,避免内存泄漏
}
}
}
}

@ -1,5 +1,6 @@
package com.example.musicplayer.base.fragment;
// 导入所需的包和类
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
@ -16,75 +17,92 @@ import butterknife.ButterKnife;
import butterknife.Unbinder;
/**
* <pre>
* author :
* time : 2019/07/14
* desc :
* </pre>
* Fragment
* <p>
* author :
* time : 2019/07/14
* desc : FragmentFragment
*/
public abstract class BaseFragment extends BaseLazyFragment implements BaseView {
private Unbinder mBinder;
protected Activity mActivity;
protected abstract void initView(); //初始化控件
protected abstract void loadData(); //加载数据
protected abstract int getLayoutId(); //获取Fragment的布局id
private Unbinder mBinder; // ButterKnife绑定对象用于解绑
protected Activity mActivity; // 引用Activity方便调用Activity的方法
// 初始化控件的抽象方法
protected abstract void initView();
// 加载数据的抽象方法
protected abstract void loadData();
// 获取Fragment的布局id的抽象方法
protected abstract int getLayoutId();
/**
* FragmentActivityActivity
* @param context
*/
@Override
public void onAttach(Context context) {
super.onAttach(context);
mActivity = (Activity) context;
}
/**
* LayoutInflater使ButterKnife
* @param inflater
* @param container
* @param savedInstanceState
* @return Fragment
*/
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(getLayoutId(),container,false);
mBinder = ButterKnife.bind(this,view);
View view = inflater.inflate(getLayoutId(), container, false);
mBinder = ButterKnife.bind(this, view);
initView();
return view;
}
/**
* ButterKnife
*/
@Override
public void onDestroyView() {
super.onDestroyView();
if(mBinder != null && mBinder != Unbinder.EMPTY){
if (mBinder != null && mBinder != Unbinder.EMPTY) {
mBinder.unbind();
mBinder = null;
}
}
/**
* Fragment
*/
@Override
protected void lazyLoadData() {
loadData();
}
// 实现BaseView接口的方法但未具体实现子类可根据需要实现
@Override
public void showNormalView() {
}
@Override
public void showErrorView() {
}
@Override
public void showLoading() {
}
@Override
public void reload() {
}
/**
* 使CommonUtil
* @param message
*/
@Override
public void showToast(String message) {
CommonUtil.showToast(mActivity,message);
CommonUtil.showToast(mActivity, message);
}
}
}

@ -1,5 +1,6 @@
package com.example.musicplayer.base.fragment;
// 导入所需的包和类
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -8,74 +9,95 @@ import android.util.Log;
import android.view.View;
/**
* <pre>
* author :
* time : 2019/07/14
* desc : Fragment
* </pre>
* Fragment
* <p>
* author :
* time : 2019/07/14
* desc : Fragment
*/
public abstract class BaseLazyFragment extends Fragment {
private boolean isViewCreated = false;//布局是否被创建
private boolean isLoadData = false;//数据是否加载
private boolean isFirstVisible = true;//是否第一次可见
private static final String TAG = "BaseLazyFragment";
private boolean isViewCreated = false; // 标记布局是否被创建
private boolean isLoadData = false; // 标记数据是否加载
private boolean isFirstVisible = true; // 标记是否第一次可见
private static final String TAG = "BaseLazyFragment"; // 日志标签
protected abstract void lazyLoadData(); //加载数据
// 抽象方法,用于子类实现具体的懒加载数据逻辑
protected abstract void lazyLoadData();
/**
* Fragment
* @param view
* @param savedInstanceState
*/
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
isViewCreated = true;
}
/**
* FragmentFragment
* @param savedInstanceState
*/
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(isFragmentVisible(this)){
if (isFragmentVisible(this)) {
if (this.getParentFragment() == null || isFragmentVisible(this.getParentFragment())) {
Log.d(TAG, "onActivityCreated: 加载数据");
lazyLoadData();
isLoadData = true;
if(isFirstVisible) isFirstVisible = false;
if (isFirstVisible) isFirstVisible = false;
}
}
}
//在使用ViewPage时加载数据
/**
* FragmentFragment
* @param isVisibleToUser
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isFragmentVisible(this)&& !isLoadData && isViewCreated){
if (isFragmentVisible(this) && !isLoadData && isViewCreated) {
lazyLoadData();
isLoadData = true;
}
}
//调用show方法时加载数据
/**
* FragmentFragment
* @param hidden
*/
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
//onHiddenChanged调用在Resumed之前所以此时可能fragment被add, 但还没调用show方法
if(!hidden && !this.isResumed())
if (!hidden && !this.isResumed())
return;
//使用hide和show时fragment的所有生命周期方法都不会调用除了onHiddenChanged
if(!hidden && isFirstVisible){
if (!hidden && isFirstVisible) {
Log.d(TAG, "onHiddenChanged: 加载数据");
lazyLoadData();
isFirstVisible = false;
}
}
/**
* Fragment
* @param fragment Fragment
* @return
*/
private boolean isFragmentVisible(Fragment fragment){
return fragment.getUserVisibleHint()&&!fragment.isHidden();
return fragment.getUserVisibleHint() && !fragment.isHidden();
}
/**
*
*/
@Override
public void onDestroyView() {
super.onDestroyView();
isFirstVisible = true;
isLoadData = false;
isViewCreated =false;
isViewCreated = false;
}
}
}

@ -1,5 +1,6 @@
package com.example.musicplayer.base.fragment;
// 导入所需的包和类
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -16,100 +17,120 @@ import static com.example.musicplayer.app.Constant.LOADING_STATE;
import static com.example.musicplayer.app.Constant.NORMAL_STATE;
/**
* <pre>
* author :
* time : 2019/07/15
* desc :
* </pre>
* MVPFragment
* <p>
* author :
* time : 2019/07/15
* desc :
*/
public abstract class BaseLoadingFragment<T extends IPresenter> extends BaseMvpFragment<T> {
private View mNormalView; //正常布局
private View mErrorView; //错误布局
private View mLoadingView;//加载布局
private AVLoadingIndicatorView avLoadingView;
private int mCurrentState = NORMAL_STATE;//当前布局状态
private View mNormalView; // 正常布局
private View mErrorView; // 错误布局
private View mLoadingView; // 加载布局
private AVLoadingIndicatorView avLoadingView; // 加载动画视图
private int mCurrentState = NORMAL_STATE; // 当前视图状态
/**
* Fragment
* @param view
* @param savedInstanceState
*/
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if(getView() == null) return;
if (getView() == null) return;
mNormalView = view.findViewById(R.id.normalView);
if(mNormalView == null){
if (mNormalView == null) {
throw new IllegalStateException("The subclass of BaseLoadFragment must contain a View it's id is named normal_view");
}
if(!(mNormalView.getParent() instanceof ViewGroup)){
if (!(mNormalView.getParent() instanceof ViewGroup)) {
throw new IllegalStateException("mNormalView's parentView should be a ViewGroup");
}
ViewGroup parentPanel = (ViewGroup) mNormalView.getParent();
View.inflate(mActivity,R.layout.error_view,parentPanel); //加载错误布局
View.inflate(mActivity,R.layout.loading_view,parentPanel);//加载loading布局
View.inflate(mActivity, R.layout.error_view, parentPanel); // 加载错误布局
View.inflate(mActivity, R.layout.loading_view, parentPanel); // 加载加载布局
mLoadingView = parentPanel.findViewById(R.id.loadingView);
avLoadingView = parentPanel.findViewById(R.id.avLoading);
mErrorView = parentPanel.findViewById(R.id.errorView);
TextView reloadBtn = parentPanel.findViewById(R.id.reloadBtn);
reloadBtn.setOnClickListener(view1 -> reload()); //重新加载
reloadBtn.setOnClickListener(view1 -> reload()); // 设置重新加载按钮的点击事件
mNormalView.setVisibility(View.VISIBLE);
mErrorView.setVisibility(View.GONE);
mLoadingView.setVisibility(View.GONE);
}
/**
*
*/
@Override
public void showNormalView() {
super.showNormalView();
if(mCurrentState == NORMAL_STATE) return;
if (mCurrentState == NORMAL_STATE) return;
hideViewByState(mCurrentState);
mCurrentState = NORMAL_STATE;
showViewByState(mCurrentState);
}
/**
*
*/
@Override
public void showErrorView() {
super.showErrorView();
if(mCurrentState == ERROR_STATE) return;
if (mCurrentState == ERROR_STATE) return;
hideViewByState(mCurrentState);
mCurrentState = ERROR_STATE;
showViewByState(mCurrentState);
}
/**
*
*/
@Override
public void showLoading() {
super.showLoading();
if(mCurrentState == LOADING_STATE) return;
if (mCurrentState == LOADING_STATE) return;
hideViewByState(mCurrentState);
mCurrentState = LOADING_STATE;
showViewByState(mCurrentState);
}
private void hideViewByState(int state){
if(state == NORMAL_STATE){
if(mNormalView == null) return;
/**
*
* @param state
*/
private void hideViewByState(int state) {
if (state == NORMAL_STATE) {
if (mNormalView == null) return;
mNormalView.setVisibility(View.GONE);
}else if(state == LOADING_STATE){
if(mLoadingView == null||avLoadingView == null) return;
mLoadingView.setVisibility(View.GONE);
}else {
if(mErrorView == null ) return;
} else if (state == LOADING_STATE) {
if (mLoadingView == null || avLoadingView == null) return;
mLoadingView.setVisibility(View.GONE);
} else {
if (mErrorView == null) return;
mErrorView.setVisibility(View.GONE);
}
}
private void showViewByState(int state){
if(state == NORMAL_STATE){
if(mNormalView == null) return;
/**
*
* @param state
*/
private void showViewByState(int state) {
if (state == NORMAL_STATE) {
if (mNormalView == null) return;
mNormalView.setVisibility(View.VISIBLE);
}else if(state == LOADING_STATE){
if(mLoadingView == null||avLoadingView == null) return;
} else if (state == LOADING_STATE) {
if (mLoadingView == null || avLoadingView == null) return;
mLoadingView.setVisibility(View.VISIBLE);
avLoadingView.show();
}else {
if(mErrorView == null ) return;
avLoadingView.show(); // 显示加载动画
} else {
if (mErrorView == null) return;
mErrorView.setVisibility(View.VISIBLE);
}
}
}
}

@ -1,31 +1,39 @@
package com.example.musicplayer.base.fragment;
// 导入所需的包和类
import com.example.musicplayer.base.presenter.IPresenter;
/**
* <pre>
* author :
* time : 2019/07/14
* desc : MvpFragment
* </pre>
* MVPFragment
* <p>
* author :
* time : 2019/07/14
* desc : PresenterMVPFragment
*/
public abstract class BaseMvpFragment<T extends IPresenter> extends BaseFragment {
// 抽象方法用于获取具体的Presenter实例
protected abstract T getPresenter();
// Presenter成员变量用于与View进行交互
protected T mPresenter;
/**
* Presenter
*/
@Override
protected void initView() {
mPresenter = getPresenter();
mPresenter.attachView(this);
mPresenter = getPresenter(); // 获取Presenter实例
mPresenter.attachView(this); // 将当前Fragment绑定到Presenter的View
}
/**
* FragmentPresenter
*/
@Override
public void onDestroy() {
if(mPresenter != null){
mPresenter.detachView();
mPresenter = null;
if (mPresenter != null) {
mPresenter.detachView(); // 从Presenter解绑当前Fragment的View
mPresenter = null; // 置空引用,避免内存泄漏
}
super.onDestroy();
super.onDestroy(); // 调用父类的onDestroy方法
}
}
}

@ -1,5 +1,6 @@
package com.example.musicplayer.base.observer;
// 导入所需的包和类
import android.net.ParseException;
import android.os.Handler;
import android.util.Log;
@ -19,57 +20,69 @@ import retrofit2.HttpException;
import static com.example.musicplayer.app.Constant.TAG_ERROR;
/**
* <pre>
* author :
* time : 2019/07/16
* desc : RxJava
* </pre>
* RxJava
* <p>
* author :
* time : 2019/07/16
* desc :
*/
public class BaseObserver<T> extends ResourceObserver<T> {
private static final String TAG = "BaseObserver";
private boolean isShowLoadingView = true;
private boolean isShowErrorView =true;
private static final String TAG = "BaseObserver"; // 日志标签
private boolean isShowLoadingView = true; // 是否显示加载视图
private boolean isShowErrorView = true; // 是否显示错误视图
private BaseView baseView;
private BaseView baseView; // 基础视图接口用于更新UI
private BaseObserver(){}
// 私有构造函数,防止直接实例化
private BaseObserver() {}
protected BaseObserver(BaseView baseView){
this(baseView,false,false);
// 构造函数初始化BaseView
protected BaseObserver(BaseView baseView) {
this(baseView, false, false);
}
protected BaseObserver(BaseView baseView,boolean isShowLoadingView){
this(baseView,isShowLoadingView,false);
// 构造函数初始化BaseView和是否显示加载视图
protected BaseObserver(BaseView baseView, boolean isShowLoadingView) {
this(baseView, isShowLoadingView, false);
}
protected BaseObserver(BaseView baseView,boolean isShowLoadingView, boolean isShowErrorView){
// 构造函数初始化BaseView、是否显示加载视图和是否显示错误视图
protected BaseObserver(BaseView baseView, boolean isShowLoadingView, boolean isShowErrorView) {
this.baseView = baseView;
this.isShowLoadingView = isShowLoadingView;
this.isShowErrorView = isShowErrorView;
}
/**
*
*/
@Override
protected void onStart() {
if(isShowLoadingView) baseView.showLoading();
if (isShowLoadingView) baseView.showLoading();
}
/**
*
* @param t
*/
@Override
public void onNext(T t) {
new Handler().postDelayed(()->{
new Handler().postDelayed(() -> {
baseView.showNormalView();
},500);
}, 500);
}
/**
*
* @param e
*/
@Override
public void onError(Throwable e) {
new Handler().postDelayed(()->{
if(isShowErrorView) baseView.showErrorView();
},500);
new Handler().postDelayed(() -> {
if (isShowErrorView) baseView.showErrorView();
}, 500);
e.printStackTrace();
// 处理不同类型的异常
if (e instanceof UnknownHostException) {
Log.e(TAG_ERROR, "networkError" + e.getMessage());
networkError();
@ -82,50 +95,51 @@ public class BaseObserver<T> extends ResourceObserver<T> {
} else if (e instanceof JsonParseException || e instanceof JSONException || e instanceof ParseException) {
Log.e(TAG_ERROR, "解析错误:" + e.getMessage());
parseError();
}else {
} else {
Log.e(TAG_ERROR, "未知错误:" + e.getMessage());
unknown();
}
}
/**
*
*/
@Override
public void onComplete() {
}
/**
*
*
*/
protected void unknown() {
baseView.showToast(App.getContext().getString(R.string.error_unknown));
}
/**
*
*
*/
protected void parseError() {
baseView.showToast(App.getContext().getString(R.string.error_parse));
}
/**
* http
* HTTP
*/
protected void httpError() {
baseView.showToast(App.getContext().getString(R.string.error_http));
}
/**
*
*
*/
protected void timeoutError() {
baseView.showToast(App.getContext().getString(R.string.error_timeout));
}
/**
*
*
*/
protected void networkError() {
baseView.showToast(App.getContext().getString(R.string.error_network));
}
}
}

@ -1,63 +1,76 @@
package com.example.musicplayer.base.presenter;
import android.provider.ContactsContract;
// 导入所需的包和类
import com.example.musicplayer.base.view.BaseView;
import com.example.musicplayer.model.DataModel;
import com.example.musicplayer.model.db.DbHelperImpl;
import com.example.musicplayer.model.https.NetworkHelperImpl;
import com.example.musicplayer.model.https.RetrofitFactory;
import com.example.musicplayer.model.prefs.PreferencesHelperImpl;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
/**
* <pre>
* author :
* time : 2019/07/14
* desc :
* </pre>
* MVPPresenter
* <p>
* author :
* time : 2019/07/14
* desc : PresenterRxJava
*/
public class BasePresenter<T extends BaseView> implements IPresenter<T> {
public class BasePresenter<T extends BaseView> implements IPresenter<T>{
protected T mView;
protected DataModel mModel;
protected T mView; // 用于与视图层交互的接口
protected DataModel mModel; // 数据模型,用于处理数据逻辑
//得到model
public BasePresenter(){
if(mModel == null){
mModel = new DataModel(new NetworkHelperImpl(RetrofitFactory.createRequest()),new DbHelperImpl(),new PreferencesHelperImpl());
// 构造函数初始化DataModel
public BasePresenter() {
if (mModel == null) {
mModel = new DataModel(new NetworkHelperImpl(RetrofitFactory.createRequest()),
new DbHelperImpl(), new PreferencesHelperImpl());
}
}
private CompositeDisposable mCompositeDisposable;
private CompositeDisposable mCompositeDisposable; // RxJava订阅容器
/**
* Presenter
* @param view
*/
@Override
public void attachView(T view) {
mView = view;
}
/**
* Presenter
* @return
*/
@Override
public boolean isAttachView() {
return mView != null;
}
//在presenter与View解除时将订阅事件切断
/**
* PresenterRxJava
*/
@Override
public void detachView() {
mView = null;
//清除
if(mCompositeDisposable != null){
// 清除所有的RxJava订阅
if (mCompositeDisposable != null) {
mCompositeDisposable.clear();
}
}
//网络请求时将订阅事件添加到容器中
/**
* RxJava便
* @param disposable RxJava
*/
@Override
public void addRxSubscribe(Disposable disposable) {
if(mCompositeDisposable == null){
if (mCompositeDisposable == null) {
mCompositeDisposable = new CompositeDisposable();
}
mCompositeDisposable.add(disposable);
}
}
}

@ -1,20 +1,41 @@
package com.example.musicplayer.base.presenter;
// 导入所需的包和类
import com.example.musicplayer.base.view.BaseView;
import io.reactivex.disposables.Disposable;
/**
* <pre>
* author :
* time : 2019/07/14
* desc : Presenter
* </pre>
* PresenterMVP
* <p>
* author :
* time : 2019/07/14
* desc : PresenterPresenter
*/
public interface IPresenter<T extends BaseView> {
void attachView(T view); //注入View
boolean isAttachView(); //判断是否注入View
void detachView(); //解除View
void addRxSubscribe(Disposable disposable);//添加订阅者
}
/**
* ViewPresenter
* MVPViewPresenterViewonCreate
* @param view BaseView
*/
void attachView(T view);
/**
* Presenter
* UIViewPresenterView
* @return trueViewfalseView
*/
boolean isAttachView();
/**
* PresenterView
* MVPViewPresenterViewonDestroy
*/
void detachView();
/**
* RxJavaDisposable
* RxJava
* @param disposable
*/
void addRxSubscribe(Disposable disposable);
}

@ -1,17 +1,41 @@
package com.example.musicplayer.base.view;
/**
* <pre>
* author :
* time : 2019/07/14
* desc :
* </pre>
* ViewMVP
* <p>
* author :
* time : 2019/07/14
* desc :
*/
public interface BaseView {
void showNormalView(); //正常布局
void showErrorView(); //错误布局
void showLoading();//加载布局
void reload();//重新加载
void showToast(String message);//显示Toast
}
/**
*
*
*/
void showNormalView();
/**
*
*
*/
void showErrorView();
/**
*
*
*/
void showLoading();
/**
*
*
*/
void reload();
/**
* Toast
*
* @param message
*/
void showToast(String message);
}
Loading…
Cancel
Save