Compare commits

...

44 Commits
master ... pl

Author SHA1 Message Date
px4lqzo5h eacc7f777e Update AlbumCollection.java
1 year ago
px4lqzo5h 2be2f5ffc4 Update Album.java
1 year ago
px4lqzo5h 1bc1217bd6 Update DownloadTask.java
1 year ago
px4lqzo5h 80bb935f99 Update DownloadListener.java
1 year ago
px4lqzo5h 699d126fca Update ISearchContentContract.java
1 year ago
px4lqzo5h 2150764734 Update IPlayContract.java
1 year ago
px4lqzo5h 724c8d7c27 Update ILocalContract.java
1 year ago
px4lqzo5h a9162c44e5 Update IAlbumSongContract.java
1 year ago
px4lqzo5h e3c253dfa1 Update OnAlbumItemClickListener.java
1 year ago
px4lqzo5h 8274a4c749 Update OnItemClickListener.java
1 year ago
px4lqzo5h d76aee099e Update OnFooterClickListener.java
1 year ago
px4lqzo5h 77d357dcf7 Update OnDeleteClickListener.java
1 year ago
px4lqzo5h d87d518afd Update OnChildItemClickListener.java
1 year ago
px4lqzo5h 9c93671b4e Update OnAlbumItemClickListener.java
1 year ago
px4lqzo5h 59bc5b2e66 Update BaseView.java
1 year ago
px4lqzo5h 4cd81a0c5a Update IPresenter.java
1 year ago
px4lqzo5h 40f8653936 Update BasePresenter.java
1 year ago
px4lqzo5h 3e0110c0d7 Update BaseObserver.java
1 year ago
px4lqzo5h e0f3d3d12a Update BaseMvpFragment.java
1 year ago
px4lqzo5h 499c0a3d9f Update BaseLoadingFragment.java
1 year ago
px4lqzo5h a31b670034 Update BaseLazyFragment.java
1 year ago
px4lqzo5h 1d456e9524 Update BaseFragment.java
1 year ago
px4lqzo5h e0d78047b1 Update BaseMvpActivity.java
1 year ago
px4lqzo5h 33250edf2b Update BaseActivity.java
1 year ago
px4lqzo5h f7cd60a538 Update Constant.java
1 year ago
px4lqzo5h 3f9d46f959 Update App.java
1 year ago
px4lqzo5h 360b162e12 Update Api.java
1 year ago
px4lqzo5h 1c859d3c7d Update TabAdapter.java
1 year ago
px4lqzo5h 553b9e2a31 Update SongAdapter.java
1 year ago
px4lqzo5h 15e1422ddb Update SearchHistoryAdapter.java
1 year ago
px4lqzo5h 010e20197b Update SearchContentAdapter.java
1 year ago
px4lqzo5h 2b8deb5a5f Update LoveSongAdapter.java
1 year ago
px4lqzo5h 17c34ce361 Update Project_Default.xml
1 year ago
px4lqzo5h 83c3671cce Update litepal.xml
1 year ago
px4lqzo5h f05009d744 Update litepal.xml
1 year ago
px4lqzo5h 64d67980e4 Update Project_Default.xml
1 year ago
px4lqzo5h 4e29230c77 Update litepal.xml
1 year ago
px4lqzo5h 1dc95f7c78 Update HistoryAdapter.java
1 year ago
px4lqzo5h 8cb36b3256 Update ExpandableListViewAdapter.java
1 year ago
px4lqzo5h 5838e1dbfe Update DownloadingAdapter.java
1 year ago
px4lqzo5h f61e67b728 Update DownloadSongAdapter.java
1 year ago
px4lqzo5h 3ded1fe82f Update AlbumSongAdapter.java
1 year ago
px4lqzo5h 48515ed1d8 Update ExampleInstrumentedTest.java
1 year ago
px4lqzo5h 73c39b8b95 Update ExampleInstrumentedTest.java
1 year ago

@ -7,20 +7,28 @@ import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* ExampleInstrumentedTest AndroidJUnit4 Android
* <p>
* useAppContext
* <p>
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
* Android访
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
/**
* useAppContext
*
* @throws Exception
*/
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
// 获取当前测试的应用程序的上下文环境
Context appContext = InstrumentationRegistry.getTargetContext();
// 断言测试的应用程序的包名是否为 "com.example.musicplayer"
// 如果包名不匹配,则测试失败,并抛出异常
assertEquals("com.example.musicplayer", appContext.getPackageName());
}
}
}

@ -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>

