diff --git a/app/src/main/assets/litepal.xml b/app/src/main/assets/litepal.xml
index f50ac56..954d39e 100644
--- a/app/src/main/assets/litepal.xml
+++ b/app/src/main/assets/litepal.xml
@@ -1,18 +1,31 @@
+
+
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/adapter/LoveSongAdapter.java b/app/src/main/java/com/example/musicplayer/adapter/LoveSongAdapter.java
index 4e7eb81..fc602ca 100644
--- a/app/src/main/java/com/example/musicplayer/adapter/LoveSongAdapter.java
+++ b/app/src/main/java/com/example/musicplayer/adapter/LoveSongAdapter.java
@@ -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;
/**
+ * 用于展示“喜欢的歌曲”列表的适配器。
+ *
* Created by 残渊 on 2018/11/30.
*/
-
public class LoveSongAdapter extends RecyclerView.Adapter {
- private static final String TAG = "LoveSongAdapter";
- private int footerViewType = 1;
- private int itemViewType = 0;
- private List 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 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 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 {
private static final String TAG = "SearchContentAdapter";
- private ArrayList mSongListBeans;
- private List mAlbumList;
- private static OnItemClickListener mItemClick;
- private static OnAlbumItemClickListener mAlbumClick;
- private String mSeek;
- private Context mContext;
- private int mLastPosition = -1;
- private int mType;
-
+ private ArrayList mSongListBeans; // 单曲列表数据
+ private List 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 dataBeans, String seek, Context context, int type) {
mContext = context;
mSeek = seek;
@@ -56,7 +60,7 @@ public class SearchContentAdapter extends RecyclerView.Adapter songListBeans, String seek, Context context, int type) {
mContext = context;
mSeek = seek;
@@ -64,10 +68,11 @@ public class SearchContentAdapter extends RecyclerView.Adapter {
mItemClick.onClick(position);
equalPosition(position);
@@ -113,21 +120,24 @@ public class SearchContentAdapter extends RecyclerView.Adapter {
mAlbumClick.onClick(position);
});
}
}
-
+ // 获取列表项的总数
@Override
public int getItemCount() {
if (mType == Constant.TYPE_SONG) {
@@ -138,6 +148,7 @@ public class SearchContentAdapter extends RecyclerView.Adapter {
- private List 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 searchHistoryList){
+ private List 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 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 {
- private static final String TAG = "SongAdapter";
- private int footerViewType = 1;
- private int itemViewType = 0;
- private List 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 mMp3InfoList; // 本地歌曲列表数据
+ private Context mContext; // 上下文对象
+ private int mLastPosition = -1; // 上一次点击的位置
+ private OnItemClickListener onItemClickListener; // 点击事件监听器
+
+ // 设置点击事件监听器
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
+ // 构造函数,初始化上下文和本地歌曲列表
public SongAdapter(Context context, List 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 {
}
}
- /**
- * 底部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 {
}
}
+ // 创建ViewHolder
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == itemViewType) {
@@ -86,6 +88,7 @@ public class SongAdapter extends RecyclerView.Adapter {
}
}
+ // 将数据绑定到ViewHolder
@SuppressLint("SetTextI18n")
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
@@ -95,20 +98,20 @@ public class SongAdapter extends RecyclerView.Adapter {
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 {
});
} 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 {
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;
}
-
-
-
-
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/adapter/TabAdapter.java b/app/src/main/java/com/example/musicplayer/adapter/TabAdapter.java
index 2bc27d9..4922390 100644
--- a/app/src/main/java/com/example/musicplayer/adapter/TabAdapter.java
+++ b/app/src/main/java/com/example/musicplayer/adapter/TabAdapter.java
@@ -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 mFragmentList;//顶部导航栏的内容即fragment
- private List mTitle;//顶部导航栏的标题
-
+ private List mFragmentList; // 顶部导航栏的内容,即 Fragment 列表
+ private List mTitle; // 顶部导航栏的标题列表
- public TabAdapter(FragmentManager fragmentManager, Listfragments, Listtitle){
+ // 构造函数,初始化 FragmentManager、Fragment 列表和标题列表
+ public TabAdapter(FragmentManager fragmentManager, List fragments, List 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);
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/app/Api.java b/app/src/main/java/com/example/musicplayer/app/Api.java
index 802817a..79a43d7 100644
--- a/app/src/main/java/com/example/musicplayer/app/Api.java
+++ b/app/src/main/java/com/example/musicplayer/app/Api.java
@@ -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的表头
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/app/App.java b/app/src/main/java/com/example/musicplayer/app/App.java
index 275a7d8..df87203 100644
--- a/app/src/main/java/com/example/musicplayer/app/App.java
+++ b/app/src/main/java/com/example/musicplayer/app/App.java
@@ -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实例。
+ *
* Created by 残渊 on 2018/7/17.
*/
-
public class App extends Application {
+ // 使用SuppressLint注解来抑制静态字段可能引起的内存泄漏警告
@SuppressLint("StaticFieldLeak")
- private static Context context;
+ private static Context context; // 静态变量,用于存储全局Context对象
+ /**
+ * 在应用创建时初始化全局Context和LitePal数据库。
+ */
@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;
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/app/Constant.java b/app/src/main/java/com/example/musicplayer/app/Constant.java
index 2c7b0db..e0cfaf0 100644
--- a/app/src/main/java/com/example/musicplayer/app/Constant.java
+++ b/app/src/main/java/com/example/musicplayer/app/Constant.java
@@ -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;
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/base/activity/BaseActivity.java b/app/src/main/java/com/example/musicplayer/base/activity/BaseActivity.java
index 9e80550..5a18314 100644
--- a/app/src/main/java/com/example/musicplayer/base/activity/BaseActivity.java
+++ b/app/src/main/java/com/example/musicplayer/base/activity/BaseActivity.java
@@ -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;
/**
- *
- * author : 残渊
- * time : 2019/07/17
- * desc : 所有活动的基类
- *
+ * 所有活动的基类,提供了基本的初始化操作和视图绑定。
+ *
+ * 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() {
-
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/base/activity/BaseMvpActivity.java b/app/src/main/java/com/example/musicplayer/base/activity/BaseMvpActivity.java
index 3ad7f75..b99e694 100644
--- a/app/src/main/java/com/example/musicplayer/base/activity/BaseMvpActivity.java
+++ b/app/src/main/java/com/example/musicplayer/base/activity/BaseMvpActivity.java
@@ -3,29 +3,36 @@ package com.example.musicplayer.base.activity;
import com.example.musicplayer.base.presenter.IPresenter;
/**
- *
- * author : 残渊
- * time : 2019/07/17
- * desc :
- *
+ * MVP架构中的基Activity类,用于所有采用MVP模式的Activity。
+ *
+ * author : 残渊
+ * time : 2019/07/17
+ * desc : 提供了Presenter的绑定和解绑操作。
*/
-
-public abstract class BaseMvpActivity extends BaseActivity{
+public abstract class BaseMvpActivity 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
}
+ /**
+ * 在Activity销毁时解绑Presenter,并置空引用。
+ */
@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; // 置空引用,避免内存泄漏
}
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/base/fragment/BaseFragment.java b/app/src/main/java/com/example/musicplayer/base/fragment/BaseFragment.java
index 62b5064..d4d170b 100644
--- a/app/src/main/java/com/example/musicplayer/base/fragment/BaseFragment.java
+++ b/app/src/main/java/com/example/musicplayer/base/fragment/BaseFragment.java
@@ -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;
/**
- *
- * author : 残渊
- * time : 2019/07/14
- * desc :
- *
+ * 所有Fragment的基类,提供了基本的初始化操作和视图绑定。
+ *
+ * author : 残渊
+ * time : 2019/07/14
+ * desc : 基Fragment类,用于简化Fragment的创建和视图管理。
*/
-
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();
+
+ /**
+ * 当Fragment附加到Activity时调用,保存Activity的引用。
+ * @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);
}
-
-
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/base/fragment/BaseLazyFragment.java b/app/src/main/java/com/example/musicplayer/base/fragment/BaseLazyFragment.java
index db4afd3..0b1c49b 100644
--- a/app/src/main/java/com/example/musicplayer/base/fragment/BaseLazyFragment.java
+++ b/app/src/main/java/com/example/musicplayer/base/fragment/BaseLazyFragment.java
@@ -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;
/**
- *
- * author : 残渊
- * time : 2019/07/14
- * desc : 实现懒加载的Fragment
- *
+ * 实现懒加载机制的Fragment基类。
+ *
+ * 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;
}
+ /**
+ * 当Fragment的活动被创建后调用,如果Fragment可见且数据未加载,则加载数据。
+ * @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时,加载数据
+ /**
+ * 当Fragment的可见性发生变化时调用,如果Fragment可见且数据未加载且布局已创建,则加载数据。
+ * @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方法时加载数据
+ /**
+ * 当Fragment的隐藏状态发生变化时调用,如果Fragment不再隐藏且数据未加载且是第一次可见,则加载数据。
+ * @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;
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/base/fragment/BaseLoadingFragment.java b/app/src/main/java/com/example/musicplayer/base/fragment/BaseLoadingFragment.java
index cc22c91..e2633a0 100644
--- a/app/src/main/java/com/example/musicplayer/base/fragment/BaseLoadingFragment.java
+++ b/app/src/main/java/com/example/musicplayer/base/fragment/BaseLoadingFragment.java
@@ -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;
/**
- *
- * author : 残渊
- * time : 2019/07/15
- * desc :
- *
+ * 带有加载、错误和正常状态视图的MVP基Fragment类。
+ *
+ * author : 残渊
+ * time : 2019/07/15
+ * desc : 提供了三种状态视图的切换逻辑,包括加载中、错误和正常显示。
*/
-
public abstract class BaseLoadingFragment extends BaseMvpFragment {
- 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);
}
}
-
-
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/base/fragment/BaseMvpFragment.java b/app/src/main/java/com/example/musicplayer/base/fragment/BaseMvpFragment.java
index 6eeda85..483da10 100644
--- a/app/src/main/java/com/example/musicplayer/base/fragment/BaseMvpFragment.java
+++ b/app/src/main/java/com/example/musicplayer/base/fragment/BaseMvpFragment.java
@@ -1,31 +1,39 @@
package com.example.musicplayer.base.fragment;
+// 导入所需的包和类
import com.example.musicplayer.base.presenter.IPresenter;
/**
- *
- * author : 残渊
- * time : 2019/07/14
- * desc : Mvp模式Fragment的基类
- *
+ * MVP模式下Fragment的基类。
+ *
+ * author : 残渊
+ * time : 2019/07/14
+ * desc : 提供了Presenter的绑定和解绑操作,用于MVP架构的Fragment。
*/
-
public abstract class BaseMvpFragment 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
}
+ /**
+ * 在Fragment销毁时解绑Presenter,并置空引用。
+ */
@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方法
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/base/observer/BaseObserver.java b/app/src/main/java/com/example/musicplayer/base/observer/BaseObserver.java
index c2d7082..bac4c72 100644
--- a/app/src/main/java/com/example/musicplayer/base/observer/BaseObserver.java
+++ b/app/src/main/java/com/example/musicplayer/base/observer/BaseObserver.java
@@ -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;
/**
- *
- * author : 残渊
- * time : 2019/07/16
- * desc : 对RxJava的下游即数据进行处理
- *
+ * 对RxJava的下游即数据进行处理的基类。
+ *
+ * author : 残渊
+ * time : 2019/07/16
+ * desc : 处理网络请求的响应,包括成功、失败和各种异常情况。
*/
-
public class BaseObserver extends ResourceObserver {
- 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 extends ResourceObserver {
} 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));
}
-
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/base/presenter/BasePresenter.java b/app/src/main/java/com/example/musicplayer/base/presenter/BasePresenter.java
index b0d01a6..1162d08 100644
--- a/app/src/main/java/com/example/musicplayer/base/presenter/BasePresenter.java
+++ b/app/src/main/java/com/example/musicplayer/base/presenter/BasePresenter.java
@@ -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;
/**
- *
- * author : 残渊
- * time : 2019/07/14
- * desc :
- *
+ * MVP架构中的基Presenter类,用于处理业务逻辑。
+ *
+ * author : 残渊
+ * time : 2019/07/14
+ * desc : 提供了Presenter的基本实现,包括视图的绑定与解绑,以及RxJava订阅的管理。
*/
+public class BasePresenter implements IPresenter {
-public class BasePresenter implements IPresenter{
-
- 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解除时将订阅事件切断
+ /**
+ * 当Presenter与视图解除绑定时,清除所有的RxJava订阅以避免内存泄漏。
+ */
@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);
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/base/presenter/IPresenter.java b/app/src/main/java/com/example/musicplayer/base/presenter/IPresenter.java
index ff81c05..5b7bc73 100644
--- a/app/src/main/java/com/example/musicplayer/base/presenter/IPresenter.java
+++ b/app/src/main/java/com/example/musicplayer/base/presenter/IPresenter.java
@@ -1,20 +1,41 @@
package com.example.musicplayer.base.presenter;
+// 导入所需的包和类
import com.example.musicplayer.base.view.BaseView;
-
import io.reactivex.disposables.Disposable;
/**
- *
- * author : 残渊
- * time : 2019/07/14
- * desc : 抽象Presenter
- *
+ * 定义了Presenter的基本行为,用于MVP架构。
+ *
+ * author : 残渊
+ * time : 2019/07/14
+ * desc : 抽象Presenter接口,规定了Presenter需要实现的方法。
*/
-
public interface IPresenter {
- void attachView(T view); //注入View
- boolean isAttachView(); //判断是否注入View
- void detachView(); //解除View
- void addRxSubscribe(Disposable disposable);//添加订阅者
-}
+ /**
+ * 将视图(View)注入到Presenter中。
+ * 这是MVP架构中View与Presenter交互的第一步,通常在View的onCreate或相似的生命周期方法中调用。
+ * @param view 需要注入的视图对象,必须遵循BaseView接口。
+ */
+ void attachView(T view);
+
+ /**
+ * 判断是否有视图已经注入到Presenter中。
+ * 这个检查常用于判断是否可以进行UI操作,因为只有当View被注入后,Presenter才能与View进行交互。
+ * @return true表示已经注入View,false表示没有注入View。
+ */
+ boolean isAttachView();
+
+ /**
+ * 从Presenter中解除视图(View)的绑定。
+ * 这是MVP架构中View与Presenter交互的结束步骤,通常在View的onDestroy或相似的生命周期方法中调用。
+ */
+ void detachView();
+
+ /**
+ * 添加RxJava的订阅者(Disposable)到管理容器中。
+ * 这个方法用于管理RxJava中的订阅生命周期,以避免内存泄漏。
+ * @param disposable 需要添加的订阅者对象。
+ */
+ void addRxSubscribe(Disposable disposable);
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/musicplayer/base/view/BaseView.java b/app/src/main/java/com/example/musicplayer/base/view/BaseView.java
index d3f21d8..2dd88d0 100644
--- a/app/src/main/java/com/example/musicplayer/base/view/BaseView.java
+++ b/app/src/main/java/com/example/musicplayer/base/view/BaseView.java
@@ -1,17 +1,41 @@
package com.example.musicplayer.base.view;
/**
- *
- * author : 残渊
- * time : 2019/07/14
- * desc : 页面基类
- *
+ * 定义了页面视图(View)的基本行为,用于MVP架构中的视图层。
+ *
+ * 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);
+}
\ No newline at end of file