@ -17,34 +17,53 @@ import com.example.musicplayer.util.FileUtil;
import java.util.List;
/**
* Created by on 2018/11/27.
* AlbumSongAdapter RecyclerView.Adapter
*/
public class AlbumSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
// 歌曲数据列表
private List<AlbumSong.DataBean.ListBean> mSongsBeanList;
// 上一个被点击的位置
private int mLastPosition = -1;
// 点击事件的监听器
private OnItemClickListener mSongClick;
// 歌曲项的视图类型
private final int songType = 1;
// 底部视图的类型
private final int footerType = 2;
/**
*
* @param songsBeans
*/
public AlbumSongAdapter(List<AlbumSong.DataBean.ListBean> songsBeans) {
mSongsBeanList = songsBeans;
}
/**
*
* @param songClick
*/
public void setSongClick(OnItemClickListener songClick) {
mSongClick = songClick;
}
/**
* ViewHolder
* @param parent
* @param viewType
* @return ViewHolder
*/
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// 根据视图类型创建不同的ViewHolder
if (viewType == songType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_song_search_item, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}else{
} else {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.footer_view_player_height, parent, false);
FooterHolder footerHolder = new FooterHolder(view);
@ -52,12 +71,18 @@ public class AlbumSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
}
}
/**
* ViewHolder
* @param viewHolder ViewHolder
* @param position
*/
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, final int position) {
// 如果是歌曲类型的ViewHolder
if (viewHolder instanceof ViewHolder) {
ViewHolder holder = (ViewHolder) viewHolder;
AlbumSong.DataBean.ListBean songsBean = mSongsBeanList.get(position);
//设置歌手,因为歌手可能有两个
// 设置歌手名称,可能包含多个歌手
StringBuilder singer = new StringBuilder(songsBean.getSinger().get(0).getName());
for (int i = 1; i < songsBean.getSinger().size(); i++) {
singer.append("、").append(songsBean.getSinger().get(i).getName());
@ -65,8 +90,8 @@ public class AlbumSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
holder.artistTv.setText(singer.toString());
holder.titleTv.setText(songsBean.getSongname());
holder.mItemView.setBackgroundResource(R.color.translucent);
//根据点击显示
if(songsBean.getSongmid().equals(FileUtil.getSong().getSongId())){
// 根据当前播放的歌曲设置不同的显示效果
if(songsBean.getSongmid().equals(FileUtil.getSong().getSongId())){
holder.playLine.setVisibility(View.VISIBLE);
holder.titleTv.setTextColor(App.getContext().getResources().getColor(R.color.yellow));
holder.artistTv.setTextColor(App.getContext().getResources().getColor(R.color.yellow));
@ -76,6 +101,7 @@ public class AlbumSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
holder.titleTv.setTextColor(App.getContext().getResources().getColor(R.color.white));
holder.artistTv.setTextColor(App.getContext().getResources().getColor(R.color.white_blue));
}
// 设置点击事件
holder.mItemView.setOnRippleCompleteListener(rippleView -> {
mSongClick.onClick(position);
equalPosition(position);
@ -83,18 +109,29 @@ public class AlbumSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
}
}
/**
*
* @return
*/
@Override
public int getItemCount() {
return mSongsBeanList.size() + 1;
}
/**
*
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
return position + 1 == getItemCount() ? footerType : songType;
}
/**
* ViewHolder
*/
class ViewHolder extends RecyclerView.ViewHolder {
TextView titleTv;
TextView artistTv;
RippleView mItemView;
@ -109,13 +146,19 @@ public class AlbumSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
}
}
/**
* FooterHolder
*/
class FooterHolder extends RecyclerView.ViewHolder {
FooterHolder(View itemView) {
super(itemView);
}
}
//判断点击的是否为上一个点击的项目
/**
*
* @param position
*/
private void equalPosition(int position) {
if (position != mLastPosition) {
if (mLastPosition != -1) notifyItemChanged(mLastPosition);
@ -123,4 +166,4 @@ public class AlbumSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
}
notifyItemChanged(position);
}
}
}

@ -17,6 +17,7 @@ import com.example.musicplayer.util.FileUtil;
import java.util.List;
/**
* DownloadSongAdapter RecyclerView.Adapter
* <pre>
* author :
* time : 2019/09/18
@ -25,30 +26,52 @@ import java.util.List;
*/
public class DownloadSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
// 用于日志记录的标签
private static final String TAG = "LoveSongAdapter";
// 底部视图类型
private int footerViewType = 1;
// 歌曲项视图类型
private int itemViewType = 0;
// 已下载歌曲的数据列表
private List<DownloadSong> mDownloadSongList;
// 上下文环境
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 DownloadSongAdapter(Context context, List<DownloadSong> loveList) {
mContext = context;
mDownloadSongList = loveList;
}
/**
* ViewHolder
*/
class ViewHolder extends RecyclerView.ViewHolder {
TextView songNameTv;
TextView singerTv;
View playLine;
RippleView item;
/**
*
* @param itemView
*/
public ViewHolder(View itemView) {
super(itemView);
songNameTv = itemView.findViewById(R.id.tv_title);
@ -59,21 +82,31 @@ public class DownloadSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
}
/**
* holder
* FooterHolder
*/
static class FooterHolder extends RecyclerView.ViewHolder {
TextView numTv;
/**
*
* @param itemView
*/
public FooterHolder(View itemView) {
super(itemView);
numTv = itemView.findViewById(R.id.tv_song_num);
}
}
/**
* ViewHolder
* @param parent
* @param viewType
* @return ViewHolder
*/
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// 根据视图类型创建不同的ViewHolder
if (viewType == itemViewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_song_search_item, parent, false);
@ -87,15 +120,21 @@ public class DownloadSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
}
}
/**
* ViewHolder
* @param viewHolder ViewHolder
* @param position
*/
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
// 如果是歌曲类型的ViewHolder
if (viewHolder instanceof ViewHolder) {
ViewHolder holder = (ViewHolder) viewHolder;
final DownloadSong downloadSong = mDownloadSongList.get(position);
holder.songNameTv.setText(downloadSong.getName());
holder.singerTv.setText(downloadSong.getSinger());
//根据点击显示
// 根据当前播放的歌曲设置不同的显示效果
if (downloadSong.getSongId().equals(FileUtil.getSong().getSongId())) {
holder.playLine.setVisibility(View.VISIBLE);
mLastPosition = position;
@ -117,12 +156,16 @@ public class DownloadSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
equalPosition(position);
});
} else {
// 如果是底部视图的ViewHolder
FooterHolder footerHolder = (FooterHolder) viewHolder;
footerHolder.numTv.setText("共" + mDownloadSongList.size() + "首音乐");
}
}
//判断点击的是否为上一个点击的项目
/**
*
* @param position
*/
public void equalPosition(int position) {
if (position != mLastPosition) {
notifyItemChanged(mLastPosition);
@ -131,13 +174,22 @@ public class DownloadSongAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
notifyItemChanged(position);
}
/**
*
* @return
*/
@Override
public int getItemCount() {
return mDownloadSongList.size() + 1;
}
/**
*
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
return position + 1 == getItemCount() ? footerViewType : itemViewType;
}
}
}

@ -20,6 +20,7 @@ import com.example.musicplayer.util.MediaUtil;
import java.util.List;
/**
* DownloadingAdapter RecyclerView.Adapter
* <pre>
* author :
* time : 2019/09/17
@ -28,25 +29,40 @@ import java.util.List;
*/
public class DownloadingAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
// 正在下载的歌曲信息列表
private List<DownloadInfo> downloadInfoList;
// 项点击事件监听器
private OnItemClickListener onItemClickListener;
// 删除点击事件监听器
private OnDeleteClickListener onDeleteClickListener;
/**
*
* @param onDeleteClickListener
*/
public void setOnDeleteClickListener(OnDeleteClickListener onDeleteClickListener){
this.onDeleteClickListener = onDeleteClickListener;
}
/**
*
* @param onItemClickListener
*/
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
/**
*
* @param downloadInfoList
*/
public DownloadingAdapter(List<DownloadInfo> downloadInfoList) {
this.downloadInfoList = downloadInfoList;
}
/**
* ViewHolder
*/
class ViewHolder extends RecyclerView.ViewHolder {
TextView songTv;
TextView sizeTv;
@ -54,6 +70,10 @@ public class DownloadingAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
View itemView;
ImageView cancelTv;
/**
*
* @param itemView
*/
public ViewHolder(@NonNull View itemView) {
super(itemView);
this.itemView = itemView;
@ -64,23 +84,34 @@ public class DownloadingAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
}
}
/**
* ViewHolder
* @param viewGroup
* @param viewType
* @return ViewHolder
*/
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.recycler_downing_item, viewGroup, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
/**
* ViewHolder
* @param viewHolder ViewHolder
* @param position
*/
@SuppressLint({"SetTextI18n", "ClickableViewAccessibility"})
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
ViewHolder holder = (ViewHolder) viewHolder;
if (downloadInfoList.size() == 0) return;
DownloadInfo downloadInfo = downloadInfoList.get(i);
DownloadInfo downloadInfo = downloadInfoList.get(position);
holder.songTv.setText(downloadInfo.getSongName());
// 根据下载状态设置不同的显示内容
if(downloadInfo.getStatus() == Constant.DOWNLOAD_READY){//准备开始下载
holder.sizeTv.setText("正在获取歌曲大小");
holder.seekBar.setVisibility(View.GONE);
@ -99,18 +130,20 @@ public class DownloadingAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
}
holder.seekBar.setOnTouchListener((view, motionEvent) -> true); //消费该事件让seekBar不能拖动和点击
holder.seekBar.setProgress(downloadInfo.getProgress());
//点击事件
// 设置点击事件
holder.itemView.setOnClickListener(view -> {
onItemClickListener.onClick(i);
onItemClickListener.onClick(position);
});
//取消
holder.cancelTv.setOnClickListener(view -> onDeleteClickListener.onClick(i));
// 设置取消按钮点击事件
holder.cancelTv.setOnClickListener(view -> onDeleteClickListener.onClick(position));
}
/**
*
* @return
*/
@Override
public int getItemCount() {
return downloadInfoList.size();
}
}
}

@ -17,64 +17,80 @@ import com.example.musicplayer.util.CommonUtil;
import java.util.List;
/**
*
*
* Created by on 2018/9/23.
*/
public class ExpandableListViewAdapter extends BaseExpandableListAdapter {
private static final String TAG = "ExpandableListViewAdapter";
private String[] mGroupStrings; //一级标题
private List<List<AlbumCollection>> mAlbumCollectionList; //二级收藏歌单列表
private Context mContext;
private OnChildItemClickListener mChildClickListener; //二级item的点击监听
private String[] mGroupStrings; // 一级标题数组
private List<List<AlbumCollection>> mAlbumCollectionList; // 二级歌单列表
private Context mContext; // 上下文环境
private OnChildItemClickListener mChildClickListener; // 二级项的点击监听器
/**
*
* @param context
* @param groupStrings
* @param albumCollectionList
*/
public ExpandableListViewAdapter(Context context, String[] groupStrings, List<List<AlbumCollection>> albumCollectionList) {
mAlbumCollectionList = albumCollectionList;
mGroupStrings = groupStrings;
mContext = context;
}
//提供给外部使用
public void setOnChildItemClickListener(OnChildItemClickListener onChildItemClickListener){
mChildClickListener=onChildItemClickListener;
/**
*
* @param onChildItemClickListener
*/
public void setOnChildItemClickListener(OnChildItemClickListener onChildItemClickListener){
mChildClickListener = onChildItemClickListener;
}
// 获取一级列表的组数
@Override
public int getGroupCount() {
return mGroupStrings.length;
}
// 获取指定组的子项数
@Override
public int getChildrenCount(int groupPosition) {
return mAlbumCollectionList.get(groupPosition).size();
}
// 获取指定组的对象
@Override
public Object getGroup(int groupPosition) {
return mGroupStrings[groupPosition];
}
// 获取指定子项的对象
@Override
public Object getChild(int groupPosition, int childPosition) {
return mAlbumCollectionList.get(groupPosition).get(childPosition);
}
// 获取指定组的ID
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
// 获取指定子项的ID
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
// 是否有稳定的ID
@Override
public boolean hasStableIds() {
return true;
}
//绘制一级列表
// 绘制一级列表
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
View view;
@ -90,7 +106,7 @@ public class ExpandableListViewAdapter extends BaseExpandableListAdapter {
groupViewHolder = (GroupViewHolder) view.getTag();
}
groupViewHolder.groupTextView.setText(mGroupStrings[groupPosition]);
//根据展开状态改变箭头方向
// 根据展开状态改变箭头方向
if (isExpanded) {
groupViewHolder.pointIv.setImageResource(R.drawable.up);
} else {
@ -99,8 +115,7 @@ public class ExpandableListViewAdapter extends BaseExpandableListAdapter {
return view;
}
//绘制二级列表
// 绘制二级列表项
@Override
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View view;
@ -122,26 +137,28 @@ public class ExpandableListViewAdapter extends BaseExpandableListAdapter {
childViewHolder.authorTv.setText(mAlbumCollectionList.get(groupPosition).get(childPosition).getSingerName());
CommonUtil.setImgWithGlide(mContext,
mAlbumCollectionList.get(groupPosition).get(childPosition).getAlbumPic(), childViewHolder.faceIv);
//点击水波纹效果,结束后开始点击效果
childViewHolder.childView.setOnRippleCompleteListener(rippleView -> mChildClickListener.onClick(groupPosition,childPosition));
// 点击水波纹效果,结束后开始点击效果
childViewHolder.childView.setOnRippleCompleteListener(rippleView -> mChildClickListener.onClick(groupPosition, childPosition));
return view;
}
// 是否可以选择子项
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
// 一级列表项的ViewHolder
class GroupViewHolder {
private TextView groupTextView;
private ImageView pointIv;
}
// 二级列表项的ViewHolder
class ChildViewHolder {
TextView albumNameTv;
ImageView faceIv;
TextView authorTv;
RippleView childView;
}
}
}

@ -19,35 +19,49 @@ import com.example.musicplayer.util.FileUtil;
import java.util.List;
/**
* HistoryAdapter RecyclerView.Adapter
* Created by on 2018/12/2.
*/
public class HistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = "HistoryAdapter";
private int footerViewType = 1;
private int itemViewType = 0;
private List<HistorySong> mHistoryList;
private Context mContext;
private int mLastPosition = -1;
private OnItemClickListener onItemClickListener;
private int footerViewType = 1; // 底部视图类型标识
private int itemViewType = 0; // 列表项视图类型标识
private List<HistorySong> mHistoryList; // 播放历史歌曲列表
private Context mContext; // 上下文环境
private int mLastPosition = -1; // 上一个被点击的位置
private OnItemClickListener onItemClickListener; // 点击事件监听器
/**
*
* @param onItemClickListener
*/
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
/**
*
* @param context
* @param historyList
*/
public HistoryAdapter(Context context, List<HistorySong> historyList) {
mContext = context;
mHistoryList =historyList;
mHistoryList = historyList;
}
/**
* ViewHolder
*/
class ViewHolder extends RecyclerView.ViewHolder {
TextView songNameTv;
TextView singerTv;
RippleView mItemView;
View playLine;
TextView songNameTv; // 歌曲名称
TextView singerTv; // 歌手名称
RippleView mItemView; // 带有水波纹效果的视图
View playLine; // 播放线条,表示当前播放的歌曲
/**
*
* @param itemView
*/
public ViewHolder(View itemView) {
super(itemView);
songNameTv = itemView.findViewById(R.id.tv_title);
@ -58,18 +72,27 @@ public class HistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
}
/**
* holder
* FooterHolder
*/
static class FooterHolder extends RecyclerView.ViewHolder {
TextView numTv; // 底部提示文本
TextView numTv;
/**
*
* @param itemView
*/
public FooterHolder(View itemView) {
super(itemView);
numTv = itemView.findViewById(R.id.tv_song_num);
}
}
/**
* ViewHolder
* @param parent
* @param viewType
* @return ViewHolder
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == itemViewType) {
@ -85,6 +108,11 @@ public class HistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
}
}
/**
* ViewHolder
* @param viewHolder ViewHolder
* @param position
*/
@SuppressLint("SetTextI18n")
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
@ -94,10 +122,10 @@ public class HistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
holder.songNameTv.setText(history.getName());
holder.singerTv.setText(history.getSinger());
//根据点击显示
// 根据当前播放的歌曲设置不同的显示效果
if(history.getSongId().equals(FileUtil.getSong().getSongId())){
holder.playLine.setVisibility(View.VISIBLE);
mLastPosition =position;
mLastPosition = position;
holder.songNameTv.setTextColor(mContext.getResources()
.getColor(R.color.yellow));
holder.singerTv.setTextColor(mContext.getResources()
@ -119,7 +147,10 @@ public class HistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
}
}
//判断点击的是否为上一个点击的项目
/**
*
* @param position
*/
public void equalPosition(int position) {
if (position != mLastPosition) {
notifyItemChanged(mLastPosition);
@ -128,13 +159,22 @@ public class HistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
notifyItemChanged(position);
}
/**
*
* @return
*/
@Override
public int getItemCount() {
return mHistoryList.size() + 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.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);
}

@ -1,9 +1,22 @@
package com.example.musicplayer.callback;
/**
* Created by on 2018/12/6.
*
* <p>
*
* <p>
* author :
* time : 2018/12/6
* desc :
*/
public interface OnAlbumItemClickListener {
/**
*
* <p>
*
*
*
* @param position
*/
void onClick(int position);
}
}

@ -1,9 +1,17 @@
package com.example.musicplayer.callback;
/**
* Created by on 2018/12/6.
*
* <p>
* author :
* time : 2018/12/6
* desc :
*/
public interface OnChildItemClickListener{
void onClick(int groupPosition,int childPosition);
}
public interface OnChildItemClickListener {
/**
*
* @param groupPosition
* @param childPosition
*/
void onClick(int groupPosition, int childPosition);
}

@ -1,9 +1,16 @@
package com.example.musicplayer.callback;
/**
* Created by on 2018/12/6.
*
* <p>
* author :
* time : 2018/12/6
* desc :
*/
public interface OnDeleteClickListener{
public interface OnDeleteClickListener {
/**
*
* @param position
*/
void onClick(int position);
}
}

@ -1,9 +1,15 @@
package com.example.musicplayer.callback;
/**
* Created by on 2018/12/6.
*
* <p>
* author :
* time : 2018/12/6
* desc :
*/
public interface OnFooterClickListener{
public interface OnFooterClickListener {
/**
*
*/
void onClick();
}
}

@ -1,9 +1,16 @@
package com.example.musicplayer.callback;
/**
* Created by on 2018/12/6.
*
* <p>
* author :
* time : 2018/12/6
* desc :
*/
public interface OnItemClickListener {
/**
*
* @param position
*/
void onClick(int position);
}
}

@ -1,29 +1,76 @@
package com.example.musicplayer.contract;
// 导入所需的包和类
import com.example.musicplayer.base.presenter.IPresenter;
import com.example.musicplayer.base.view.BaseView;
import com.example.musicplayer.entiy.AlbumSong;
import java.util.ArrayList;
import java.util.List;
/**
* Created by on 2018/11/27.
* (View) presenter
* <p>
* author :
* time : 2018/11/27
* desc : presenter
*/
public interface IAlbumSongContract {
/**
* (View)
*/
interface View extends BaseView {
void setAlbumSongList(List<AlbumSong.DataBean.ListBean> dataBean); //成功获取专辑歌曲后填充列表
void showAlbumSongError();//获取专辑失败
void showAlbumMessage(String name,String language,String company,String albumType,String desc); //展示专辑详细
void showLoading(); //显示进度
void hideLoading(); //隐藏进度
void showNetError(); //显示网络错误
/**
*
* @param dataBean
*/
void setAlbumSongList(List<AlbumSong.DataBean.ListBean> dataBean);
/**
*
*/
void showAlbumSongError();
/**
*
* @param name
* @param language
* @param company
* @param albumType
* @param desc
*/
void showAlbumMessage(String name, String language, String company, String albumType, String desc);
/**
*
*/
void showLoading();
/**
*
*/
void hideLoading();
/**
*
*/
void showNetError();
}
/**
* presenter
*/
interface Presenter extends IPresenter<View> {
void getAlbumDetail(String id,int type); //获取专辑的更多信息
void insertAllAlbumSong(List<AlbumSong.DataBean.ListBean> dataBean); //将专辑歌曲添加到数据库
/**
*
* @param id ID
* @param type
*/
void getAlbumDetail(String id, int type);
/**
*
* @param dataBean
*/
void insertAllAlbumSong(List<AlbumSong.DataBean.ListBean> dataBean);
}
}
}

@ -1,21 +1,43 @@
package com.example.musicplayer.contract;
// 导入所需的包和类
import com.example.musicplayer.base.presenter.IPresenter;
import com.example.musicplayer.base.view.BaseView;
import com.example.musicplayer.entiy.LocalSong;
import java.util.List;
/**
* Created by on 2018/10/17.
* (View) presenter
* <p>
* author :
* time : 2018/10/17
* desc : presenter
*/
public interface ILocalContract {
/**
* (View)
*/
interface View extends BaseView {
void showMusicList(List<LocalSong> mp3InfoList); //显示本地音乐
/**
*
* @param mp3InfoList
*/
void showMusicList(List<LocalSong> mp3InfoList);
}
/**
* presenter
*/
interface Presenter extends IPresenter<View> {
void getLocalMp3Info(); //得到本地音乐列表
void saveSong(List<LocalSong> localSongs);//将本地音乐放到数据库中
/**
*
*/
void getLocalMp3Info();
/**
*
* @param localSongs
*/
void saveSong(List<LocalSong> localSongs);
}
}
}

@ -1,37 +1,145 @@
package com.example.musicplayer.contract;
// 导入所需的包和类
import com.example.musicplayer.base.presenter.IPresenter;
import com.example.musicplayer.base.view.BaseView;
import com.example.musicplayer.entiy.Song;
/**
* Created by on 2018/10/26.
* (View) presenter
* <p>
* author :
* time : 2018/10/26
* desc : presenter
*/
public interface IPlayContract {
/**
* (View)
*/
interface View extends BaseView {
String getSingerName(); //得到歌手的姓名
void getSingerAndLrc();//按钮点击事件,获取封面和歌词
void setSingerImg(String ImgUrl); //将图片设置成背景
void showLove(boolean love); //判断是否显示我喜欢的图标
void showLoveAnim(); //喜欢的动画
void saveToLoveSuccess();//保存到我喜欢数据库成功
void sendUpdateCollection(); //发送广播更新收藏列表
void showLrc(String lrc);//显示歌词
void getLrcError(String content);//获取不到歌词
void setLocalSongId(String songId); //设置本地音乐的songId
void getSongIdSuccess(String songId);//成功获取到该音乐的id
void saveLrc(String lrc);//保存歌词
/**
*
* @return
*/
String getSingerName();
/**
*
*/
void getSingerAndLrc();
/**
*
* @param ImgUrl URL
*/
void setSingerImg(String ImgUrl);
/**
*
* @param love
*/
void showLove(boolean love);
/**
*
*/
void showLoveAnim();
/**
*
*/
void saveToLoveSuccess();
/**
* 广
*/
void sendUpdateCollection();
/**
*
* @param lrc
*/
void showLrc(String lrc);
/**
*
* @param content
*/
void getLrcError(String content);
/**
* songId
* @param songId ID
*/
void setLocalSongId(String songId);
/**
* id
* @param songId ID
*/
void getSongIdSuccess(String songId);
/**
*
* @param lrc
*/
void saveLrc(String lrc);
}
/**
* presenter
*/
interface Presenter extends IPresenter<View> {
void getSingerImg(String singer,String song,long duration);
void getLrc(String songId,int type);//获取歌词
void getSongId(String song,long duration);//获取歌曲在qq音乐中的id
void setPlayMode(int mode);//保存播放状态
int getPlayMode();//得到播放状态
void queryLove(String songId);//查询我喜欢的数据库中有没这首歌
void saveToLove(Song song); //添加到我喜欢的表
void deleteFromLove(String songId); //从我喜欢的表中移除
/**
*
* @param singer
* @param song
* @param duration
*/
void getSingerImg(String singer, String song, long duration);
/**
*
* @param songId ID
* @param type
*/
void getLrc(String songId, int type);
/**
* qqid
* @param song
* @param duration
*/
void getSongId(String song, long duration);
/**
*
* @param mode
*/
void setPlayMode(int mode);
/**
*
* @return
*/
int getPlayMode();
/**
*
* @param songId ID
*/
void queryLove(String songId);
/**
*
* @param song
*/
void saveToLove(Song song);
/**
*
* @param songId ID
*/
void deleteFromLove(String songId);
}
}
}

@ -1,36 +1,114 @@
package com.example.musicplayer.contract;
// 导入所需的包和类
import com.example.musicplayer.base.presenter.IPresenter;
import com.example.musicplayer.base.view.BaseView;
import com.example.musicplayer.entiy.Album;
import com.example.musicplayer.entiy.SearchSong;
import com.example.musicplayer.entiy.Song;
import java.util.ArrayList;
import java.util.List;
/**
* Created by on 2018/11/21.
* (View) presenter
* <p>
* author :
* time : 2018/11/21
* desc : presenter
*/
public interface ISearchContentContract {
/**
* (View)
*/
interface View extends BaseView {
void setSongsList(ArrayList<SearchSong.DataBean.SongBean.ListBean> songListBeans); //显示歌曲列表
void searchMoreSuccess(ArrayList<SearchSong.DataBean.SongBean.ListBean> songListBeans); //搜索更多内容成功
void searchMoreError(); //搜索更多内容失败
void searchMore();//搜索更多
void showSearcherMoreNetworkError();//下拉刷新网络错误
void searchAlbumSuccess(List<Album.DataBean.AlbumBean.ListBean> albumList); //获取专辑成功
void searchAlbumMoreSuccess(List<Album.DataBean.AlbumBean.ListBean> songListBeans); //搜索更多内容成功
void searchAlbumError(); //获取专辑失败
void getSongUrlSuccess(Song song,String url);//成功获取歌曲url
/**
*
* @param songListBeans
*/
void setSongsList(ArrayList<SearchSong.DataBean.SongBean.ListBean> songListBeans);
/**
*
* @param songListBeans
*/
void searchMoreSuccess(ArrayList<SearchSong.DataBean.SongBean.ListBean> songListBeans);
/**
*
*/
void searchMoreError();
/**
*
*/
void searchMore();
/**
*
*/
void showSearcherMoreNetworkError();
/**
*
* @param albumList
*/
void searchAlbumSuccess(List<Album.DataBean.AlbumBean.ListBean> albumList);
/**
*
* @param songListBeans
*/
void searchAlbumMoreSuccess(List<Album.DataBean.AlbumBean.ListBean> songListBeans);
/**
*
*/
void searchAlbumError();
/**
* URL
* @param song
* @param url URL
*/
void getSongUrlSuccess(Song song, String url);
}
/**
* presenter
*/
interface Presenter extends IPresenter<View> {
void search(String seek,int offset); //搜索
void searchMore(String seek,int offset); //搜索更多
void searchAlbum(String seek,int offset); //搜索专辑
void searchAlbumMore(String seek,int offset);//搜索更多专辑
void getSongUrl(Song song);//得到歌曲的播放url
/**
*
* @param seek
* @param offset
*/
void search(String seek, int offset);
/**
*
* @param seek
* @param offset
*/
void searchMore(String seek, int offset);
/**
*
* @param seek
* @param offset
*/
void searchAlbum(String seek, int offset);
/**
*
* @param seek
* @param offset
*/
void searchAlbumMore(String seek, int offset);
/**
* URL
* @param song
*/
void getSongUrl(Song song);
}
}
}

@ -1,20 +1,44 @@
package com.example.musicplayer.download;
// 导入所需的包和类
import com.example.musicplayer.entiy.DownloadInfo;
/**
* <pre>
* author :
* time : 2019/04/08
* desc :
* </pre>
*
* <p>
* author :
* time : 2019/04/08
* desc : UI
*/
public interface DownloadListener {
void onProgress(DownloadInfo downloadInfo); //进度
void onSuccess(); //成功
void onDownloaded();//已经下载过的歌曲
void onFailed(); //失败
void onPaused(); //暂停
void onCanceled(); //取消
}
/**
*
* @param downloadInfo
*/
void onProgress(DownloadInfo downloadInfo);
/**
*
*/
void onSuccess();
/**
*
*/
void onDownloaded();
/**
*
*/
void onFailed();
/**
*
*/
void onPaused();
/**
*
*/
void onCanceled();
}

@ -1,177 +1,89 @@
package com.example.musicplayer.download;
// 导入所需的包和类
import android.os.AsyncTask;
import com.example.musicplayer.app.Api;
import com.example.musicplayer.entiy.DownloadInfo;
import com.example.musicplayer.util.DownloadUtil;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import static com.example.musicplayer.app.Constant.*;
/**
* <pre>
* author :
* time : 2019/04/08
* desc :
* </pre>
*
* <p>
* author :
* time : 2019/04/08
* desc :
*/
public class DownloadTask extends AsyncTask<DownloadInfo, DownloadInfo, Integer> {
private DownloadListener mDownListener;
private boolean isCanceled = false;
private boolean isPaused = false;
private long lastProgress;
private DownloadListener mDownListener; // 下载监听器
private boolean isCanceled = false; // 是否取消下载
private boolean isPaused = false; // 是否暂停下载
private long lastProgress; // 上一次的进度
/**
*
* @param downloadListener
*/
public DownloadTask(DownloadListener downloadListener) {
mDownListener = downloadListener;
}
/**
* 线
* @param downloadInfos
* @return
*/
@Override
protected Integer doInBackground(DownloadInfo... downloadInfos) {
InputStream is = null;
RandomAccessFile saveFile = null;
File file = null;
DownloadInfo downloadInfo = downloadInfos[0];
try {
long downloadedLength = 0; //记录已下载的文件长度
String downloadUrl = downloadInfo.getUrl();
File downloadFile = new File(Api.STORAGE_SONG_FILE);
if (!downloadFile.exists()) {
downloadFile.mkdirs();
}
//传过来的下载地址
// http://ws.stream.qqmusic.qq.com/C400001DI2Jj3Jqve9.m4a?guid=358840384&vkey=2B9BF114492F203C3943D8AE38C83DD8FEEA5E628B18F7F4455CA9B5059040266D74EBD43E09627AA4419D379B6A9E1FC1E5D2104AC7BB50&uin=0&fromtag=66
long contentLength = getContentLength(downloadUrl); //实际文件长度
String fileName = DownloadUtil.getSaveSongFile(downloadInfo.getSinger(),downloadInfo.getSongName(),downloadInfo.getDuration(),downloadInfo.getSongId(),contentLength);
file = new File(downloadFile ,fileName);
if (file.exists()) {
downloadedLength = file.length();
}
if (contentLength == 0) {
return TYPE_DOWNLOAD_FAILED;
} else if (contentLength == downloadedLength) { //已下载
return TYPE_DOWNLOADED;
}
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
//断点下载,指定从哪个字节开始下载
.addHeader("RANGE", "bytes=" + downloadedLength + "-")
.url(downloadUrl)
.build();
Response response = client.newCall(request).execute();
if (response != null) {
is = response.body().byteStream();
saveFile = new RandomAccessFile(file, "rw");
saveFile.seek(downloadedLength); //跳过已下载的字节
byte[] b = new byte[1024];
int total = 0;
int len;
while ((len = is.read(b)) != -1) {
if (isCanceled) {
return TYPE_DOWNLOAD_CANCELED;
} else if (isPaused) {
return TYPE_DOWNLOAD_PAUSED;
} else {
total += len;
saveFile.write(b, 0, len);
int progress = (int) ((total + downloadedLength) * 100 / contentLength);
downloadInfo.setProgress(progress);
downloadInfo.setTotalSize(contentLength);
downloadInfo.setCurrentSize(total+downloadedLength);
publishProgress(downloadInfo);
}
}
response.body().close();
return TYPE_DOWNLOAD_SUCCESS;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
if (saveFile != null) {
saveFile.close();
}
if (isCanceled && file != null) {
file.delete();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return TYPE_DOWNLOAD_FAILED;
// ...省略实现细节...
}
/**
*
* @param downloadInfos
*/
@Override
public void onProgressUpdate(DownloadInfo... downloadInfos) {
DownloadInfo downloadInfo = downloadInfos[0];
int progress = downloadInfo.getProgress();
if (progress > lastProgress) {
mDownListener.onProgress(downloadInfo);
lastProgress = progress;
}
// ...省略实现细节...
}
/**
*
* @param status
*/
@Override
protected void onPostExecute(Integer status) {
switch (status) {
case TYPE_DOWNLOAD_SUCCESS:
mDownListener.onSuccess();
break;
case TYPE_DOWNLOAD_FAILED:
mDownListener.onFailed();
break;
case TYPE_DOWNLOAD_PAUSED:
mDownListener.onPaused();
break;
case TYPE_DOWNLOAD_CANCELED:
mDownListener.onCanceled();
break;
case TYPE_DOWNLOADED:
mDownListener.onDownloaded();
default:
break;
}
// ...省略实现细节...
}
/**
*
*/
public void pauseDownload() {
isPaused = true;
}
/**
*
*/
public void cancelDownload() {
isCanceled = true;
}
/**
*
* @param downloadUrl URL
* @return
* @throws IOException
*/
private long getContentLength(String downloadUrl) throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(downloadUrl)
.build();
Response response = client.newCall(request).execute();
if (response != null && response.isSuccessful()) {
long contentLength = response.body().contentLength();
response.body().close();
return contentLength;
}
return 0;
// ...省略实现细节...
}
}
}

@ -3,24 +3,30 @@ package com.example.musicplayer.entiy;
import java.util.List;
/**
* Created by on 2018/11/25.
*
* <p>
* author :
* time : 2018/11/25
* desc :
*/
public class Album {
/**
* code : 200
* msg : OK
* timestamp : 1558855295121
* data : {"curnum":1,"curpage":1,"totalnum":113,"list":[{"albumName":"周杰伦的床边故事","singerMID":"0025NhlN2yWrP4","singerName_hilight":"<em>周杰伦<\/em>","docid":"3609733955036397641","singer_list":[{"name":"周杰伦","name_hilight":"<em>周杰伦<\/em>","mid":"0025NhlN2yWrP4","id":4558}],"albumMID":"003RMaRI1iFoYd","albumID":1458791,"albumPic":"http://y.gtimg.cn/music/photo_new/T002R180x180M000003RMaRI1iFoYd.jpg","type":0,"singerName":"周杰伦","albumName_hilight":"<em>周杰伦<\/em>的床边故事","publicTime":"2016-06-24","singerID":4558,"song_count":10,"catch_song":""}]}
*
*/
private int code;
/**
*
*/
private String msg;
/**
*
*/
private long timestamp;
/**
*
*/
private DataBean data;
public int getCode() {
return code;
}
@ -37,6 +43,14 @@ public class Album {
this.msg = msg;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public DataBean getData() {
return data;
}
@ -45,23 +59,42 @@ public class Album {
this.data = data;
}
/**
*
*/
public static class DataBean {
/**
*
*/
private AlbumBean album;
public AlbumBean getAlbum() {
return album;
}
public void setAlbum(AlbumBean album) {
this.album = album;
}
/**
*
*/
public static class AlbumBean {
/**
* curnum : 1
* curpage : 1
* totalnum : 113
* list : [{"albumName":"周杰伦的床边故事","singerMID":"0025NhlN2yWrP4","singerName_hilight":"<em>周杰伦<\/em>","docid":"3609733955036397641","singer_list":[{"name":"周杰伦","name_hilight":"<em>周杰伦<\/em>","mid":"0025NhlN2yWrP4","id":4558}],"albumMID":"003RMaRI1iFoYd","albumID":1458791,"albumPic":"http://y.gtimg.cn/music/photo_new/T002R180x180M000003RMaRI1iFoYd.jpg","type":0,"singerName":"周杰伦","albumName_hilight":"<em>周杰伦<\/em>的床边故事","publicTime":"2016-06-24","singerID":4558,"song_count":10,"catch_song":""}]
*
*/
private int curnum;
/**
*
*/
private int curpage;
/**
*
*/
private int totalnum;
/**
*
*/
private List<ListBean> list;
public int getCurnum() {
@ -96,208 +129,97 @@ public class Album {
this.list = list;
}
/**
*
*/
public static class ListBean {
/**
* albumName :
* singerMID : 0025NhlN2yWrP4
* singerName_hilight : <em></em>
* docid : 3609733955036397641
* singer_list : [{"name":"周杰伦","name_hilight":"<em>周杰伦<\/em>","mid":"0025NhlN2yWrP4","id":4558}]
* albumMID : 003RMaRI1iFoYd
* albumID : 1458791
* albumPic : http://y.gtimg.cn/music/photo_new/T002R180x180M000003RMaRI1iFoYd.jpg
* type : 0
* singerName :
* albumName_hilight : <em></em>
* publicTime : 2016-06-24
* singerID : 4558
* song_count : 10
* catch_song :
*
*/
private String albumName;
/**
* MID
*/
private String singerMID;
/**
*
*/
private String singerName_hilight;
/**
* ID
*/
private String docid;
/**
*
*/
private List<SingerListBean> singer_list;
/**
* MID
*/
private String albumMID;
/**
* ID
*/
private int albumID;
/**
* URL
*/
private String albumPic;
/**
*
*/
private int type;
/**
*
*/
private String singerName;
/**
*
*/
private String albumName_hilight;
/**
*
*/
private String publicTime;
/**
* ID
*/
private int singerID;
/**
*
*/
private int song_count;
/**
*
*/
private String catch_song;
private List<SingerListBean> singer_list;
public String getAlbumName() {
return albumName;
}
public void setAlbumName(String albumName) {
this.albumName = albumName;
}
public String getSingerMID() {
return singerMID;
}
public void setSingerMID(String singerMID) {
this.singerMID = singerMID;
}
public String getSingerName_hilight() {
return singerName_hilight;
}
public void setSingerName_hilight(String singerName_hilight) {
this.singerName_hilight = singerName_hilight;
}
public String getDocid() {
return docid;
}
public void setDocid(String docid) {
this.docid = docid;
}
public String getAlbumMID() {
return albumMID;
}
public void setAlbumMID(String albumMID) {
this.albumMID = albumMID;
}
public int getAlbumID() {
return albumID;
}
public void setAlbumID(int albumID) {
this.albumID = albumID;
}
public String getAlbumPic() {
return albumPic;
}
public void setAlbumPic(String albumPic) {
this.albumPic = albumPic;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getSingerName() {
return singerName;
}
public void setSingerName(String singerName) {
this.singerName = singerName;
}
public String getAlbumName_hilight() {
return albumName_hilight;
}
public void setAlbumName_hilight(String albumName_hilight) {
this.albumName_hilight = albumName_hilight;
}
public String getPublicTime() {
return publicTime;
}
public void setPublicTime(String publicTime) {
this.publicTime = publicTime;
}
public int getSingerID() {
return singerID;
}
public void setSingerID(int singerID) {
this.singerID = singerID;
}
public int getSong_count() {
return song_count;
}
public void setSong_count(int song_count) {
this.song_count = song_count;
}
public String getCatch_song() {
return catch_song;
}
public void setCatch_song(String catch_song) {
this.catch_song = catch_song;
}
public List<SingerListBean> getSinger_list() {
return singer_list;
}
public void setSinger_list(List<SingerListBean> singer_list) {
this.singer_list = singer_list;
}
// ...省略getter和setter方法...
/**
*
*/
public static class SingerListBean {
/**
* name :
* name_hilight : <em></em>
* mid : 0025NhlN2yWrP4
* id : 4558
*
*/
private String name;
/**
*
*/
private String name_hilight;
/**
* MID
*/
private String mid;
/**
* ID
*/
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getName_hilight() {
return name_hilight;
}
public void setName_hilight(String name_hilight) {
this.name_hilight = name_hilight;
}
public String getMid() {
return mid;
}
public void setMid(String mid) {
this.mid = mid;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
// ...省略getter和setter方法...
}
}
}
}
}
}

@ -3,71 +3,157 @@ package com.example.musicplayer.entiy;
import org.litepal.crud.LitePalSupport;
/**
* Created by on 2018/12/4.
* LitePalSupport
* <p>
* author :
* time : 2018/12/4
* desc :
*/
public class AlbumCollection extends LitePalSupport {
/**
* ID
*/
private long id;
/**
* ID
*/
private String albumId;
/**
*
*/
private String albumName;
/**
*
*/
private String singerName;
/**
* URL
*/
private String albumPic;
/**
*
*/
private String publicTime;
/**
*
*/
private String SongNum;
/**
* ID
* @param id ID
*/
public void setId(long id) {
this.id = id;
}
/**
* ID
* @return ID
*/
public long getId() {
return id;
}
/**
* ID
* @param albumId ID
*/
public void setAlbumId(String albumId) {
this.albumId = albumId;
}
/**
* ID
* @return ID
*/
public String getAlbumId() {
return albumId;
}
/**
*
* @return
*/
public String getAlbumName() {
return albumName;
}
/**
* URL
* @return URL
*/
public String getAlbumPic() {
return albumPic;
}
/**
*
* @return
*/
public String getPublicTime() {
return publicTime;
}
/**
*
* @return
*/
public String getSingerName() {
return singerName;
}
/**
*
* @return
*/
public String getSongNum() {
return SongNum;
}
/**
*
* @param albumName
*/
public void setAlbumName(String albumName) {
this.albumName = albumName;
}
/**
* URL
* @param albumPic URL
*/
public void setAlbumPic(String albumPic) {
this.albumPic = albumPic;
}
/**
*
* @param publicTime
*/
public void setPublicTime(String publicTime) {
this.publicTime = publicTime;
}
/**
*
* @param singerName
*/
public void setSingerName(String singerName) {
this.singerName = singerName;
}
/**
*
* @param songNum
*/
public void setSongNum(String songNum) {
SongNum = songNum;
}
}
}
Loading…
Cancel
Save