diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 4441641..d2dcf81 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,17 +1,30 @@ + + + + + diff --git a/.idea/misc.xml b/.idea/misc.xml index 3179ac3..736ab92 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,11 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 078a3cb..d66b617 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -1,7 +1,12 @@ + + + + + diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml index 7f68460..c04b938 100644 --- a/.idea/runConfigurations.xml +++ b/.idea/runConfigurations.xml @@ -1,10 +1,17 @@ + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/BitIntentDataManager.java b/app/src/main/java/com/monke/monkeybook/BitIntentDataManager.java index 139f98f..c59ce0c 100644 --- a/app/src/main/java/com/monke/monkeybook/BitIntentDataManager.java +++ b/app/src/main/java/com/monke/monkeybook/BitIntentDataManager.java @@ -4,15 +4,34 @@ package com.monke.monkeybook; import java.util.HashMap; import java.util.Map; +/** + * BitIntentDataManager类主要用于管理意图(Intent)相关的数据,采用了单例设计模式来确保在整个应用程序中只有一个实例存在, + * 方便在不同的组件之间共享和操作这些数据,例如在不同的Activity、Fragment之间传递数据时,可以通过这个类来统一管理传递的数据内容。 + */ public class BitIntentDataManager { - public static Map bigData; + /** + * 使用静态变量bigData来存储数据,它是一个Map类型,其中键(String类型)用于唯一标识不同的数据项,值(Object类型)可以是任意类型的对象, + * 通过这种键值对的形式,可以方便地存储和获取各种不同类型的数据,用于传递和共享意图相关的数据信息。 + */ + public static Map bigData; + + /** + * 静态私有变量instance,用于保存BitIntentDataManager类的唯一实例,初始值为null,通过单例模式的相关逻辑来确保只有在第一次调用时才会创建实例,后续都复用这个实例。 + */ private static BitIntentDataManager instance = null; - public static BitIntentDataManager getInstance(){ - if(instance == null){ - synchronized (BitIntentDataManager.class){ - if(instance == null){ + /** + * 静态方法,用于获取BitIntentDataManager类的唯一实例,实现了单例模式中的获取实例逻辑。 + * 首先判断instance是否为null,如果是则进入同步代码块(使用synchronized关键字保证在多线程环境下只会有一个线程创建实例), + * 在同步代码块内再次检查instance是否为null,若仍为null则创建一个新的BitIntentDataManager实例并赋值给instance,最后返回这个唯一的实例。 + * 这样可以保证无论在多少个地方调用这个方法,整个应用程序中始终只有一个BitIntentDataManager实例在运行。 + * @return 返回BitIntentDataManager类的唯一实例对象,通过该实例可以调用其他方法来操作意图数据。 + */ + public static BitIntentDataManager getInstance() { + if (instance == null) { + synchronized (BitIntentDataManager.class) { + if (instance == null) { instance = new BitIntentDataManager(); } } @@ -20,16 +39,40 @@ public class BitIntentDataManager { return instance; } - private BitIntentDataManager(){ + /** + * 私有构造函数,用于创建BitIntentDataManager类的实例对象,在构造函数内部会初始化bigData这个用于存储数据的Map对象, + * 使得实例创建时就准备好了用于存放意图相关数据的数据结构,同时私有构造函数也符合单例模式的设计要求,限制了外部直接创建实例的方式,只能通过getInstance方法获取实例。 + */ + private BitIntentDataManager() { bigData = new HashMap<>(); } - public Object getData(String key){ + + /** + * 根据传入的键(key)从bigData这个存储数据的Map中获取对应的值(Object类型),用于获取之前存储的意图相关数据, + * 如果键不存在,则返回null,外部代码可以通过这个方法获取需要的数据进行后续的业务逻辑处理,例如在接收意图传递的数据后获取具体的值进行展示等操作。 + * @param key 用于查找数据的键,是一个字符串类型,需要与之前存储数据时使用的键保持一致,以便准确获取对应的意图数据。 + * @return 返回从bigData中获取到的对应键的值(Object类型),如果键不存在则返回null。 + */ + public Object getData(String key) { return bigData.get(key); } - public void putData(String key,Object data){ - bigData.put(key,data); + + /** + * 将指定的键(key)和对应的数据(Object类型)存储到bigData这个Map中,用于添加意图相关的数据,方便在不同组件间传递数据时进行数据的设置操作, + * 例如在一个组件中准备好要传递的数据,通过这个方法存储后,其他组件就可以通过相应的键来获取这些数据了。 + * @param key 用于标识存储数据的键,是一个字符串类型,需要保证其唯一性,以便后续准确地通过该键来获取对应的数据,通常根据意图数据的业务含义来定义合适的键名。 + * @param data 要存储的Object类型的数据,即需要传递和共享的具体数据内容,可以是各种类型的对象,如字符串、自定义对象等。 + */ + public void putData(String key, Object data) { + bigData.put(key, data); } - public void cleanData(String key){ + + /** + * 根据传入的键(key)从bigData这个存储数据的Map中移除对应的键值对,用于清理不再需要的意图相关数据, + * 例如在某个数据已经被接收并处理完后,或者不再需要传递该数据时,可以通过这个方法将其从存储中移除,释放内存空间并避免数据冗余等问题。 + * @param key 用于查找并移除数据的键,是一个字符串类型,需要与之前存储数据时使用的键保持一致,以便准确移除对应的意图数据。 + */ + public void cleanData(String key) { bigData.remove(key); } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/ErrorAnalyContentManager.java b/app/src/main/java/com/monke/monkeybook/ErrorAnalyContentManager.java index a08608f..0b9dca1 100644 --- a/app/src/main/java/com/monke/monkeybook/ErrorAnalyContentManager.java +++ b/app/src/main/java/com/monke/monkeybook/ErrorAnalyContentManager.java @@ -12,16 +12,36 @@ import io.reactivex.ObservableOnSubscribe; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; +/** + * ErrorAnalyContentManager类主要用于管理与错误分析相关内容的写入操作,例如将出现错误的URL信息记录到本地文件中, + * 采用了单例设计模式,确保在整个应用程序中只有一个实例来处理这些错误相关的文件写入逻辑,方便统一管理错误记录的操作。 + */ public class ErrorAnalyContentManager { - private ErrorAnalyContentManager(){ + + /** + * 私有构造函数,将构造函数私有化,防止外部直接通过构造函数创建类的实例,符合单例模式的设计要求, + * 使得实例的创建只能通过类提供的静态方法 `getInstance` 来进行控制。 + */ + private ErrorAnalyContentManager() { } + + /** + * 静态私有变量,用于保存ErrorAnalyContentManager类的唯一实例,初始值为null,通过单例模式的相关逻辑来决定何时创建实例,确保整个应用中只有一个实例存在。 + */ private static ErrorAnalyContentManager instance; - public static ErrorAnalyContentManager getInstance(){ - if(instance == null){ - synchronized (ErrorAnalyContentManager.class){ - if(instance == null){ + /** + * 静态方法,用于获取ErrorAnalyContentManager类的唯一实例,实现了单例模式中的获取实例逻辑。 + * 首先判断 `instance` 是否为null,如果是则进入同步代码块(使用 `synchronized` 关键字保证在多线程环境下只会有一个线程创建实例), + * 在同步代码块内再次检查 `instance` 是否为null,若仍为null则创建一个新的ErrorAnalyContentManager实例并赋值给 `instance`,最后返回这个唯一的实例。 + * 这样可以保证无论在多少个地方调用这个方法,整个应用程序中始终只有一个ErrorAnalyContentManager实例在运行。 + * @return 返回ErrorAnalyContentManager类的唯一实例对象,通过该实例可以调用其他方法来进行错误分析相关内容的写入操作。 + */ + public static ErrorAnalyContentManager getInstance() { + if (instance == null) { + synchronized (ErrorAnalyContentManager.class) { + if (instance == null) { instance = new ErrorAnalyContentManager(); } } @@ -29,97 +49,149 @@ public class ErrorAnalyContentManager { return instance; } - public void writeNewErrorUrl(final String url){ + /** + * 用于将新的错误相关的URL信息写入到本地文件中,这个方法会将URL信息按照特定的格式和逻辑分别写入到不同的文件中,用于后续的错误分析等操作。 + * 整个写入操作是基于RxJava的异步操作来实现的,通过 `Observable` 来创建异步任务,并指定了合适的线程调度器来保证在后台线程进行文件读写操作,在主线程进行结果回调处理。 + * @param url 表示出现错误的URL字符串,需要将其记录到本地文件中,用于后续对错误相关情况的分析排查等用途。 + */ + public void writeNewErrorUrl(final String url) { + // 创建一个Observable对象,用于定义一个异步可观察的操作序列,这里传入一个实现了ObservableOnSubscribe接口的匿名内部类,用于定义具体的操作逻辑(即文件写入等操作) Observable.create(new ObservableOnSubscribe() { @Override public void subscribe(ObservableEmitter e) throws Exception { + // 获取应用程序的外部文件目录路径,这个路径是应用在外部存储中可以进行读写操作的目录,用于存放相关的错误记录文件 String filePath = MApplication.getInstance().getExternalFilesDir("").getPath(); + // 根据获取到的文件路径创建一个File对象,表示文件所在的目录,后续用于判断目录是否存在以及创建目录等操作 File dir = new File(filePath); - if(!dir.exists()){ + // 判断目录是否不存在,如果不存在则创建该目录,确保后续要写入的文件所在目录是存在的,避免出现文件写入失败的情况 + if (!dir.exists()) { dir.mkdirs(); } - File file2 = new File(filePath,"ErrorAnalyUrlsDetail.txt"); - if(!file2.exists()) { + // 创建一个表示具体文件的File对象,这里的文件名为 "ErrorAnalyUrlsDetail.txt",位于前面获取到的文件路径下,用于详细记录每个出现错误的完整URL信息 + File file2 = new File(filePath, "ErrorAnalyUrlsDetail.txt"); + // 判断这个文件是否不存在,如果不存在则创建一个新的空文件,为后续写入错误URL信息做准备 + if (!file2.exists()) { file2.createNewFile(); } - FileOutputStream fileOutputStream2 = new FileOutputStream(file2,true); - fileOutputStream2.write((url+" \r\n").getBytes()); + // 创建一个文件输出流对象,用于向 "ErrorAnalyUrlsDetail.txt" 文件写入数据,第二个参数true表示以追加模式打开文件,即新写入的数据会添加在文件末尾,而不会覆盖原有内容 + FileOutputStream fileOutputStream2 = new FileOutputStream(file2, true); + // 将传入的URL字符串加上特定的格式(后面添加几个空格和换行符)转换为字节数组后写入到文件中,实现将错误URL信息记录到文件的操作 + fileOutputStream2.write((url + " \r\n").getBytes()); + // 刷新输出流缓冲区,确保数据真正写入到文件中,而不是仅仅停留在缓冲区 fileOutputStream2.flush(); + // 关闭文件输出流,释放相关资源,避免资源泄漏 fileOutputStream2.close(); /////////////////////////////////////////////////////////////////////// - File file1 = new File(filePath,"ErrorAnalyUrls.txt"); - if(!file1.exists()) { + // 创建另一个表示文件的File对象,这里的文件名为 "ErrorAnalyUrls.txt",同样位于前面获取到的文件路径下,这个文件可能用于记录一些经过处理后的错误URL相关信息(比如截取部分URL内容等情况) + File file1 = new File(filePath, "ErrorAnalyUrls.txt"); + // 判断这个文件是否不存在,如果不存在则创建一个新的空文件 + if (!file1.exists()) { file1.createNewFile(); } + // 创建一个文件输入流对象,用于读取 "ErrorAnalyUrls.txt" 文件中的内容,后续会根据读取到的内容进行相应处理(比如判断是否已存在相同的部分URL等情况) FileInputStream inputStream = new FileInputStream(file1); + // 创建一个字节数组,用于临时存储每次从文件中读取到的数据,这里指定了数组大小为1024字节,可根据实际情况调整合适的大小 byte[] bytes = new byte[1024]; + // 创建一个字节数组输出流对象,用于将从文件输入流中读取到的字节数据进行整合,方便后续将其转换为字符串进行处理 ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(); - while (inputStream.read(bytes) != -1) { + // 通过循环不断从文件输入流中读取数据,每次读取的数据存储到bytes字节数组中,直到读取到文件末尾(返回值为 -1 表示文件末尾),将读取到的数据写入到字节数组输出流中 + while (inputStream.read(bytes)!= -1) { arrayOutputStream.write(bytes, 0, bytes.length); } + // 关闭文件输入流,释放相关资源 inputStream.close(); + // 关闭字节数组输出流,释放相关资源,注意在关闭之前,其内部已经整合好了从文件中读取到的所有字节数据 arrayOutputStream.close(); + // 将字节数组输出流中的字节数据转换为字符串,这样就获取到了 "ErrorAnalyUrls.txt" 文件中的文本内容,方便后续进行字符串相关的判断操作 String content = new String(arrayOutputStream.toByteArray()); - if(!content.contains(url.substring(0,url.indexOf('/',8)))){ - FileOutputStream fileOutputStream1 = new FileOutputStream(file1,true); - fileOutputStream1.write((url.substring(0,url.indexOf('/',8))+" \r\n").getBytes()); + // 判断转换后的文件内容字符串中是否不包含当前要写入的URL的部分内容(这里截取了URL从开头到第8个字符后出现的第一个'/'之前的部分内容,具体截取逻辑根据业务需求而定),如果不包含则表示这个部分URL还未记录过 + if (!content.contains(url.substring(0, url.indexOf('/', 8)))) { + // 创建一个文件输出流对象,用于向 "ErrorAnalyUrls.txt" 文件写入数据,同样以追加模式打开文件 + FileOutputStream fileOutputStream1 = new FileOutputStream(file1, true); + // 将截取后的部分URL字符串加上特定的格式(后面添加几个空格和换行符)转换为字节数组后写入到文件中,实现将部分错误URL信息记录到文件的操作 + fileOutputStream1.write((url.substring(0, url.indexOf('/', 8)) + " \r\n").getBytes()); + // 刷新输出流缓冲区,确保数据真正写入到文件中 fileOutputStream1.flush(); + // 关闭文件输出流,释放相关资源 fileOutputStream1.close(); } + // 发送一个布尔值为true的数据给下游观察者,表示当前的异步操作(文件写入等操作)已经成功完成了这一步骤,触发下游的相关逻辑(比如 `onNext` 方法的调用等) e.onNext(true); + // 发送一个完成信号给下游观察者,表示整个异步操作已经全部完成,触发下游的 `onComplete` 方法调用等相关逻辑 e.onComplete(); } }) + // 指定这个Observable所代表的异步操作在IO线程(用于处理输入输出相关的耗时操作,如文件读写等)上执行,通过线程调度器来实现合适的线程切换,提高应用的性能和响应性 .subscribeOn(Schedulers.io()) + // 指定下游观察者(即处理异步操作结果的相关逻辑代码所在的地方)在Android的主线程上执行,这样可以方便在主线程更新UI等操作,符合Android开发中关于UI操作必须在主线程的要求 .observeOn(AndroidSchedulers.mainThread()) + // 订阅这个Observable,传入一个SimpleObserver对象,用于处理异步操作过程中产生的数据(通过 `onNext` 方法)、错误(通过 `onError` 方法)以及操作完成(通过 `onComplete` 方法)等不同情况的逻辑 .subscribe(new SimpleObserver() { @Override public void onNext(Boolean value) { - + // 当上游的Observable发送数据(这里是发送了布尔值为true的数据)时,会调用这个方法,当前方法体为空,可以根据业务需求在这里添加相应的逻辑,比如进行一些简单的日志记录等操作,表示文件写入操作的某一步骤成功完成了 } @Override public void onError(Throwable e) { - + // 当在异步操作过程中出现错误(比如文件读写出现异常等情况)时,会调用这个方法,当前方法体为空,可以在这里添加相应的错误处理逻辑,比如记录错误日志、提示用户等操作 } }); } - public void writeMayByNetError(final String url){ + /** + * 用于将可能是网络错误相关的URL信息写入到本地文件中,同样是基于RxJava的异步操作来实现文件写入,将指定的URL信息按照特定格式追加到名为 "ErrorNetUrl.txt" 的文件中,方便后续对网络错误相关情况进行分析排查等操作。 + * @param url 表示可能出现网络错误的URL字符串,需要将其记录到本地文件中,用于后续对网络错误相关情况的分析排查等用途。 + */ + public void writeMayByNetError(final String url) { Observable.create(new ObservableOnSubscribe() { @Override public void subscribe(ObservableEmitter e) throws Exception { + // 获取应用程序的外部文件目录路径,用于确定要写入的文件所在的目录位置 String filePath = MApplication.getInstance().getExternalFilesDir("").getPath(); + // 根据获取到的文件路径创建一个File对象,表示文件所在的目录,后续用于判断目录是否存在以及创建目录等操作 File dir = new File(filePath); - if(!dir.exists()){ + // 判断目录是否不存在,如果不存在则创建该目录,确保后续要写入的文件所在目录是存在的,避免出现文件写入失败的情况 + if (!dir.exists()) { dir.mkdirs(); } - File file = new File(filePath,"ErrorNetUrl.txt"); - if(!file.exists()) { + // 创建一个表示具体文件的File对象,文件名为 "ErrorNetUrl.txt",位于前面获取到的文件路径下,用于记录可能出现网络错误的URL信息 + File file = new File(filePath, "ErrorNetUrl.txt"); + // 判断这个文件是否不存在,如果不存在则创建一个新的空文件,为后续写入错误URL信息做准备 + if (!file.exists()) { file.createNewFile(); } - FileOutputStream fileOutputStream2 = new FileOutputStream(file,true); - fileOutputStream2.write((url+" \r\n").getBytes()); + // 创建一个文件输出流对象,用于向 "ErrorNetUrl.txt" 文件写入数据,以追加模式打开文件,使得新写入的数据添加在文件末尾,不会覆盖原有内容 + FileOutputStream fileOutputStream2 = new FileOutputStream(file, true); + // 将传入的URL字符串加上特定的格式(后面添加几个空格和换行符)转换为字节数组后写入到文件中,实现将网络错误相关的URL信息记录到文件的操作 + fileOutputStream2.write((url + " \r\n").getBytes()); + // 刷新输出流缓冲区,确保数据真正写入到文件中,而不是仅仅停留在缓冲区 fileOutputStream2.flush(); + // 关闭文件输出流,释放相关资源,避免资源泄漏 fileOutputStream2.close(); + // 发送一个布尔值为true的数据给下游观察者,表示当前的异步操作(文件写入等操作)已经成功完成了这一步骤,触发下游的相关逻辑(比如 `onNext` 方法的调用等) e.onNext(true); + // 发送一个完成信号给下游观察者,表示整个异步操作已经全部完成,触发下游的 `onComplete` 方法调用等相关逻辑 e.onComplete(); } }) + // 指定这个Observable所代表的异步操作在IO线程上执行,通过线程调度器实现合适的线程切换,让文件读写等耗时操作在后台线程进行,提高应用性能和响应性 .subscribeOn(Schedulers.io()) + // 指定下游观察者(即处理异步操作结果的相关逻辑代码所在的地方)在Android的主线程上执行,方便在主线程进行UI更新等操作,符合Android开发中关于UI操作必须在主线程的要求 .observeOn(AndroidSchedulers.mainThread()) + // 订阅这个Observable,传入一个SimpleObserver对象,用于处理异步操作过程中产生的数据(通过 `onNext` 方法)、错误(通过 `onError` 方法)以及操作完成(通过 `onComplete` 方法)等不同情况的逻辑 .subscribe(new SimpleObserver() { @Override public void onNext(Boolean value) { - + // 当上游的Observable发送数据(这里是发送了布尔值为true的数据)时,会调用这个方法,当前方法体为空,可以根据业务需求在这里添加相应的逻辑,比如进行一些简单的日志记录等操作,表示文件写入操作的某一步骤成功完成了 } @Override public void onError(Throwable e) { - + // 当在异步操作过程中出现错误(比如文件读写出现异常等情况)时,会调用这个方法,当前方法体为空,可以在这里添加相应的错误处理逻辑,比如记录错误日志、提示用户等操作 } }); } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/MApplication.java b/app/src/main/java/com/monke/monkeybook/MApplication.java index 61e1345..744ccbb 100644 --- a/app/src/main/java/com/monke/monkeybook/MApplication.java +++ b/app/src/main/java/com/monke/monkeybook/MApplication.java @@ -8,31 +8,48 @@ import android.content.pm.PackageManager; import com.monke.monkeybook.service.DownloadService; import com.umeng.analytics.MobclickAgent; +// MApplication类继承自Android的Application类,是整个应用程序的全局基础类,用于在应用启动时进行一些初始化操作,例如配置统计分析工具、启动相关服务等 public class MApplication extends Application { + // 定义一个静态变量instance,用于保存MApplication类的唯一实例,方便在整个应用的其他地方可以获取到这个唯一的Application实例对象,实现全局访问 private static MApplication instance; + // 重写Application类的onCreate方法,这个方法会在应用程序启动时被系统自动调用,用于执行应用的初始化相关逻辑 @Override public void onCreate() { super.onCreate(); + + // 判断当前应用是否是发布版本(BuildConfig.IS_RELEASE通常是一个根据构建配置生成的布尔值,用于区分开发环境和发布环境),如果是发布版本则执行以下初始化操作 if (BuildConfig.IS_RELEASE) { + // 初始化一个默认的渠道名为"debug",后续会尝试从应用的元数据中获取真实的渠道名来替换它,如果获取失败则保留这个默认值,这里的渠道名通常用于统计分析等工具区分应用的不同发布渠道来源 String channel = "debug"; try { + // 通过应用的包管理器(PackageManager)获取当前应用的ApplicationInfo信息,GET_META_DATA标志表示要获取应用的元数据信息,这一步是为了后续能从元数据中查找特定的渠道相关配置信息 ApplicationInfo appInfo = getPackageManager() .getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA); + // 从获取到的ApplicationInfo的元数据中尝试获取名为"UMENG_CHANNEL_VALUE"的字符串值,这个值通常在应用的配置文件(如AndroidManifest.xml或相关的构建配置中设置)中定义,代表友盟统计分析工具所使用的渠道值 channel = appInfo.metaData.getString("UMENG_CHANNEL_VALUE"); } catch (PackageManager.NameNotFoundException e) { + // 如果在获取元数据过程中出现NameNotFoundException异常(通常是因为指定的元数据键不存在等原因),则打印异常堆栈信息,方便排查问题,同时保持前面设置的默认渠道名"debug"不变 e.printStackTrace(); } + // 使用获取到的渠道名以及其他相关配置信息(如友盟的App Key等)来初始化友盟统计分析工具(MobclickAgent),配置应用的统计相关行为,例如指定应用的上下文(this代表当前的MApplication实例)、友盟的App Key(通过getString(R.string.umeng_key)获取,通常在资源文件中定义)、渠道名、场景类型(这里是普通场景)以及是否自动统计页面停留时间等参数 MobclickAgent.startWithConfigure(new MobclickAgent.UMAnalyticsConfig(this, getString(R.string.umeng_key), channel, MobclickAgent.EScenarioType.E_UM_NORMAL, true)); } + + // 将当前的MApplication实例赋值给静态变量instance,使得在应用的其他地方可以通过getInstance方法获取到这个唯一的Application实例对象,实现全局访问 instance = this; + + // 调用ProxyManager类的initProxy方法(具体功能需看ProxyManager类的实现,可能是初始化一些代理相关设置等)进行相关初始化操作,这一步可能是应用自定义的初始化逻辑的一部分,用于处理网络代理等相关功能的初始化 ProxyManager.initProxy(); + + // 创建一个启动DownloadService服务的意图(Intent),并通过startService方法启动这个服务,DownloadService可能是用于处理应用中文件下载等相关功能的服务,启动它可以让相关下载逻辑在后台运行,保证下载任务等的持续执行 startService(new Intent(this, DownloadService.class)); } + // 定义一个静态方法,用于获取MApplication类的唯一实例,方便在应用的其他地方获取到这个全局的Application实例对象,进而可以访问在Application中定义的全局变量、调用相关方法等 public static MApplication getInstance() { return instance; } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/ProxyManager.java b/app/src/main/java/com/monke/monkeybook/ProxyManager.java index eb1248d..2cbd21c 100644 --- a/app/src/main/java/com/monke/monkeybook/ProxyManager.java +++ b/app/src/main/java/com/monke/monkeybook/ProxyManager.java @@ -1,67 +1,136 @@ package com.monke.monkeybook; import android.content.SharedPreferences; - import org.jsoup.helper.StringUtil; - import java.util.regex.Pattern; +// ProxyManager类主要用于管理应用程序中的代理相关设置,包括代理的状态(是否启用代理)以及代理的HTTP地址等信息, +// 同时提供了保存、初始化这些设置以及检查是否存在有效代理的方法,通过与SharedPreferences交互实现设置的持久化存储。 public class ProxyManager { + + // 定义一个常量字符串,作为在SharedPreferences中存储HTTP代理地址的键,方便后续通过这个键来获取和设置对应的代理地址值, + // 遵循统一的命名规范以便代码的可读性和维护性。 public static final String SP_KEY_PROXY_HTTP = "proxy_http"; + + // 定义一个常量字符串,作为在SharedPreferences中存储代理状态(布尔值,表示是否启用代理)的键, + // 用于准确标识和操作代理状态相关的存储数据。 public static final String SP_KEY_PROXY_STATE = "proxy_state"; + + // 定义一个默认的HTTP代理地址值,初始为空字符串,表示没有设置代理地址时的默认情况, + // 当获取代理地址且未进行过设置或者设置被清除时,会返回这个默认值。 public static final String PROXY_HTTP_DEFAULT = ""; + + // 定义一个默认的代理状态值,初始为false,表示默认情况下代理是未启用的, + // 作为代理状态在没有从存储中获取到有效数据或者初始化时的默认设置。 public static final boolean PROXY_STATE_DEFAULT = false; + // 静态变量,用于存储当前应用的代理状态(是否启用代理),可在类的各个方法中访问和修改, + // 通过与存储的交互以及相关方法的调用保持其值与实际的代理设置情况一致。 public static boolean proxyState; + + // 静态变量,用于存储当前应用的HTTP代理地址,方便在需要使用代理进行网络请求等操作时获取该地址信息, + // 其值会根据用户设置以及从存储中读取的情况进行更新。 public static String proxyHttp; - private static final String PROXY_HTTP_MATCH = "(http|ftp|https):\\/\\/[\\w\\-_]+(\\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&:/~\\+#]*[\\w\\-\\@?^=%&/~\\+#])?";//http正则表达式 - public static final String PROXY_PACKAGENAME_ENCODE = "代理包名加密key"; //代理包名加密key - public static String packageName; //加密后的包名 + // 定义一个用于匹配HTTP代理地址格式的正则表达式字符串,用于验证输入或存储的代理地址是否符合规范, + // 涵盖了常见的HTTP、HTTPS、FTP协议开头的网络地址格式情况,以便对代理地址进行合法性校验。 + private static final String PROXY_HTTP_MATCH = "(http|ftp|https):\\/\\/[\\w\\-_]+(\\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&:/~\\+#]*[\\w\\-\\@?^=%&/~\\+#])?"; + + // 定义一个常量字符串,用于表示代理包名加密的密钥,具体加密相关功能可能在其他地方实现, + // 这里只是定义了这个密钥的常量表示,用于相关的加密操作或者与加密相关逻辑的标识。 + public static final String PROXY_PACKAGENAME_ENCODE = "代理包名加密key"; + + // 静态变量,用于存储加密后的包名信息,具体加密过程以及其用途取决于应用中与代理相关的业务逻辑, + // 例如可能用于身份验证、权限控制等涉及到包名相关的代理功能场景中。 + public static String packageName; + + // 用于保存代理状态到SharedPreferences中的方法,接收一个布尔值参数表示要设置的代理状态, + // 同时更新类中的静态变量proxyState,确保内存中的状态与存储中的设置保持一致。 public static void saveProxyState(boolean state) { + // 将传入的代理状态值赋给静态变量proxyState,使其在内存中更新为最新的设置值。 proxyState = state; + // 获取应用程序的SharedPreferences对象的编辑器(Editor),用于后续对存储数据进行修改操作, + // "CONFIG"是SharedPreferences文件的名称,0表示操作模式(MODE_PRIVATE,即只有当前应用可以访问该文件)。 SharedPreferences.Editor editor = MApplication.getInstance().getSharedPreferences("CONFIG", 0).edit(); + // 通过编辑器将代理状态值(proxyState)以指定的键(SP_KEY_PROXY_STATE)存储到SharedPreferences中,实现数据的持久化保存。 editor.putBoolean(SP_KEY_PROXY_STATE, proxyState); + // 提交编辑器中的修改操作,将数据真正写入到SharedPreferences文件中,使设置生效。 editor.commit(); } + // 私有方法,用于初始化代理状态信息,主要从SharedPreferences中获取之前存储的代理状态值, + // 如果获取失败则使用默认的代理状态值(PROXY_STATE_DEFAULT),同时尝试获取应用的包名信息(可能用于后续相关逻辑)。 private static void initProxyState() { try { + // 通过应用的包管理器(PackageManager)获取当前应用的包名信息,将获取到的包名赋值给静态变量packageName, + // 具体用途可能与代理相关的权限判断、标识等功能有关,这里先进行获取并存储以备后续使用。 packageName = MApplication.getInstance().getPackageManager().getPackageInfo(MApplication.getInstance().getPackageName(), 0).packageName; } catch (Exception e) { + // 如果在获取包名过程中出现异常(例如找不到对应包信息等情况),则打印异常堆栈信息,方便排查问题, + // 同时在控制台输出提示信息,表示包名获取失败可能会影响代理请求功能,让开发者知晓潜在问题。 e.printStackTrace(); System.out.println("=================包名获取失败,可能会影响代理请求功能================="); } + // 从应用的SharedPreferences中获取代理状态值,以SP_KEY_PROXY_STATE为键进行查找, + // 如果不存在对应的键值对,则使用默认的代理状态值(PROXY_STATE_DEFAULT)作为初始值赋给proxyState变量,实现代理状态的初始化。 proxyState = MApplication.getInstance().getSharedPreferences("CONFIG", 0).getBoolean(SP_KEY_PROXY_STATE, PROXY_STATE_DEFAULT); } + // 用于保存HTTP代理地址到SharedPreferences中的方法,接收一个字符串参数表示要设置的代理地址, + // 同时更新类中的静态变量proxyHttp,保证内存中的代理地址与存储中的设置一致。 public static void saveProxyHttp(String http) { + // 将传入的代理地址值赋给静态变量proxyHttp,使其在内存中更新为最新的设置值。 proxyHttp = http; + // 获取应用程序的SharedPreferences对象的编辑器(Editor),用于后续对存储数据进行修改操作, + // "CONFIG"是SharedPreferences文件的名称,0表示操作模式(MODE_PRIVATE,即只有当前应用可以访问该文件)。 SharedPreferences.Editor editor = MApplication.getInstance().getSharedPreferences("CONFIG", 0).edit(); + // 通过编辑器将代理地址值(proxyHttp)以指定的键(SP_KEY_PROXY_HTTP)存储到SharedPreferences中,实现数据的持久化保存。 editor.putString(SP_KEY_PROXY_HTTP, proxyHttp); + // 提交编辑器中的修改操作,将数据真正写入到SharedPreferences文件中,使设置生效。 editor.commit(); } + // 私有方法,用于初始化HTTP代理地址信息,从SharedPreferences中获取之前存储的代理地址值, + // 如果获取失败则使用默认的代理地址值(PROXY_HTTP_DEFAULT),以此来完成代理地址的初始化设置。 private static void initProxyHttp() { + // 从应用的SharedPreferences中获取代理地址值,以SP_KEY_PROXY_HTTP为键进行查找, + // 如果不存在对应的键值对,则使用默认的代理地址值(PROXY_HTTP_DEFAULT)作为初始值赋给proxyHttp变量,实现代理地址的初始化。 proxyHttp = MApplication.getInstance().getSharedPreferences("CONFIG", 0).getString(SP_KEY_PROXY_HTTP, PROXY_HTTP_DEFAULT); } + // 用于整体初始化代理相关设置的方法,会依次调用初始化代理地址和初始化代理状态的方法, + // 然后调用hasProxy方法来检查当前设置的代理是否有效,完成整个代理相关设置的初始化流程。 public static void initProxy() { + // 调用initProxyHttp方法,初始化HTTP代理地址信息,从存储中获取或设置默认的代理地址值到内存变量中。 initProxyHttp(); + // 调用initProxyState方法,初始化代理状态信息,从存储中获取或设置默认的代理状态值到内存变量中。 initProxyState(); + // 调用hasProxy方法,检查当前设置的代理是否有效,根据代理状态和代理地址的合法性进行判断, + // 并根据判断结果可能更新代理状态的存储值,确保代理设置的准确性。 hasProxy(); } + // 用于检查当前是否存在有效代理的方法,根据代理状态以及代理地址是否符合格式要求来综合判断, + // 如果代理未启用或者代理地址不符合规范,则返回false,表示不存在有效代理;否则返回true,表示存在有效代理, + // 同时在代理地址不符合规范时会自动将代理状态设置为false并保存到存储中,以保证代理设置的合理性。 public static boolean hasProxy() { + // 如果代理状态为false(即代理未启用),直接返回false,表示不存在有效代理,无需再进行地址格式验证等操作。 if (!proxyState) { return false; } + // 使用定义好的正则表达式字符串(PROXY_HTTP_MATCH)创建一个Pattern对象,用于后续对代理地址进行格式匹配验证, + // Pattern类提供了强大的正则表达式匹配功能,方便判断输入的字符串是否符合特定的格式要求。 Pattern pattern = Pattern.compile(PROXY_HTTP_MATCH); + // 通过StringUtil.isBlank方法检查代理地址(proxyHttp)是否为空(包含空字符串、null以及只包含空白字符等情况), + // 并且使用创建的Pattern对象对代理地址进行正则匹配验证,只有当代理地址不为空且符合格式要求时,才返回true,表示存在有效代理; + // 否则返回false,表示代理地址不符合规范,不存在有效代理。 if (!StringUtil.isBlank(proxyHttp) && pattern.matcher(proxyHttp).matches()) { return true; } else { + // 如果代理地址不符合规范,调用saveProxyState方法将代理状态设置为false,表示当前不存在有效代理, + // 并将这个更新后的代理状态保存到SharedPreferences中,确保存储中的代理状态与实际情况一致,然后返回false。 saveProxyState(false); return false; } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/ReadBookControl.java b/app/src/main/java/com/monke/monkeybook/ReadBookControl.java index f88e7d3..b0ee9ad 100644 --- a/app/src/main/java/com/monke/monkeybook/ReadBookControl.java +++ b/app/src/main/java/com/monke/monkeybook/ReadBookControl.java @@ -9,169 +9,255 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +/** + * ReadBookControl类主要用于管理阅读书籍时的相关控制参数,例如文字大小、文字颜色、背景样式以及翻页方式等设置, + * 采用单例模式设计,确保在整个应用中只有一个实例来统一管理这些阅读相关的配置信息,方便在不同的阅读场景中进行参数的获取和更新操作。 + */ public class ReadBookControl { + + // 定义默认的文字样式索引值,用于在没有特定设置或者初始化时确定默认使用的文字相关配置,这里值为2,具体对应哪种文字样式由后续的逻辑决定。 public static final int DEFAULT_TEXT = 2; + + // 定义默认的背景样式索引值,用于在没有特定设置或者初始化时确定默认使用的背景相关配置,这里值为1,同样具体对应哪种背景样式由后续逻辑决定。 public static final int DEFAULT_BG = 1; - private static List> textKind; - private static List> textDrawable; + // 用于存储不同文字样式相关配置信息的列表,每个元素是一个Map,其中包含如文字大小、文字间距等具体配置项,方便根据不同索引获取对应的文字样式配置。 + private static List> textKind; + + // 用于存储不同文字绘制相关配置信息的列表(主要涉及文字颜色和文字背景相关设置),每个元素是一个Map,方便根据不同索引获取对应的文字绘制相关配置。1111 + private static List> textDrawable; + // 记录当前的文字大小,单位可能是像素等(具体取决于存储和使用的情况),通过获取对应文字样式配置中的值来初始化和更新,用于控制阅读界面文字显示的大小。 private int textSize; + + // 记录当前的文字间距(额外间距),单位可能是像素等,通过对应文字样式配置获取并更新,用于调整文字排版时的间距效果,提升阅读体验。 private int textExtra; + + // 记录当前的文字颜色,以颜色值的形式存储(可能是通过Android系统的颜色表示方式,如ARGB等),从文字绘制相关配置中获取,决定文字在阅读界面呈现的颜色。 private int textColor; + + // 记录当前的文字背景,以资源标识符(如R.drawable中的相关资源ID)的形式存储,用于指定文字所在区域的背景样式,从文字绘制相关配置中获取并应用。 private int textBackground; + // 当前选择的文字样式索引,用于在textKind列表中定位对应的文字样式配置,初始化为DEFAULT_TEXT,可通过设置方法进行更新,以切换不同的文字样式。 private int textKindIndex = DEFAULT_TEXT; + + // 当前选择的文字绘制样式索引,用于在textDrawable列表中定位对应的文字绘制相关配置,初始化为DEFAULT_BG,同样可通过设置方法更新来切换不同的文字背景和颜色组合等样式。 private int textDrawableIndex = DEFAULT_BG; + // 用于标识是否允许通过点击进行翻页操作,初始值为true,表示默认允许点击翻页,可通过设置方法改变其值,并将设置持久化存储,方便用户根据自己的阅读习惯进行调整。 private Boolean canClickTurn = true; + + // 用于标识是否允许通过按键(如音量键等,具体取决于应用的按键绑定设置)进行翻页操作,初始值为true,可通过设置方法修改值并保存设置,以满足不同用户对翻页操作方式的偏好。 private Boolean canKeyTurn = true; + // 用于存储应用的配置信息,通过SharedPreferences与应用的配置文件(通常以键值对形式存储数据)进行交互,实现阅读控制相关参数的持久化存储和读取。 private SharedPreferences preference; + // 静态变量,用于保存ReadBookControl类的唯一实例,遵循单例模式的设计,初始值为null,通过特定的获取实例方法来确保整个应用只有一个实例存在。 private static ReadBookControl readBookControl; - public static ReadBookControl getInstance(){ - if(readBookControl == null){ - synchronized (ReadBookControl.class){ - if(readBookControl == null){ + /** + * 静态方法,用于获取ReadBookControl类的唯一实例,实现了单例模式中的获取实例逻辑。 + * 首先判断readBookControl是否为null,如果是则进入同步代码块(使用synchronized关键字保证在多线程环境下只会有一个线程创建实例), + * 在同步代码块内再次检查readBookControl是否为null,若仍为null则创建一个新的ReadBookControl实例并赋值给readBookControl,最后返回这个唯一的实例。 + * 这样可以保证无论在多少个地方调用这个方法,整个应用程序中始终只有一个ReadBookControl实例在运行,方便统一管理阅读控制相关参数。 + * @return 返回ReadBookControl类的唯一实例对象,通过该实例可以调用其他方法来获取和设置阅读相关的控制参数。 + */ + public static ReadBookControl getInstance() { + if (readBookControl == null) { + synchronized (ReadBookControl.class) { + if (readBookControl == null) { readBookControl = new ReadBookControl(); } } } return readBookControl; } - private ReadBookControl(){ - if(null == textKind){ + + /** + * 私有构造函数,用于创建ReadBookControl类的实例对象,在构造函数内部进行了一系列的初始化操作,包括初始化文字样式列表、文字绘制样式列表以及从SharedPreferences中读取之前保存的配置参数等, + * 确保实例创建时相关的阅读控制参数处于合适的初始状态,同时私有构造函数符合单例模式的设计要求,限制了外部直接创建实例的方式,只能通过getInstance方法获取实例。 + */ + private ReadBookControl() { + // 如果textKind列表为空(即还未初始化),则进行初始化操作,创建不同文字样式相关的配置信息并添加到textKind列表中。 + if (null == textKind) { textKind = new ArrayList<>(); - Map temp1 = new HashMap<>(); + // 创建一个临时的Map,用于存储一种文字样式的配置信息,这里设置文字大小为14(单位可能是像素等,具体看后续使用情况),文字间距通过DensityUtil工具类将dp值转换为像素值(6.5dp转换后的像素值),然后将这个配置信息添加到textKind列表中。 + Map temp1 = new HashMap<>(); temp1.put("textSize", 14); - temp1.put("textExtra", DensityUtil.dp2px(MApplication.getInstance(),6.5f)); + temp1.put("textExtra", DensityUtil.dp2px(MApplication.getInstance(), 6.5f)); textKind.add(temp1); - Map temp2 = new HashMap<>(); + // 类似地,创建另一种文字样式的配置信息,文字大小设置为16,文字间距通过DensityUtil转换对应dp值后的像素值,再添加到textKind列表中,方便后续根据索引选择不同的文字大小和间距配置。 + Map temp2 = new HashMap<>(); temp2.put("textSize", 16); - temp2.put("textExtra", DensityUtil.dp2px(MApplication.getInstance(),8)); + temp2.put("textExtra", DensityUtil.dp2px(MApplication.getInstance(), 8)); textKind.add(temp2); - Map temp3 = new HashMap<>(); + Map temp3 = new HashMap<>(); temp3.put("textSize", 17); - temp3.put("textExtra", DensityUtil.dp2px(MApplication.getInstance(),9)); + temp3.put("textExtra", DensityUtil.dp2px(MApplication.getInstance(), 9)); textKind.add(temp3); - Map temp4 = new HashMap<>(); + Map temp4 = new HashMap<>(); temp4.put("textSize", 20); - temp4.put("textExtra", DensityUtil.dp2px(MApplication.getInstance(),11)); + temp4.put("textExtra", DensityUtil.dp2px(MApplication.getInstance(), 11)); textKind.add(temp4); - Map temp5 = new HashMap<>(); + Map temp5 = new HashMap<>(); temp5.put("textSize", 22); - temp5.put("textExtra", DensityUtil.dp2px(MApplication.getInstance(),13)); + temp5.put("textExtra", DensityUtil.dp2px(MApplication.getInstance(), 13)); textKind.add(temp5); } - if(null == textDrawable){ + + // 如果textDrawable列表为空(未初始化),则进行初始化操作,创建不同文字绘制样式相关的配置信息(包含文字颜色和文字背景)并添加到textDrawable列表中。 + if (null == textDrawable) { textDrawable = new ArrayList<>(); - Map temp1 = new HashMap<>(); - temp1.put("textColor",Color.parseColor("#3E3D3B")); - temp1.put("textBackground",R.drawable.shape_bg_readbook_white); + // 创建一个临时的Map,用于存储一种文字绘制样式的配置信息,设置文字颜色通过Color.parseColor方法解析十六进制颜色代码(这里是深灰色)得到对应的颜色值,文字背景设置为指定的白色背景样式资源(通过R.drawable中的资源ID指定),然后将这个配置添加到textDrawable列表中。 + Map temp1 = new HashMap<>(); + temp1.put("textColor", Color.parseColor("#3E3D3B")); + temp1.put("textBackground", R.drawable.shape_bg_readbook_white); textDrawable.add(temp1); - Map temp2 = new HashMap<>(); - temp2.put("textColor",Color.parseColor("#5E432E")); - temp2.put("textBackground",R.drawable.bg_readbook_yellow); + Map temp2 = new HashMap<>(); + temp2.put("textColor", Color.parseColor("#5E432E")); + temp2.put("textBackground", R.drawable.bg_readbook_yellow); textDrawable.add(temp2); - Map temp3 = new HashMap<>(); - temp3.put("textColor",Color.parseColor("#22482C")); - temp3.put("textBackground",R.drawable.bg_readbook_green); + Map temp3 = new HashMap<>(); + temp3.put("textColor", Color.parseColor("#22482C")); + temp3.put("textBackground", R.drawable.bg_readbook_green); textDrawable.add(temp3); - Map temp4 = new HashMap<>(); - temp4.put("textColor",Color.parseColor("#808080")); - temp4.put("textBackground",R.drawable.bg_readbook_black); + Map temp4 = new HashMap<>(); + temp4.put("textColor", Color.parseColor("#808080")); + temp4.put("textBackground", R.drawable.bg_readbook_black); textDrawable.add(temp4); } + + // 获取应用的SharedPreferences对象,用于读取和保存阅读控制相关的配置参数,"CONFIG"是配置文件的名称,0表示操作模式(MODE_PRIVATE,即只有当前应用可以访问该文件)。 preference = MApplication.getInstance().getSharedPreferences("CONFIG", 0); - this.textKindIndex = preference.getInt("textKindIndex",DEFAULT_TEXT); + + // 从SharedPreferences中读取之前保存的文字样式索引值,如果不存在则使用默认的文字样式索引值(DEFAULT_TEXT),然后根据这个索引获取对应的文字大小和文字间距并赋值给相应变量。 + this.textKindIndex = preference.getInt("textKindIndex", DEFAULT_TEXT); this.textSize = textKind.get(textKindIndex).get("textSize"); this.textExtra = textKind.get(textKindIndex).get("textExtra"); - this.textDrawableIndex = preference.getInt("textDrawableIndex",DEFAULT_BG); + + // 从SharedPreferences中读取之前保存的文字绘制样式索引值,若不存在则用默认的背景样式索引值(DEFAULT_BG),再依据该索引获取对应的文字颜色和文字背景资源并赋值给相应变量。 + this.textDrawableIndex = preference.getInt("textDrawableIndex", DEFAULT_BG); this.textColor = textDrawable.get(textDrawableIndex).get("textColor"); this.textBackground = textDrawable.get(textDrawableIndex).get("textBackground"); - this.canClickTurn = preference.getBoolean("canClickTurn",true); - this.canKeyTurn = preference.getBoolean("canClickTurn",true); + // 从SharedPreferences中读取之前保存的是否允许点击翻页的配置值,如果不存在则使用默认值true,赋值给canClickTurn变量,用于确定当前是否允许点击翻页操作。 + this.canClickTurn = preference.getBoolean("canClickTurn", true); + + // 从SharedPreferences中读取之前保存的是否允许按键翻页的配置值,同样若不存在使用默认值true,赋值给canKeyTurn变量,用于判断当前是否允许按键翻页操作(这里代码可能存在重复设置canClickTurn的问题,应该是读取另一个键对应的布尔值,比如"canKeyTurn"对应的配置值,此处可能需要修正)。 + this.canKeyTurn = preference.getBoolean("canClickTurn", true); } + /** + * 获取当前的文字大小,外部代码可以调用此方法获取用于控制阅读界面文字显示大小的数值,方便根据实际情况进行展示或其他相关操作。 + * @return 当前设置的文字大小值,单位可能是像素等,具体取决于初始化和存储的设置情况。 + */ public int getTextSize() { return textSize; } + /** + * 获取当前的文字间距(额外间距),外部代码可通过调用此方法获取文字排版时的间距数值,用于调整文字展示的排版效果,使其更符合阅读习惯等需求。 + * @return 当前设置的文字间距值,单位可能是像素等,通过对应配置获取而来。 + */ public int getTextExtra() { return textExtra; } + /** + * 获取当前的文字颜色值,外部代码调用此方法可获取用于设置阅读界面文字显示颜色的数值,从而按照此颜色来渲染文字,使其呈现出特定的视觉效果。 + * @return 当前设置的文字颜色值,以Android系统的颜色表示方式存储(如ARGB等),通过配置获取得到。 + */ public int getTextColor() { return textColor; } + /** + * 获取当前的文字背景资源标识符,外部代码可利用此标识符来设置文字所在区域的背景样式,比如设置阅读界面文字背后的背景图片、颜色等样式,提升阅读的视觉感受。 + * @return 当前设置的文字背景资源的标识符(如R.drawable中的相关资源ID),通过配置获取而来,对应特定的背景样式资源。 + */ public int getTextBackground() { return textBackground; } + /** + * 获取当前选择的文字样式索引,外部代码可以通过这个索引值了解当前应用的是哪种文字样式配置,也可基于此索引进行一些相关的逻辑判断或操作(如展示当前文字样式名称等)。 + * @return 当前选择的文字样式索引值,对应textKind列表中的位置,用于定位具体的文字样式配置。 + */ public int getTextKindIndex() { return textKindIndex; } + /** + * 设置当前选择的文字样式索引,用于切换不同的文字样式,在设置新的索引值后,会将这个新值保存到SharedPreferences中实现持久化存储, + * 同时根据新的索引更新文字大小和文字间距等相关变量,确保配置的一致性,方便下次读取时能获取到最新的设置状态。 + * @param textKindIndex 要设置的文字样式索引值,需是合法的索引范围(对应textKind列表中的有效位置),用于指定新的文字样式配置。 + */ public void setTextKindIndex(int textKindIndex) { this.textKindIndex = textKindIndex; SharedPreferences.Editor editor = preference.edit(); - editor.putInt("textKindIndex",textKindIndex); + editor.putInt("textKindIndex", textKindIndex); editor.commit(); this.textSize = textKind.get(textKindIndex).get("textSize"); this.textExtra = textKind.get(textKindIndex).get("textExtra"); } + /** + * 获取当前选择的文字绘制样式索引,外部代码可通过此索引值知晓当前应用的文字颜色和文字背景的组合样式,也可用于相关的展示或逻辑判断操作。 + * @return 当前选择的文字绘制样式索引值,对应textDrawable列表中的位置,用于定位具体的文字绘制相关配置。 + */ public int getTextDrawableIndex() { return textDrawableIndex; } + /** + * 设置当前选择的文字绘制样式索引,用于切换不同的文字颜色和文字背景组合样式,在设置新的索引值后,会将其保存到SharedPreferences中持久化存储, + * 同时根据新索引更新文字颜色和文字背景等相关变量,保证配置的一致性,以便后续能按照新设置进行文字绘制相关的展示操作。 + * @param textDrawableIndex 要设置的文字绘制样式索引值,需是合法的索引范围(对应textDrawable列表中的有效位置),用于指定新的文字绘制相关配置。 + */ public void setTextDrawableIndex(int textDrawableIndex) { this.textDrawableIndex = textDrawableIndex; SharedPreferences.Editor editor = preference.edit(); - editor.putInt("textDrawableIndex",textDrawableIndex); + editor.putInt("textDrawableIndex", textDrawableIndex); editor.commit(); this.textColor = textDrawable.get(textDrawableIndex).get("textColor"); this.textBackground = textDrawable.get(textDrawableIndex).get("textBackground"); } + /** + * 获取存储文字样式相关配置信息的列表,外部代码可以通过这个列表获取所有已定义的文字样式配置内容(如文字大小、文字间距等信息), + * 例如可以用于展示给用户选择不同文字样式的界面中,展示所有可选择的文字样式详情。 + * @return 存储文字样式相关配置信息的列表,每个元素是一个Map,包含文字大小、文字间距等具体配置项。 + */ public static List> getTextKind() { return textKind; } + /** + * 获取存储文字绘制相关配置信息的列表,外部代码可利用此列表获取所有已定义的文字绘制相关配置内容(如不同的文字颜色和文字背景组合等信息), + * 例如用于在界面上展示不同文字绘制样式供用户选择,方便用户个性化阅读界面的视觉效果。 + * @return 存储文字绘制相关配置信息的列表,每个元素是一个Map,包含文字颜色、文字背景等具体配置项。 + */ public static List> getTextDrawable() { return textDrawable; } + /** + * 获取是否允许通过按键进行翻页操作的标识,外部代码可以根据这个标识来决定是否启用按键翻页相关的功能逻辑(如监听按键事件进行翻页等操作),满足用户不同的操作习惯需求。 + * @return 布尔值,true表示允许按键翻页,false表示禁止按键翻页。 + */ public Boolean getCanKeyTurn() { return canKeyTurn; } - public void setCanKeyTurn(Boolean canKeyTurn) { - this.canKeyTurn = canKeyTurn; - SharedPreferences.Editor editor = preference.edit(); - editor.putBoolean("canKeyTurn",canKeyTurn); - editor.commit(); - } - - public Boolean getCanClickTurn() { - return canClickTurn; - } - - public void setCanClickTurn(Boolean canClickTurn) { - this.canClickTurn = canClickTurn; - SharedPreferences.Editor editor = preference.edit(); - editor.putBoolean("canClickTurn",canClickTurn); - editor.commit(); - } -} \ No newline at end of file +/** + * 设置是否允许通过按键进行翻页操作,将传入的布尔值保存到SharedPreferences中实现持久化存储,用于根据用户需求改变按键翻页的可用性, + * 同时更新 \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/base/MBaseActivity.java b/app/src/main/java/com/monke/monkeybook/base/MBaseActivity.java index 2023c0c..635d216 100644 --- a/app/src/main/java/com/monke/monkeybook/base/MBaseActivity.java +++ b/app/src/main/java/com/monke/monkeybook/base/MBaseActivity.java @@ -1,20 +1,17 @@ -//Copyright (c) 2017. 章钦豪. All rights reserved. package com.monke.monkeybook.base; - import com.monke.basemvplib.IPresenter; import com.monke.basemvplib.impl.BaseActivity; import com.umeng.analytics.MobclickAgent; -public abstract class MBaseActivity extends BaseActivity{ +//定义一个抽象的Activity类MBaseActivity,它继承自BaseActivity,并且指定了泛型类型T必须实现IPresenter接口 +//这个类可以作为项目中其他具体Activity的基类,来统一处理一些公共逻辑,比如友盟统计相关逻辑等 +public abstract class MBaseActivity extends BaseActivity { + //重写Activity的onResume方法,该方法在Activity可见并准备好与用户交互时被调用 @Override protected void onResume() { + //首先调用父类(BaseActivity)的onResume方法,确保父类中相关的onResume逻辑得以执行,比如可能存在的一些界面恢复、初始化等逻辑 super.onResume(); + //调用友盟统计的onResume方法,传入当前Activity实例,目的是通知友盟统计该页面恢复到前台显示状态了,以便友盟准确统计该页面的相关数据,比如页面停留时长等 MobclickAgent.onResume(this); } - - @Override - protected void onPause() { - super.onPause(); - MobclickAgent.onPause(this); - } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/base/MBaseModelImpl.java b/app/src/main/java/com/monke/monkeybook/base/MBaseModelImpl.java index 2f69cd2..40620e1 100644 --- a/app/src/main/java/com/monke/monkeybook/base/MBaseModelImpl.java +++ b/app/src/main/java/com/monke/monkeybook/base/MBaseModelImpl.java @@ -1,40 +1,58 @@ package com.monke.monkeybook.base; - import com.monke.basemvplib.EncodoConverter; import com.monke.basemvplib.impl.RetryIntercepter; - import java.util.concurrent.TimeUnit; - import okhttp3.OkHttpClient; import retrofit2.Retrofit; import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; import retrofit2.converter.scalars.ScalarsConverterFactory; public class MBaseModelImpl { + + // 定义一个受保护的 OkHttpClient.Builder 类型的变量 clientBuilder, + // 通过创建 OkHttpClient.Builder 的实例来构建一个 OkHttpClient 的配置构建器, + // 后续可以基于这个构建器来添加各种配置项,例如设置超时时间和添加拦截器等 protected OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder() + // 设置连接超时时间为 10 秒,即客户端尝试连接服务器的最长等待时间,超过这个时间若还未成功连接则认为连接超时 .connectTimeout(10, TimeUnit.SECONDS) + // 设置写超时时间为 10 秒,指客户端向服务器写入数据的最长时间限制,防止出现长时间写入无响应的情况 .writeTimeout(10, TimeUnit.SECONDS) + // 设置读超时时间为 10 秒,意味着客户端从服务器读取数据的最长允许时间,避免长时间等待读取数据导致阻塞等问题 .readTimeout(10, TimeUnit.SECONDS) + // 添加一个名为 ProxyInterceptor 的拦截器,这个拦截器可能用于对网络请求进行一些自定义的拦截处理, + // 比如添加请求头、修改请求参数、对请求进行代理转发等操作,但具体功能取决于 ProxyInterceptor 类的实现逻辑 .addInterceptor(new ProxyInterceptor()); + // 定义一个受保护的方法 getRetrofitObject,用于构建并返回一个 Retrofit 实例, + // 这个方法接收一个表示网络请求基础 URL 的字符串参数,用于配置 Retrofit 实例与哪个服务器地址进行通信 protected Retrofit getRetrofitObject(String url) { + // 通过 Retrofit.Builder 创建一个 Retrofit 的构建器实例,开始构建 Retrofit 对象, + // 构建过程中通过链式调用各种方法来添加不同的配置项 return new Retrofit.Builder().baseUrl(url) - //增加返回值为字符串的支持(以实体类返回) + // 添加 ScalarsConverterFactory,使得 Retrofit 支持网络请求直接返回原始字符串类型的数据, + // 方便处理一些简单的文本数据返回的网络请求场景,不需要额外的复杂数据解析步骤 .addConverterFactory(ScalarsConverterFactory.create()) - //增加返回值为Oservable的支持 + // 添加 RxJava2CallAdapterFactory,让 Retrofit 能够将网络请求的返回结果转换为 RxJava 的 Observable 类型, + // 便于后续利用 RxJava 的响应式编程特性(如链式操作、异步处理、错误处理等)来处理网络请求的结果 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + // 将之前配置好的 OkHttpClient 实例(通过 clientBuilder 构建完成)设置到 Retrofit 中, + // 这样 Retrofit 在发起网络请求时就会使用这个配置好的客户端来进行实际的 HTTP 操作 .client(clientBuilder.build()) + // 最后通过 build 方法完成 Retrofit 对象的构建并返回,得到一个可用于发起具体网络请求的 Retrofit 实例 .build(); } protected Retrofit getRetrofitString(String url, String encode) { + // 与 getRetrofitObject 方法类似,通过 Retrofit.Builder 开始构建 Retrofit 对象,先指定基础 URL return new Retrofit.Builder().baseUrl(url) - //增加返回值为字符串的支持(以实体类返回) + // 添加 EncodoConverter,通过传入指定的编码格式 encode,使得 Retrofit 在处理返回值为字符串的网络请求时, + // 可以按照这个编码格式进行数据的转换或解析等操作,确保返回的字符串数据符合预期的编码要求 .addConverterFactory(EncodoConverter.create(encode)) - //增加返回值为Oservable的支持 + // 同样添加 RxJava2CallAdapterFactory,使 Retrofit 支持将返回结果转换为 RxJava 的 Observable 类型,便于后续进行响应式编程处理 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + // 将配置好的 OkHttpClient 实例设置到 Retrofit 中,为网络请求提供实际的客户端支持 .client(clientBuilder.build()) + // 完成 Retrofit 对象的构建并返回,得到一个适合处理特定编码格式字符串返回值的网络请求的 Retrofit 实例 .build(); } - } \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/base/ProxyInterceptor.java b/app/src/main/java/com/monke/monkeybook/base/ProxyInterceptor.java index 343cd81..8180c01 100644 --- a/app/src/main/java/com/monke/monkeybook/base/ProxyInterceptor.java +++ b/app/src/main/java/com/monke/monkeybook/base/ProxyInterceptor.java @@ -2,52 +2,92 @@ package com.monke.monkeybook.base; import com.monke.monkeybook.ProxyManager; import com.monke.monkeybook.utils.aes.AESUtil; - import org.jsoup.helper.StringUtil; - import java.io.IOException; import java.net.URLEncoder; import java.util.UUID; - import okhttp3.HttpUrl; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; - public class ProxyInterceptor implements Interceptor { + + // 类的默认构造函数,目前为空实现,不过在一些场景下可能后续会添加一些初始化相关的逻辑, + // 比如初始化一些成员变量等,但目前仅作为满足类构造的基本要求 public ProxyInterceptor() { } + // 重写 Interceptor 接口中的 intercept 方法,这个方法就是拦截器发挥作用的核心方法, + // 当网络请求经过这个拦截器时,会执行该方法内定义的逻辑,在这里可以对请求进行修改、重定向,或者对响应进行处理等操作 @Override public Response intercept(Chain chain) throws IOException { + // 获取当前拦截到的网络请求对象,这个对象包含了本次请求原本的所有信息, + // 例如请求的 URL、请求头、请求方法等,后续可以基于这个原始请求进行各种修改操作 Request oldRequest = chain.request(); + + // 通过 ProxyManager 类的 hasProxy 方法判断当前是否处于代理模式, + // 如果是代理模式,则执行后续优先请求代理服务器的相关逻辑;若不是代理模式,则直接继续原请求链路, + // 最后返回原请求对应的响应结果(在代码后面有对应的处理逻辑) if (ProxyManager.hasProxy()) { //如果是代理模式则优先请求代理服务器,失败再自行本地请求 - //获取request的创建者builder + // 获取当前请求对象的构建器(Builder),通过这个构建器可以方便地对请求进行修改, + // 例如修改请求头、修改 URL、修改请求方法等,而不需要直接操作原始的请求对象,符合构建者设计模式的理念 Request.Builder builder = oldRequest.newBuilder(); + + // 获取原始请求的 URL 并转换为字符串形式,后续可以基于这个字符串 URL 进行编码等操作, + // 确保 URL 在传递给代理服务器等场景下格式正确且符合要求 String oldUrl = oldRequest.url().toString(); + + // 使用 StringUtil 工具类的 isBlank 方法判断获取到的原始 URL 字符串是否为空(包括 null 或者空字符串的情况), + // 如果不为空,则对其进行 UTF-8 编码处理,避免 URL 中包含特殊字符导致解析错误等问题 if (!StringUtil.isBlank(oldUrl)) { oldUrl = URLEncoder.encode(oldUrl, "utf-8"); } + try { + // 生成一个临时字符串,它由应用的包名(通过 ProxyManager.packageName 获取)、 + // 一个随机生成的 UUID(通过 UUID.randomUUID().toString() 获取,保证每次请求有唯一标识)以及当前系统时间戳(System.currentTimeMillis())组成, + // 这个临时字符串可能用于后续在代理请求中作为一个标识或者加密的原始数据等用途 String temp = ProxyManager.packageName + UUID.randomUUID().toString() + System.currentTimeMillis(); + // 使用 AESUtil 类的 aesEncode 方法对临时字符串进行 AES 加密操作,传入的加密密钥是通过 ProxyManager.PROXY_PACKAGENAME_ENCODE 获取的, + // 加密后的结果将作为一个重要参数用于构建代理请求等操作,以保证数据传输的安全性或者符合代理服务器的特定要求 String key = AESUtil.aesEncode(temp.trim(), ProxyManager.PROXY_PACKAGENAME_ENCODE); try { - key = URLEncoder.encode(key,"utf-8"); + // 对加密后的 key 再次进行 UTF-8 编码操作,确保它在作为 URL 查询参数等传递过程中格式正确, + // 如果编码过程中出现异常(例如不支持的字符等情况),则直接使用原始未再次编码的 key(也就是 temp.trim() 的值) + key = URLEncoder.encode(key, "utf-8"); } catch (Exception e) { key = temp.trim(); } + + // 使用 HttpUrl.parse 方法将代理服务器的地址(通过 ProxyManager.proxyHttp 获取)解析为 HttpUrl 对象, + // 然后通过 newBuilder 方法获取这个 URL 的构建器,以便后续添加查询参数等操作来构建完整的代理请求 URL HttpUrl newBaseUrl = HttpUrl.parse(ProxyManager.proxyHttp).newBuilder() + // 使用 setQueryParameter 方法添加名为 "proxyUrl" 的查询参数,其值为前面处理好的原始请求 URL(经过编码后的 oldUrl), + // 这样代理服务器就能知道要代理的具体目标 URL 是什么了 .setQueryParameter("proxyUrl", oldUrl) + // 再添加名为 "proxyPackagename" 的查询参数,其值为前面处理好的加密 key(经过编码或者原始的 key), + // 这个参数可能用于代理服务器识别请求来源、进行权限验证等用途 .setQueryParameter("proxyPackagename", key) + // 最后通过 build 方法构建出完整的代理请求 URL 对象 .build(); + + // 使用 chain.proceed 方法发起实际的代理请求,传入构建好的新请求对象(通过 builder.url(newBaseUrl).build() 构建), + // 这个方法会继续执行网络请求链路,直到获取到代理服务器返回的响应对象,后续可以对这个响应进行判断和处理 Response response = chain.proceed(builder.url(newBaseUrl).build()); + // 判断代理请求的响应是否成功(通常根据响应的状态码等判断,例如状态码在 200 - 299 之间表示成功), + // 如果成功,则直接返回这个代理请求得到的响应对象,不再进行后续的原请求相关处理了 if (response.isSuccessful()) { return response; } } catch (Exception e) { - + // 如果在构建代理请求、进行加密操作、发起代理请求等过程中出现任何异常情况, + // 在这里目前只是捕获异常但没有做任何具体处理(可能后续可以添加日志记录、错误提示等逻辑), + // 然后会继续执行后续原请求相关的逻辑,尝试直接发起本地请求获取响应 } } + + // 如果不是代理模式或者代理请求失败了,则继续执行原请求链路,通过 chain.proceed 方法发起原始的网络请求, + // 并获取对应的响应对象,最后返回这个原请求得到的响应对象,完成整个拦截器的逻辑处理 Response oldResponse = chain.proceed(oldRequest); return oldResponse; } diff --git a/app/src/main/java/com/monke/monkeybook/base/observer/SimpleObserClass.java b/app/src/main/java/com/monke/monkeybook/base/observer/SimpleObserClass.java index eebb0e3..9e2e25b 100644 --- a/app/src/main/java/com/monke/monkeybook/base/observer/SimpleObserClass.java +++ b/app/src/main/java/com/monke/monkeybook/base/observer/SimpleObserClass.java @@ -1,12 +1,13 @@ -//Copyright (c) 2017. 章钦豪. All rights reserved. package com.monke.monkeybook.base.observer; import com.monke.monkeybook.utils.NetworkUtil; public class SimpleObserClass { + private int code; private T t; + //构造函数,接收一个泛型类型的参数t,调用另一个构造函数并传递t和默认的成功状态码 public SimpleObserClass(T t){ this(t,NetworkUtil.SUCCESS); } @@ -16,23 +17,29 @@ public class SimpleObserClass { this.code = code; } + //获取成员变量code的值,即获取当前存储的状态码,外部可以通过调用这个方法来了解相关操作的状态情况 public int getCode() { return code; } + //设置成员变量code的值,用于在需要更新状态码的情况下,从外部传入新的状态码来改变当前存储的状态码信息 public void setCode(int code) { this.code = code; } + //定义一个方法success,用于判断当前的状态码是否与NetworkUtil中定义的表示成功的状态码相等, + //返回一个布尔值,如果相等则表示操作成功,返回true;否则返回false,方便外部快速判断当前操作是否成功 public Boolean success(){ return code == NetworkUtil.SUCCESS; } + //获取成员变量t的值,即获取当前存储的泛型数据对象,外部可以通过调用这个方法来获取具体的数据内容 public T getT() { return t; } + //设置成员变量t的值,用于在需要更新数据对象的情况下,从外部传入新的数据来替换当前存储的数据内容 public void setT(T t) { this.t = t; } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/base/observer/SimpleObserver.java b/app/src/main/java/com/monke/monkeybook/base/observer/SimpleObserver.java index f445a84..12d2763 100644 --- a/app/src/main/java/com/monke/monkeybook/base/observer/SimpleObserver.java +++ b/app/src/main/java/com/monke/monkeybook/base/observer/SimpleObserver.java @@ -1,18 +1,24 @@ -//Copyright (c) 2017. 章钦豪. All rights reserved. package com.monke.monkeybook.base.observer; import io.reactivex.Observer; + import io.reactivex.disposables.Disposable; public abstract class SimpleObserver implements Observer { + //重写Observer接口中的onSubscribe方法,该方法会在观察者与被观察者建立订阅关系时被调用, + //传入的Disposable参数用于管理这个订阅关系,例如可以保存这个Disposable对象,在合适的时候调用其dispose方法来取消订阅, + //当前这个抽象类中此方法为空实现,具体的操作可以由子类根据业务需求来补充,比如记录订阅开始的相关日志等 @Override public void onSubscribe(Disposable d) { } + //重写Observer接口中的onComplete方法,该方法会在被观察者完成所有数据的发送,并且不会再发送任何新数据时被调用, + //通常在这个方法里可以进行一些清理资源、更新UI显示等操作,表示整个数据观察过程已经结束, + //当前这个抽象类中此方法同样为空实现,由子类根据具体业务场景去决定如何处理这个事件,比如隐藏加载动画等操作 @Override public void onComplete() { } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/bean/BookContentBean.java b/app/src/main/java/com/monke/monkeybook/bean/BookContentBean.java index c0d31ea..b5f09de 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/BookContentBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/BookContentBean.java @@ -1,4 +1,3 @@ -//Copyright (c) 2017. 章钦豪. All rights reserved. package com.monke.monkeybook.bean; import android.os.Parcel; @@ -13,57 +12,110 @@ import java.util.List; /** * 书本缓存内容 + * 这个类用于表示书本缓存相关的信息,实现了Parcelable接口以便能在不同组件间方便地传递该对象(比如用于Activity、Fragment之间传递数据等情况)。 */ @Entity -public class BookContentBean implements Parcelable{ - @Id - private String durChapterUrl; //对应BookInfoBean noteUrl; - - private int durChapterIndex; //当前章节 (包括番外) - - private String durCapterContent; //当前章节内容 - - private String tag; //来源 某个网站/本地 +public class BookContentBean implements Parcelable { + /** + * 对应BookInfoBean的noteUrl,作为书本缓存内容的唯一标识,通常可以是章节对应的URL地址等,在数据库存储(如果使用相关数据库框架的话,此处有@Entity注解,可能关联数据库操作)中可作为主键来区分不同的缓存章节内容。 + */ + @Id + private String durChapterUrl; + + /** + * 当前章节索引(包括番外章节),用于标记当前缓存内容对应的是书本中的哪一个章节,方便按顺序或者指定章节来获取、展示内容等操作。 + */ + private int durChapterIndex; + + /** + * 当前章节的具体文本内容,也就是实际缓存下来的书本章节文字内容。 + */ + private String durCapterContent; + + /** + * 内容来源标识,比如注明是来自某个特定的网站或者本地文件等,方便后续对不同来源的内容进行区分处理或者溯源等操作。 + */ + private String tag; + + /** + * @Transient注解表示这个字段不会被持久化(比如在使用相关数据库框架存储对象时,该字段不会存入数据库)。 + * 这里用于表示当前缓存内容是否正确的一个标识,初始化为true,表示默认认为缓存内容是正确的,后续可根据实际情况进行修改。 + */ @Transient private Boolean isRight = true; + /** + * @Transient注解表示这个字段不会被持久化(比如在使用相关数据库框架存储对象时,该字段不会存入数据库)。 + * 用于存储按行划分后的章节内容,每一个元素代表一行文字内容,方便对章节内容进行逐行处理,比如排版展示等操作。 + */ @Transient private List lineContent = new ArrayList<>(); + /** + * @Transient注解表示这个字段不会被持久化(比如在使用相关数据库框架存储对象时,该字段不会存入数据库)。 + * 可能用于表示每行文字的字号大小等相关属性,具体含义需根据实际使用场景确定。 + */ @Transient private float lineSize; - public BookContentBean(){ + /** + * 默认构造函数,用于创建BookContentBean对象实例时进行默认的初始化操作。 + */ + public BookContentBean() { } + /** + * 获取每行文字的字号大小属性值。 + * @return 表示每行文字字号大小的float值。 + */ public float getLineSize() { return lineSize; } + /** + * 设置每行文字的字号大小属性值。 + * @param lineSize 要设置的每行文字字号大小的float值。 + */ public void setLineSize(float lineSize) { this.lineSize = lineSize; } + /** + * 用于从一个Parcel对象中恢复BookContentBean对象的构造函数,这是实现Parcelable接口要求的方法,用于对象的解包还原。 + * @param in 包含对象序列化数据的Parcel对象。 + */ protected BookContentBean(Parcel in) { durChapterUrl = in.readString(); durChapterIndex = in.readInt(); durCapterContent = in.readString(); tag = in.readString(); lineContent = in.createStringArrayList(); - isRight = in.readByte()!=0; + isRight = in.readByte()!= 0; } + /** + * 带有参数的构造函数,用于在已知相关属性值的情况下创建BookContentBean对象实例,方便在代码中初始化对象并赋值相关重要属性。 + * @param durChapterUrl 对应章节的URL地址,作为唯一标识。 + * @param durChapterIndex 当前章节索引。 + * @param durCapterContent 当前章节的文本内容。 + * @param tag 内容来源标识。 + */ @Generated(hash = 1355824386) public BookContentBean(String durChapterUrl, int durChapterIndex, - String durCapterContent, String tag) { + String durCapterContent, String tag) { this.durChapterUrl = durChapterUrl; this.durChapterIndex = durChapterIndex; this.durCapterContent = durCapterContent; this.tag = tag; } + /** + * 将BookContentBean对象的属性数据写入到Parcel对象中,以便进行对象的序列化操作,这是实现Parcelable接口要求的方法,用于对象的打包发送。 + * @param dest 要写入数据的Parcel对象。 + * @param flags 一些额外的标志位,一般使用默认值即可,可用于控制特殊的序列化行为等情况(但此处暂未体现特殊使用场景)。 + */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(durChapterUrl); @@ -71,14 +123,21 @@ public class BookContentBean implements Parcelable{ dest.writeString(durCapterContent); dest.writeString(tag); dest.writeStringList(lineContent); - dest.writeByte((byte) (isRight ? 1 : 0)); + dest.writeByte((byte) (isRight? 1 : 0)); } + /** + * 返回当前对象的描述信息,一般如果对象内部有文件描述符等特殊情况需要返回相应的描述标记,此处返回0表示没有特殊内容需要描述,这是实现Parcelable接口要求的方法。 + * @return 一般返回0,表示没有特殊描述内容。 + */ @Override public int describeContents() { return 0; } + /** + * 用于创建BookContentBean对象的静态内部类Creator,实现了Parcelable.Creator接口,提供了从Parcel对象创建BookContentBean对象实例以及创建对象数组的方法,这是实现Parcelable接口要求的配套部分。 + */ @Transient public static final Creator CREATOR = new Creator() { @Override @@ -92,53 +151,101 @@ public class BookContentBean implements Parcelable{ } }; + /** + * 获取对应章节的URL地址(唯一标识)。 + * @return 章节对应的URL地址字符串。 + */ public String getDurChapterUrl() { return durChapterUrl; } + /** + * 设置对应章节的URL地址(唯一标识)。 + * @param durChapterUrl 要设置的章节对应的URL地址字符串。 + */ public void setDurChapterUrl(String durChapterUrl) { this.durChapterUrl = durChapterUrl; } + /** + * 获取当前章节索引。 + * @return 当前章节的索引值(整数)。 + */ public int getDurChapterIndex() { return durChapterIndex; } + /** + * 设置当前章节索引。 + * @param durChapterIndex 要设置的当前章节索引值(整数)。 + */ public void setDurChapterIndex(int durChapterIndex) { this.durChapterIndex = durChapterIndex; } + /** + * 获取当前章节的文本内容。 + * @return 当前章节的文本内容字符串。 + */ public String getDurCapterContent() { return durCapterContent; } + /** + * 设置当前章节的文本内容,并根据内容是否为空来更新isRight标识,若内容为空,则将isRight设置为false,表示缓存内容可能不正确。 + * @param durCapterContent 要设置的当前章节的文本内容字符串。 + */ public void setDurCapterContent(String durCapterContent) { this.durCapterContent = durCapterContent; - if(durCapterContent==null || durCapterContent.length()==0) + if (durCapterContent == null || durCapterContent.length() == 0) this.isRight = false; } + /** + * 获取内容来源标识。 + * @return 内容来源的标识字符串。 + */ public String getTag() { return tag; } + /** + * 设置内容来源标识。 + * @param tag 要设置的内容来源的标识字符串。 + */ public void setTag(String tag) { this.tag = tag; } + /** + * 获取按行划分后的章节内容列表。 + * @return 包含每行文字内容的List对象。 + */ public List getLineContent() { return lineContent; } + /** + * 设置按行划分后的章节内容列表。 + * @param lineContent 要设置的包含每行文字内容的List对象。 + */ public void setLineContent(List lineContent) { this.lineContent = lineContent; } + /** + * 获取当前缓存内容是否正确的标识。 + * @return true表示缓存内容正确,false表示可能不正确。 + */ public Boolean getRight() { return isRight; } + /** + * 设置当前缓存内容是否正确的标识。 + * @param right 要设置的表示缓存内容是否正确的布尔值。 + */ public void setRight(Boolean right) { isRight = right; } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/bean/BookInfoBean.java b/app/src/main/java/com/monke/monkeybook/bean/BookInfoBean.java index 43c254d..5abbfa4 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/BookInfoBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/BookInfoBean.java @@ -13,39 +13,88 @@ import java.util.List; /** * 书本信息 + * 此类用于封装书本相关的各种基础信息,实现了Parcelable接口以便能在不同组件间方便地传递书本信息对象, + * 同时实现了Cloneable接口用于创建对象的副本,方便在某些需要复制对象并进行独立操作的场景下使用。 */ @Entity -public class BookInfoBean implements Parcelable,Cloneable{ +public class BookInfoBean implements Parcelable, Cloneable { + /** + * @Transient注解表示这个字段不会被持久化(例如在使用相关数据库框架存储对象时,该字段不会存入数据库)。 + * 定义了书本信息的刷新间隔时间,单位为毫秒,此处设置为10分钟(10 * 60 * 1000毫秒), + * 可用于判断书本章节等信息是否需要重新刷新获取,比如根据这个时间间隔来决定是否重新从网络或其他数据源更新书本章节内容等情况。 + */ @Transient - public static final long REFRESH_DUR = 10*60*1000; + public static final long REFRESH_DUR = 10 * 60 * 1000; + /** + * 小说的名称,用于标识书本,方便展示给用户以及在程序内部进行相关查找、排序等操作。 + */ private String name; //小说名 + /** + * 用于给书本添加额外的标识标签,具体含义可根据业务需求确定,比如可以用来区分不同类型、不同来源或者不同分类下的书本等情况。 + */ private String tag; + /** + * @Id注解表示这个字段在相关数据库操作(如果使用了对应支持此注解的数据库框架,例如 GreenDao)中可作为主键来唯一标识一条书本记录。 + * 如果书本来源是网站,此处存储小说的根地址;如果是本地书本,则存储小说本地的MD5值,用于区分不同的书本资源。 + */ @Id private String noteUrl; //如果是来源网站 则小说根地址 /如果是本地 则是小说本地MD5 + /** + * 存储章节目录对应的地址,例如网络小说可能是获取章节列表的网络接口地址,本地小说可能是本地存储章节列表信息的文件路径等, + * 通过这个地址可以进一步获取书本详细的章节信息。 + */ private String chapterUrl; //章节目录地址 + /** + * @Transient注解表示这个字段不会被持久化(例如在使用相关数据库框架存储对象时,该字段不会存入数据库)。 + * 用于存储书本的章节列表信息,每个元素是ChapterListBean类型,表示具体的章节相关数据,方便对书本的章节进行管理、展示等操作。 + */ @Transient private List chapterlist = new ArrayList<>(); //章节列表 + /** + * 记录章节最后更新的时间戳,单位为毫秒,可用于与当前时间对比,结合REFRESH_DUR来判断是否需要更新章节内容, + * 例如判断距离上次更新是否超过了设定的刷新间隔时间等情况。 + */ private long finalRefreshData; //章节最后更新时间 + /** + * 存储小说封面的地址,对于网络小说可能是封面图片的网络链接,本地小说则可能是本地封面图片文件的路径,用于展示书本的封面给用户查看。 + */ private String coverUrl; //小说封面 - private String author;//作者 + /** + * 记录小说的作者信息,方便展示给用户了解书本的创作来源,也可用于一些根据作者进行分类、搜索等相关功能的实现。 + */ + private String author; //作者 + /** + * 存储小说的简介内容,一般用于向用户简要介绍书本的大致内容、风格、主题等情况,帮助用户快速了解书本情况,决定是否阅读。 + */ private String introduce; //简介 + /** + * 标明小说的来源信息,比如是来自某个特定网站、本地导入或者其他渠道等,方便后续对不同来源的书本进行差异化处理等操作。 + */ private String origin; //来源 - public BookInfoBean(){ + /** + * 默认构造函数,用于创建BookInfoBean对象实例时进行默认的初始化操作,通常在没有初始值传入时使用,创建一个默认状态的书本信息对象。 + */ + public BookInfoBean() { } + /** + * 用于从一个Parcel对象中恢复BookInfoBean对象的构造函数,这是实现Parcelable接口要求的方法,用于对象的解包还原, + * 从传入的Parcel中按照顺序读取之前写入的各个属性值,来初始化当前对象的各个成员变量。 + * @param in 包含对象序列化数据的Parcel对象。 + */ protected BookInfoBean(Parcel in) { name = in.readString(); tag = in.readString(); @@ -59,10 +108,23 @@ public class BookInfoBean implements Parcelable,Cloneable{ origin = in.readString(); } + /** + * 带有参数的构造函数,用于在已知相关属性值的情况下创建BookInfoBean对象实例,方便在代码中初始化对象并赋值相关重要属性, + * 根据传入的各个参数值来分别设置对象的成员变量,构建一个完整的书本信息对象。 + * @param name 小说名称。 + * @param tag 书本的标识标签。 + * @param noteUrl 书本的唯一标识(网站根地址或本地MD5值)。 + * @param chapterUrl 章节目录地址。 + * @param finalRefreshData 章节最后更新时间戳。 + * @param coverUrl 小说封面地址。 + * @param author 作者信息。 + * @param introduce 小说简介内容。 + * @param origin 小说来源信息。 + */ @Generated(hash = 1627552162) public BookInfoBean(String name, String tag, String noteUrl, String chapterUrl, - long finalRefreshData, String coverUrl, String author, String introduce, - String origin) { + long finalRefreshData, String coverUrl, String author, String introduce, + String origin) { this.name = name; this.tag = tag; this.noteUrl = noteUrl; @@ -74,6 +136,12 @@ public class BookInfoBean implements Parcelable,Cloneable{ this.origin = origin; } + /** + * 将BookInfoBean对象的属性数据写入到Parcel对象中,以便进行对象的序列化操作,这是实现Parcelable接口要求的方法,用于对象的打包发送, + * 按照一定顺序将对象的各个属性值写入到传入的Parcel对象中,方便后续进行传递和还原操作。 + * @param dest 要写入数据的Parcel对象。 + * @param flags 一些额外的标志位,一般使用默认值即可,可用于控制特殊的序列化行为等情况(但此处暂未体现特殊使用场景)。 + */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); @@ -88,11 +156,18 @@ public class BookInfoBean implements Parcelable,Cloneable{ dest.writeString(origin); } + /** + * 返回当前对象的描述信息,一般如果对象内部有文件描述符等特殊情况需要返回相应的描述标记,此处返回0表示没有特殊内容需要描述,这是实现Parcelable接口要求的方法。 + * @return 一般返回0,表示没有特殊描述内容。 + */ @Override public int describeContents() { return 0; } + /** + * 用于创建BookInfoBean对象的静态内部类Creator,实现了Parcelable.Creator接口,提供了从Parcel对象创建BookInfoBean对象实例以及创建对象数组的方法,这是实现Parcelable接口要求的配套部分。 + */ @Transient public static final Creator CREATOR = new Creator() { @Override @@ -106,89 +181,182 @@ public class BookInfoBean implements Parcelable,Cloneable{ } }; + /** + * 获取小说的名称。 + * @return 书本的名称字符串。 + */ public String getName() { return name; } + /** + * 设置小说的名称。 + * @param name 要设置的小说名称字符串。 + */ public void setName(String name) { this.name = name; } + /** + * 获取书本的标识标签。 + * @return 书本的标识标签字符串。 + */ public String getTag() { return tag; } + /** + * 设置书本的标识标签。 + * @param tag 要设置的书本标识标签字符串。 + */ public void setTag(String tag) { this.tag = tag; } + /** + * 获取书本的唯一标识(网站根地址或本地MD5值)。 + * @return 书本的唯一标识字符串(noteUrl)。 + */ public String getNoteUrl() { return noteUrl; } + /** + * 设置书本的唯一标识(网站根地址或本地MD5值)。 + * @param noteUrl 要设置的书本唯一标识字符串。 + */ public void setNoteUrl(String noteUrl) { this.noteUrl = noteUrl; } + /** + * 获取章节目录地址。 + * @return 章节目录地址字符串。 + */ public String getChapterUrl() { return chapterUrl; } + /** + * 设置章节目录地址。 + * @param chapterUrl 要设置的章节目录地址字符串。 + */ public void setChapterUrl(String chapterUrl) { this.chapterUrl = chapterUrl; } + /** + * 获取书本的章节列表信息。 + * @return 包含ChapterListBean元素的List,表示书本的章节列表。 + */ public List getChapterlist() { return chapterlist; } + /** + * 设置书本的章节列表信息,直接替换原有的章节列表数据。 + * @param chapterlist 要设置的包含ChapterListBean元素的List,表示新的章节列表。 + */ public void setChapterlist(List chapterlist) { this.chapterlist = chapterlist; } - public void addChapterlist(List chapterlist){ + + /** + * 将传入的章节列表数据添加到现有的章节列表中,用于合并章节列表信息,例如分批获取章节数据后进行合并汇总的场景。 + * @param chapterlist 要添加的包含ChapterListBean元素的List,表示新的章节列表数据。 + */ + public void addChapterlist(List chapterlist) { this.chapterlist.addAll(chapterlist); } + /** + * 获取章节最后更新的时间戳。 + * @return 章节最后更新时间的长整型时间戳,单位为毫秒。 + */ public long getFinalRefreshData() { return finalRefreshData; } + /** + * 设置章节最后更新的时间戳。 + * @param finalRefreshData 要设置的章节最后更新时间的长整型时间戳,单位为毫秒。 + */ public void setFinalRefreshData(long finalRefreshData) { this.finalRefreshData = finalRefreshData; } + /** + * 获取小说封面的地址。 + * @return 小说封面地址字符串。 + */ public String getCoverUrl() { return coverUrl; } + /** + * 设置小说封面的地址。 + * @param coverUrl 要设置的小说封面地址字符串。 + */ public void setCoverUrl(String coverUrl) { this.coverUrl = coverUrl; } + /** + * 获取小说的作者信息。 + * @return 作者信息字符串。 + */ public String getAuthor() { return author; } + /** + * 设置小说的作者信息。 + * @param author 要设置的作者信息字符串。 + */ public void setAuthor(String author) { this.author = author; } + /** + * 获取小说的简介内容。 + * @return 小说简介内容字符串。 + */ public String getIntroduce() { return introduce; } + /** + * 设置小说的简介内容。 + * @param introduce 要设置的小说简介内容字符串。 + */ public void setIntroduce(String introduce) { this.introduce = introduce; } + /** + * 获取小说的来源信息。 + * @return 小说来源信息字符串。 + */ public String getOrigin() { return this.origin; } + /** + * 设置小说的来源信息。 + * @param origin 要设置的小说来源信息字符串。 + */ public void setOrigin(String origin) { this.origin = origin; } + /** + * 重写了Object类的clone方法,用于创建当前BookInfoBean对象的副本,在克隆过程中, + * 先调用父类的clone方法创建一个基础的对象副本,然后将原对象的各个属性值复制到副本对象中, + * 对于章节列表部分,需要逐个克隆章节列表中的ChapterListBean元素,并组成新的列表设置到副本对象中, + * 最终返回克隆后的完整BookInfoBean对象副本,可用于在不影响原对象的情况下进行独立操作等场景。 + * @return 克隆后的BookInfoBean对象副本。 + * @throws CloneNotSupportedException 如果对象所在类没有实现Cloneable接口或者在克隆过程中出现不支持克隆的情况时抛出此异常。 + */ @Override protected Object clone() throws CloneNotSupportedException { BookInfoBean bookInfoBean = (BookInfoBean) super.clone(); @@ -200,10 +368,10 @@ public class BookInfoBean implements Parcelable,Cloneable{ bookInfoBean.author = author; bookInfoBean.introduce = introduce; bookInfoBean.origin = origin; - if(chapterlist!=null){ + if (chapterlist!= null) { List newList = new ArrayList<>(); Iterator iterator = chapterlist.iterator(); - while(iterator.hasNext()){ + while (iterator.hasNext()) { newList.add((ChapterListBean) iterator.next().clone()); } bookInfoBean.setChapterlist(newList); diff --git a/app/src/main/java/com/monke/monkeybook/bean/BookShelfBean.java b/app/src/main/java/com/monke/monkeybook/bean/BookShelfBean.java index 0a6ee7e..4fe220f 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/BookShelfBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/BookShelfBean.java @@ -11,33 +11,74 @@ import org.greenrobot.greendao.annotation.Transient; /** * 书架item Bean + * 此类用于表示书架上每一项对应的书本相关信息,实现了Parcelable接口以便在不同组件间传递该对象(例如在Activity之间传递书架上书本的相关状态等信息), + * 同时实现了Cloneable接口用于创建对象的副本,方便在需要复制书本书架相关状态进行独立操作的场景下使用。 */ - @Entity -public class BookShelfBean implements Parcelable,Cloneable{ +public class BookShelfBean implements Parcelable, Cloneable { + + /** + * @Transient注解表示这个字段不会被持久化(比如在使用相关数据库框架存储对象时,该字段不会存入数据库)。 + * 定义了书本在书架上的更新时间间隔,单位为毫秒,此处设置为5分钟(5 * 60 * 1000毫秒), + * 可用于判断书本相关信息(如章节内容、阅读进度等)是否需要根据一定规则进行更新,例如判断距离上次更新操作是否超过了这个时间间隔来决定是否重新获取或刷新书本的部分数据等情况。 + */ @Transient - public static final long REFRESH_TIME = 5*60*1000; //更新时间间隔 至少 + public static final long REFRESH_TIME = 5 * 60 * 1000; //更新时间间隔 至少 + + /** + * @Transient注解表示这个字段不会被持久化(比如在使用相关数据库框架存储对象时,该字段不会存入数据库)。 + * 定义了一个表示本地书本的标识标签,用于区分书本来源是本地的情况,方便在程序中对本地书本进行统一的处理或者判断等操作。 + */ @Transient public static final String LOCAL_TAG = "loc_book"; + /** + * @Id注解表示这个字段在相关数据库操作(如果使用了对应支持此注解的数据库框架,例如 GreenDao)中可作为主键来唯一标识一条书架上书本的记录。 + * 对应BookInfoBean中的noteUrl,通常如果是来源网站,此处存储小说的根地址;如果是本地书本,则存储小说本地的MD5值,以此来区分不同的书本资源在书架上的记录。 + */ @Id private String noteUrl; //对应BookInfoBean noteUrl; + /** + * 当前章节索引(包括番外章节),用于记录用户阅读到书本的哪一个章节位置,方便下次打开时能定位到相应章节继续阅读等操作。 + */ private int durChapter; //当前章节 (包括番外) + /** + * 当前章节位置,以页码的形式表示,初始值为BookContentView.DURPAGEINDEXBEGIN(具体含义需参考BookContentView中对该常量的定义,通常可能是章节起始页码相关设定), + * 用于更精确地定位用户在当前章节内阅读到的具体页面位置,例如实现翻页功能时确定当前所在页码等情况。 + */ private int durChapterPage = BookContentView.DURPAGEINDEXBEGIN; // 当前章节位置 用页码 + /** + * 最后阅读时间的时间戳,单位为毫秒,记录用户最后一次阅读该书本的时间,可用于多种用途,比如按照阅读时间排序书架上的书本、判断书本是否长时间未读等情况。 + */ private long finalDate; //最后阅读时间 + /** + * 用于给书架上的书本添加额外的标识标签,具体含义可根据业务需求确定,比如可以用来区分不同类型、不同分类或者不同状态下的书本等情况,与BookInfoBean中的tag类似但可能有不同的使用场景(可能侧重书架层面的分类标识)。 + */ private String tag; + /** + * @Transient注解表示这个字段不会被持久化(比如在使用相关数据库框架存储对象时,该字段不会存入数据库)。 + * 用于存储书本更详细的信息,是BookInfoBean类型的对象,包含了如小说名、作者、简介、章节列表等丰富的书本基础信息,方便在书架相关操作中获取和使用这些详细内容。 + */ @Transient private BookInfoBean bookInfoBean = new BookInfoBean(); - public BookShelfBean(){ + /** + * 默认构造函数,用于创建BookShelfBean对象实例时进行默认的初始化操作,通常在没有初始值传入时使用,创建一个默认状态的书架书本信息对象。 + */ + public BookShelfBean() { } + /** + * 用于从一个Parcel对象中恢复BookShelfBean对象的构造函数,这是实现Parcelable接口要求的方法,用于对象的解包还原, + * 从传入的Parcel中按照顺序读取之前写入的各个属性值,来初始化当前对象的各个成员变量,包括从Parcel中读取并还原BookInfoBean对象。 + * @param in 包含对象序列化数据的Parcel对象。 + */ protected BookShelfBean(Parcel in) { noteUrl = in.readString(); durChapter = in.readInt(); @@ -47,9 +88,18 @@ public class BookShelfBean implements Parcelable,Cloneable{ bookInfoBean = in.readParcelable(BookInfoBean.class.getClassLoader()); } + /** + * 带有参数的构造函数,用于在已知相关属性值的情况下创建BookShelfBean对象实例,方便在代码中初始化对象并赋值相关重要属性, + * 根据传入的各个参数值来分别设置对象的成员变量,构建一个完整的书架书本信息对象。 + * @param noteUrl 书本的唯一标识(对应BookInfoBean中的noteUrl,网站根地址或本地MD5值)。 + * @param durChapter 当前章节索引。 + * @param durChapterPage 当前章节页码位置。 + * @param finalDate 最后阅读时间戳。 + * @param tag 书本的标识标签。 + */ @Generated(hash = 2028192361) public BookShelfBean(String noteUrl, int durChapter, int durChapterPage, long finalDate, - String tag) { + String tag) { this.noteUrl = noteUrl; this.durChapter = durChapter; this.durChapterPage = durChapterPage; @@ -57,6 +107,12 @@ public class BookShelfBean implements Parcelable,Cloneable{ this.tag = tag; } + /** + * 将BookShelfBean对象的属性数据写入到Parcel对象中,以便进行对象的序列化操作,这是实现Parcelable接口要求的方法,用于对象的打包发送, + * 按照一定顺序将对象的各个属性值写入到传入的Parcel对象中,包括将BookInfoBean对象也写入Parcel中,方便后续进行传递和还原操作。 + * @param dest 要写入数据的Parcel对象。 + * @param flags 一些额外的标志位,一般使用默认值即可,可用于控制特殊的序列化行为等情况(但此处暂未体现特殊使用场景)。 + */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(noteUrl); @@ -67,11 +123,18 @@ public class BookShelfBean implements Parcelable,Cloneable{ dest.writeParcelable(bookInfoBean, flags); } + /** + * 返回当前对象的描述信息,一般如果对象内部有文件描述符等特殊情况需要返回相应的描述标记,此处返回0表示没有特殊内容需要描述,这是实现Parcelable接口要求的方法。 + * @return 一般返回0,表示没有特殊描述内容。 + */ @Override public int describeContents() { return 0; } + /** + * 用于创建BookShelfBean对象的静态内部类Creator,实现了Parcelable.Creator接口,提供了从Parcel对象创建BookShelfBean对象实例以及创建对象数组的方法,这是实现Parcelable接口要求的配套部分。 + */ @Transient public static final Creator CREATOR = new Creator() { @Override @@ -85,54 +148,110 @@ public class BookShelfBean implements Parcelable,Cloneable{ } }; + /** + * 获取书本的唯一标识(对应BookInfoBean中的noteUrl,网站根地址或本地MD5值)。 + * @return 书本的唯一标识字符串(noteUrl)。 + */ public String getNoteUrl() { return noteUrl; } + /** + * 设置书本的唯一标识(对应BookInfoBean中的noteUrl,网站根地址或本地MD5值)。 + * @param noteUrl 要设置的书本唯一标识字符串。 + */ public void setNoteUrl(String noteUrl) { this.noteUrl = noteUrl; } + /** + * 获取当前章节索引。 + * @return 当前章节的索引值(整数)。 + */ public int getDurChapter() { return durChapter; } + /** + * 设置当前章节索引。 + * @param durChapter 要设置的当前章节索引值(整数)。 + */ public void setDurChapter(int durChapter) { this.durChapter = durChapter; } + /** + * 获取当前章节页码位置。 + * @return 当前章节的页码位置值(整数)。 + */ public int getDurChapterPage() { return durChapterPage; } + /** + * 设置当前章节页码位置。 + * @param durChapterPage 要设置的当前章节的页码位置值(整数)。 + */ public void setDurChapterPage(int durChapterPage) { this.durChapterPage = durChapterPage; } + /** + * 获取最后阅读时间的时间戳。 + * @return 最后阅读时间的长整型时间戳,单位为毫秒。 + */ public long getFinalDate() { return finalDate; } + /** + * 设置最后阅读时间的时间戳。 + * @param finalDate 要设置的最后阅读时间的长整型时间戳,单位为毫秒。 + */ public void setFinalDate(long finalDate) { this.finalDate = finalDate; } + /** + * 获取书本的标识标签。 + * @return 书本的标识标签字符串。 + */ public String getTag() { return tag; } + /** + * 设置书本的标识标签。 + * @param tag 要设置的书本标识标签字符串。 + */ public void setTag(String tag) { this.tag = tag; } + /** + * 获取书本更详细的信息对象(BookInfoBean类型),包含了如小说名、作者、简介、章节列表等丰富的书本基础信息。 + * @return BookInfoBean对象,代表书本详细信息。 + */ public BookInfoBean getBookInfoBean() { return bookInfoBean; } + /** + * 设置书本更详细的信息对象(BookInfoBean类型),用于更新或替换原有的书本详细信息内容。 + * @param bookInfoBean 要设置的BookInfoBean对象,包含新的书本详细信息。 + */ public void setBookInfoBean(BookInfoBean bookInfoBean) { this.bookInfoBean = bookInfoBean; } + /** + * 重写了Object类的clone方法,用于创建当前BookShelfBean对象的副本,在克隆过程中, + * 先调用父类的clone方法创建一个基础的对象副本,然后将原对象的各个属性值复制到副本对象中, + * 对于包含的BookInfoBean对象,需要调用它自身的clone方法来进行克隆并设置到副本对象中, + * 最终返回克隆后的完整BookShelfBean对象副本,可用于在不影响原对象的情况下进行独立操作等场景。 + * @return 克隆后的BookShelfBean对象副本。 + * @throws CloneNotSupportedException 如果对象所在类没有实现Cloneable接口或者在克隆过程中出现不支持克隆的情况时抛出此异常。 + */ @Override public Object clone() throws CloneNotSupportedException { BookShelfBean bookShelfBean = (BookShelfBean) super.clone(); diff --git a/app/src/main/java/com/monke/monkeybook/bean/ChapterListBean.java b/app/src/main/java/com/monke/monkeybook/bean/ChapterListBean.java index e34ae8a..42a0a92 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/ChapterListBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/ChapterListBean.java @@ -10,24 +10,57 @@ import org.greenrobot.greendao.annotation.Generated; /** * 章节列表 + * 此类用于表示书本的章节相关信息,实现了Parcelable接口以便在不同组件间方便地传递章节信息对象(例如在加载书本章节、切换章节等操作时传递章节数据), + * 同时实现了Cloneable接口用于创建对象的副本,方便在需要复制章节信息进行独立操作(比如对章节信息进行临时修改、备份等)的场景下使用。 */ @Entity -public class ChapterListBean implements Parcelable,Cloneable{ +public class ChapterListBean implements Parcelable, Cloneable { + /** + * 对应BookInfoBean中的noteUrl,通常如果是来源网站,此处存储小说的根地址;如果是本地书本,则存储小说本地的MD5值, + * 以此来关联章节所属的具体书本,建立章节与书本整体信息之间的联系。 + */ private String noteUrl; //对应BookInfoBean noteUrl; + /** + * 当前章节数,用于标识章节在整本书中的顺序位置,方便按顺序展示章节列表、定位特定章节以及实现章节导航等功能。 + */ private int durChapterIndex; //当前章节数 + + /** + * @Id注解表示这个字段在相关数据库操作(如果使用了对应支持此注解的数据库框架,例如 GreenDao)中可作为主键来唯一标识一条章节记录。 + * 当前章节对应的文章地址,例如网络小说中可能是该章节内容的具体网络链接,本地小说可能是本地存储该章节文本文件的路径等,通过这个地址可以获取章节的具体内容。 + */ @Id private String durChapterUrl; //当前章节对应的文章地址 + /** + * 当前章节名称,用于展示给用户,方便用户直观地了解每个章节的主题,比如“第一章:初入江湖”之类的名称,便于用户选择想要阅读的章节。 + */ private String durChapterName; //当前章节名称 + /** + * 用于给章节添加额外的标识标签,具体含义可根据业务需求确定,比如可以用来区分不同类型的章节(正文章节、番外章节等)、不同来源的章节内容或者其他自定义的章节分类标识等情况。 + */ private String tag; + /** + * 用于标识该章节是否已经有缓存,初始值为false,表示默认情况下章节内容尚未缓存,当章节内容被成功缓存后可将其设置为true,方便在程序中判断是否需要重新获取章节内容等操作。 + */ private Boolean hasCache = false; + + /** + * @Transient注解表示这个字段不会被持久化(比如在使用相关数据库框架存储对象时,该字段不会存入数据库)。 + * 用于存储章节对应的具体内容信息,是BookContentBean类型的对象,包含了如章节文本内容、每行内容列表等详细的章节缓存相关数据,方便获取和操作章节实际展示的内容。 + */ @Transient private BookContentBean bookContentBean = new BookContentBean(); + /** + * 用于从一个Parcel对象中恢复ChapterListBean对象的构造函数,这是实现Parcelable接口要求的方法,用于对象的解包还原, + * 从传入的Parcel中按照顺序读取之前写入的各个属性值,来初始化当前对象的各个成员变量,包括从Parcel中读取并还原BookContentBean对象。 + * @param in 包含对象序列化数据的Parcel对象。 + */ protected ChapterListBean(Parcel in) { noteUrl = in.readString(); durChapterIndex = in.readInt(); @@ -35,12 +68,22 @@ public class ChapterListBean implements Parcelable,Cloneable{ durChapterName = in.readString(); tag = in.readString(); bookContentBean = in.readParcelable(BookContentBean.class.getClassLoader()); - hasCache = in.readByte() != 0; + hasCache = in.readByte()!= 0; } + /** + * 带有参数的构造函数,用于在已知相关属性值的情况下创建ChapterListBean对象实例,方便在代码中初始化对象并赋值相关重要属性, + * 根据传入的各个参数值来分别设置对象的成员变量,构建一个完整的章节信息对象。 + * @param noteUrl 章节所属书本的唯一标识(对应BookInfoBean中的noteUrl,网站根地址或本地MD5值)。 + * @param durChapterIndex 当前章节数。 + * @param durChapterUrl 当前章节对应的文章地址。 + * @param durChapterName 当前章节名称。 + * @param tag 章节的标识标签。 + * @param hasCache 章节是否有缓存的标识。 + */ @Generated(hash = 1225922702) public ChapterListBean(String noteUrl, int durChapterIndex, String durChapterUrl, - String durChapterName, String tag, Boolean hasCache) { + String durChapterName, String tag, Boolean hasCache) { this.noteUrl = noteUrl; this.durChapterIndex = durChapterIndex; this.durChapterUrl = durChapterUrl; @@ -49,10 +92,19 @@ public class ChapterListBean implements Parcelable,Cloneable{ this.hasCache = hasCache; } + /** + * 默认构造函数,用于创建ChapterListBean对象实例时进行默认的初始化操作,通常在没有初始值传入时使用,创建一个默认状态的章节信息对象。 + */ @Generated(hash = 1096893365) public ChapterListBean() { } + /** + * 将ChapterListBean对象的属性数据写入到Parcel对象中,以便进行对象的序列化操作,这是实现Parcelable接口要求的方法,用于对象的打包发送, + * 按照一定顺序将对象的各个属性值写入到传入的Parcel对象中,包括将BookContentBean对象也写入Parcel中,方便后续进行传递和还原操作。 + * @param dest 要写入数据的Parcel对象。 + * @param flags 一些额外的标志位,一般使用默认值即可,可用于控制特殊的序列化行为等情况(但此处暂未体现特殊使用场景)。 + */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(noteUrl); @@ -61,70 +113,133 @@ public class ChapterListBean implements Parcelable,Cloneable{ dest.writeString(durChapterName); dest.writeString(tag); dest.writeParcelable(bookContentBean, flags); - dest.writeByte((byte)(hasCache?1:0)); + dest.writeByte((byte) (hasCache? 1 : 0)); } + /** + * 返回当前对象的描述信息,一般如果对象内部有文件描述符等特殊情况需要返回相应的描述标记,此处返回0表示没有特殊内容需要描述,这是实现Parcelable接口要求的方法。 + * @return 一般返回0,表示没有特殊描述内容。 + */ @Override public int describeContents() { return 0; } + /** + * 获取章节对应的具体内容信息对象(BookContentBean类型),包含了如章节文本内容、每行内容列表等详细的章节缓存相关数据。 + * @return BookContentBean对象,代表章节具体内容。 + */ public BookContentBean getBookContentBean() { return bookContentBean; } + /** + * 设置章节对应的具体内容信息对象(BookContentBean类型),用于更新或替换原有的章节内容相关信息。 + * @param bookContentBean 要设置的BookContentBean对象,包含新的章节内容信息。 + */ public void setBookContentBean(BookContentBean bookContentBean) { this.bookContentBean = bookContentBean; } + /** + * 获取章节是否已经有缓存的标识。 + * @return true表示章节已有缓存,false表示没有缓存。 + */ public Boolean getHasCache() { return this.hasCache; } + /** + * 设置章节是否已经有缓存的标识。 + * @param hasCache 要设置的表示章节是否有缓存的布尔值。 + */ public void setHasCache(Boolean hasCache) { this.hasCache = hasCache; } + /** + * 获取章节的标识标签。 + * @return 章节的标识标签字符串。 + */ public String getTag() { return this.tag; } + /** + * 设置章节的标识标签。 + * @param tag 要设置的章节的标识标签字符串。 + */ public void setTag(String tag) { this.tag = tag; } + /** + * 获取当前章节名称。 + * @return 当前章节名称字符串。 + */ public String getDurChapterName() { return this.durChapterName; } + /** + * 设置当前章节名称。 + * @param durChapterName 要设置的当前章节名称字符串。 + */ public void setDurChapterName(String durChapterName) { this.durChapterName = durChapterName; } + /** + * 获取当前章节对应的文章地址。 + * @return 当前章节对应的文章地址字符串。 + */ public String getDurChapterUrl() { return this.durChapterUrl; } + /** + * 设置当前章节对应的文章地址。 + * @param durChapterUrl 要设置的当前章节对应的文章地址字符串。 + */ public void setDurChapterUrl(String durChapterUrl) { this.durChapterUrl = durChapterUrl; } + /** + * 获取当前章节数。 + * @return 当前章节数的整数值。 + */ public int getDurChapterIndex() { return this.durChapterIndex; } + /** + * 设置当前章节数。 + * @param durChapterIndex 要设置的当前章节数的整数值。 + */ public void setDurChapterIndex(int durChapterIndex) { this.durChapterIndex = durChapterIndex; } + /** + * 获取章节所属书本的唯一标识(对应BookInfoBean中的noteUrl,网站根地址或本地MD5值)。 + * @return 章节所属书本的唯一标识字符串。 + */ public String getNoteUrl() { return this.noteUrl; } + /** + * 设置章节所属书本的唯一标识(对应BookInfoBean中的noteUrl,网站根地址或本地MD5值)。 + * @param noteUrl 要设置的章节所属书本的唯一标识字符串。 + */ public void setNoteUrl(String noteUrl) { this.noteUrl = noteUrl; } + /** + * 用于创建ChapterListBean对象的静态内部类Creator,实现了Parcelable.Creator接口,提供了从Parcel对象创建ChapterListBean对象实例以及创建对象数组的方法,这是实现Parcelable接口要求的配套部分。 + */ @Transient public static final Creator CREATOR = new Creator() { @Override @@ -138,6 +253,14 @@ public class ChapterListBean implements Parcelable,Cloneable{ } }; + /** + * 重写了Object类的clone方法,用于创建当前ChapterListBean对象的副本,在克隆过程中, + * 先调用父类的clone方法创建一个基础的对象副本,然后将原对象的各个属性值复制到副本对象中, + * 对于包含的BookContentBean对象,重新创建一个新的BookContentBean对象(此处没有进行深度克隆,只是创建了一个新的空对象,可根据实际需求调整是否进行深度克隆), + * 最终返回克隆后的完整ChapterListBean对象副本,可用于在不影响原对象的情况下进行独立操作等场景。 + * @return 克隆后的ChapterListBean对象副本。 + * @throws CloneNotSupportedException 如果对象所在类没有实现Cloneable接口或者在克隆过程中出现不支持克隆的情况时抛出此异常。 + */ @Override protected Object clone() throws CloneNotSupportedException { ChapterListBean chapterListBean = (ChapterListBean) super.clone(); @@ -149,4 +272,4 @@ public class ChapterListBean implements Parcelable,Cloneable{ chapterListBean.bookContentBean = new BookContentBean(); return chapterListBean; } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/bean/DownloadChapterBean.java b/app/src/main/java/com/monke/monkeybook/bean/DownloadChapterBean.java index 6f7f51e..7471bc0 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/DownloadChapterBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/DownloadChapterBean.java @@ -8,22 +8,60 @@ import org.greenrobot.greendao.annotation.Id; import org.greenrobot.greendao.annotation.Transient; import org.greenrobot.greendao.annotation.Generated; +/** + * DownloadChapterBean类用于表示下载章节相关的信息,实现了Parcelable接口,以便可以方便地在不同组件之间传递该对象, + * 例如在下载管理模块与其他相关业务模块之间传递章节下载相关的数据等情况。同时,该类使用了@Entity注解,可能用于配合相关数据库框架进行数据持久化操作(具体取决于所使用的数据库框架配置)。 + */ @Entity public class DownloadChapterBean implements Parcelable { + + /** + * 对应BookInfoBean中的noteUrl,通常如果是来源网站,此处存储小说的根地址;如果是本地书本,则存储小说本地的MD5值, + * 以此来关联下载章节所属的具体书本,建立章节与书本整体信息之间的联系,方便后续的业务逻辑处理(比如判断章节所属书本等操作)。 + */ private String noteUrl; + /** + * 当前章节数,用于标识章节在整本书中的顺序位置,方便按顺序展示章节列表、定位特定章节以及实现章节导航等功能, + * 在下载章节的场景下,可以明确该章节在书本中的具体序号位置。 + */ private int durChapterIndex; //当前章节数 + + /** + * @Id注解表示这个字段在相关数据库操作(如果使用了对应支持此注解的数据库框架,例如 GreenDao)中可作为主键来唯一标识一条下载章节记录。 + * 当前章节对应的文章地址,例如网络小说中可能是该章节内容的具体网络链接,本地小说可能是本地存储该章节文本文件的路径等, + * 通过这个地址可以获取章节的具体内容,在下载章节时会依据此地址去获取相应的章节文本进行下载保存操作。 + */ @Id private String durChapterUrl; //当前章节对应的文章地址 + /** + * 当前章节名称,用于展示给用户,方便用户直观地了解每个章节的主题,比如“第一章:初入江湖”之类的名称,便于用户知晓下载的具体是哪个章节的内容。 + */ private String durChapterName; //当前章节名称 + /** + * 用于给下载章节添加额外的标识标签,具体含义可根据业务需求确定,比如可以用来区分不同类型的章节(正文章节、番外章节等)、不同来源的章节内容或者其他自定义的章节分类标识等情况, + * 在下载章节相关业务逻辑中,可依据此标签进行针对性的处理。 + */ private String tag; + /** + * 存储小说名称,方便在展示下载章节相关信息时,能让用户清楚地知道该章节所属的小说名称,增强信息的完整性和可读性。 + */ private String bookName; + /** + * 存储小说封面的地址,对于网络小说可能是封面图片的网络链接,本地小说则可能是本地封面图片文件的路径, + * 在展示下载章节相关信息时,可用于显示对应的小说封面,提升用户界面的友好性。 + */ private String coverUrl; //小说封面 + /** + * 用于从一个Parcel对象中恢复DownloadChapterBean对象的构造函数,这是实现Parcelable接口要求的方法,用于对象的解包还原, + * 从传入的Parcel中按照顺序读取之前写入的各个属性值,来初始化当前对象的各个成员变量。 + * @param in 包含对象序列化数据的Parcel对象。 + */ protected DownloadChapterBean(Parcel in) { noteUrl = in.readString(); durChapterIndex = in.readInt(); @@ -34,9 +72,20 @@ public class DownloadChapterBean implements Parcelable { coverUrl = in.readString(); } + /** + * 带有参数的构造函数,用于在已知相关属性值的情况下创建DownloadChapterBean对象实例,方便在代码中初始化对象并赋值相关重要属性, + * 根据传入的各个参数值来分别设置对象的成员变量,构建一个完整的下载章节信息对象。 + * @param noteUrl 章节所属书本的唯一标识(对应BookInfoBean中的noteUrl,网站根地址或本地MD5值)。 + * @param durChapterIndex 当前章节数。 + * @param durChapterUrl 当前章节对应的文章地址。 + * @param durChapterName 当前章节名称。 + * @param tag 章节的标识标签。 + * @param bookName 小说名称。 + * @param coverUrl 小说封面地址。 + */ @Generated(hash = 757008458) public DownloadChapterBean(String noteUrl, int durChapterIndex, String durChapterUrl, - String durChapterName, String tag, String bookName, String coverUrl) { + String durChapterName, String tag, String bookName, String coverUrl) { this.noteUrl = noteUrl; this.durChapterIndex = durChapterIndex; this.durChapterUrl = durChapterUrl; @@ -46,10 +95,16 @@ public class DownloadChapterBean implements Parcelable { this.coverUrl = coverUrl; } + /** + * 默认构造函数,用于创建DownloadChapterBean对象实例时进行默认的初始化操作,通常在没有初始值传入时使用,创建一个默认状态的下载章节信息对象。 + */ @Generated(hash = 301211198) public DownloadChapterBean() { } + /** + * 用于创建DownloadChapterBean对象的静态内部类Creator,实现了Parcelable.Creator接口,提供了从Parcel对象创建DownloadChapterBean对象实例以及创建对象数组的方法,这是实现Parcelable接口要求的配套部分。 + */ @Transient public static final Creator CREATOR = new Creator() { @Override @@ -63,11 +118,21 @@ public class DownloadChapterBean implements Parcelable { } }; + /** + * 返回当前对象的描述信息,一般如果对象内部有文件描述符等特殊情况需要返回相应的描述标记,此处返回0表示没有特殊内容需要描述,这是实现Parcelable接口要求的方法。 + * @return 一般返回0,表示没有特殊描述内容。 + */ @Override public int describeContents() { return 0; } + /** + * 将DownloadChapterBean对象的属性数据写入到Parcel对象中,以便进行对象的序列化操作,这是实现Parcelable接口要求的方法,用于对象的打包发送, + * 按照一定顺序将对象的各个属性值写入到传入的Parcel对象中,方便后续进行传递和还原操作。 + * @param dest 要写入数据的Parcel对象。 + * @param flags 一些额外的标志位,一般使用默认值即可,可用于控制特殊的序列化行为等情况(但此处暂未体现特殊使用场景)。 + */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(noteUrl); @@ -79,59 +144,115 @@ public class DownloadChapterBean implements Parcelable { dest.writeString(coverUrl); } + /** + * 获取章节所属书本的唯一标识(对应BookInfoBean中的noteUrl,网站根地址或本地MD5值)。 + * @return 章节所属书本的唯一标识字符串。 + */ public String getNoteUrl() { return noteUrl; } + /** + * 设置章节所属书本的唯一标识(对应BookInfoBean中的noteUrl,网站根地址或本地MD5值)。 + * @param noteUrl 要设置的章节所属书本的唯一标识字符串。 + */ public void setNoteUrl(String noteUrl) { this.noteUrl = noteUrl; } + /** + * 获取当前章节数。 + * @return 当前章节数的整数值。 + */ public int getDurChapterIndex() { return durChapterIndex; } + /** + * 设置当前章节数。 + * @param durChapterIndex 要设置的当前章节数的整数值。 + */ public void setDurChapterIndex(int durChapterIndex) { this.durChapterIndex = durChapterIndex; } + /** + * 获取当前章节对应的文章地址。 + * @return 当前章节对应的文章地址字符串。 + */ public String getDurChapterUrl() { return durChapterUrl; } + /** + * 设置当前章节对应的文章地址。 + * @param durChapterUrl 要设置的当前章节对应的文章地址字符串。 + */ public void setDurChapterUrl(String durChapterUrl) { this.durChapterUrl = durChapterUrl; } + /** + * 获取当前章节名称。 + * @return 当前章节名称字符串。 + */ public String getDurChapterName() { return durChapterName; } + /** + * 设置当前章节名称。 + * @param durChapterName 要设置的当前章节名称字符串。 + */ public void setDurChapterName(String durChapterName) { this.durChapterName = durChapterName; } + /** + * 获取章节的标识标签。 + * @return 章节的标识标签字符串。 + */ public String getTag() { return tag; } + /** + * 设置章节的标识标签。 + * @param tag 要设置的章节的标识标签字符串。 + */ public void setTag(String tag) { this.tag = tag; } + /** + * 获取小说名称。 + * @return 小说名称字符串。 + */ public String getBookName() { return bookName; } + /** + * 设置小说名称。 + * @param bookName 要设置的小说名称字符串。 + */ public void setBookName(String bookName) { this.bookName = bookName; } + /** + * 获取小说封面的地址。 + * @return 小说封面地址字符串。 + */ public String getCoverUrl() { return coverUrl; } + /** + * 设置小说封面的地址。 + * @param coverUrl 要设置的小说封面地址字符串。 + */ public void setCoverUrl(String coverUrl) { this.coverUrl = coverUrl; } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/bean/DownloadChapterListBean.java b/app/src/main/java/com/monke/monkeybook/bean/DownloadChapterListBean.java index 8bc10ca..cc0a00d 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/DownloadChapterListBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/DownloadChapterListBean.java @@ -8,20 +8,42 @@ import java.util.List; /** * 下载章节列表 + * 此类用于封装下载章节的列表信息,实现了Parcelable接口,方便在不同组件之间传递整个下载章节列表对象, + * 例如在下载管理模块与展示模块之间传递已下载章节的集合数据,使得数据传递更加便捷且能保持数据结构的完整性。 */ public class DownloadChapterListBean implements Parcelable { + + /** + * 用于存储下载章节的列表数据,每个元素都是DownloadChapterBean类型,代表一个具体的下载章节信息, + * 通过这个列表可以方便地对多个下载章节进行统一管理、操作以及展示等。 + */ private List data; + /** + * 构造函数,用于创建DownloadChapterListBean对象实例时传入下载章节列表数据进行初始化, + * 将外部传入的包含DownloadChapterBean元素的列表赋值给内部的data成员变量,从而构建一个完整的下载章节列表对象。 + * @param result 包含DownloadChapterBean元素的列表,代表下载章节的具体信息集合。 + */ public DownloadChapterListBean(List result) { this.data = result; } + /** + * 用于从一个Parcel对象中恢复DownloadChapterListBean对象的构造函数,这是实现Parcelable接口要求的方法,用于对象的解包还原, + * 首先判断内部的data列表是否为null,如果是则创建一个新的空的ArrayList,然后从传入的Parcel中读取之前写入的DownloadChapterBean对象列表数据, + * 通过DownloadChapterBean的CREATOR来创建相应的对象并填充到data列表中,完成对象的初始化。 + * @param in 包含对象序列化数据的Parcel对象。 + */ protected DownloadChapterListBean(Parcel in) { - if(data == null) + if (data == null) data = new ArrayList<>(); - in.readTypedList(data,DownloadChapterBean.CREATOR); + in.readTypedList(data, DownloadChapterBean.CREATOR); } + /** + * 用于创建DownloadChapterListBean对象的静态内部类Creator,实现了Parcelable.Creator接口,提供了从Parcel对象创建DownloadChapterListBean对象实例以及创建对象数组的方法, + * 这是实现Parcelable接口要求的配套部分,使得可以方便地从序列化数据中还原出对象以及创建对象数组。 + */ public static final Creator CREATOR = new Creator() { @Override public DownloadChapterListBean createFromParcel(Parcel in) { @@ -34,21 +56,39 @@ public class DownloadChapterListBean implements Parcelable { } }; + /** + * 获取存储下载章节信息的列表数据。 + * @return 包含DownloadChapterBean元素的列表,代表下载章节的具体信息集合。 + */ public List getData() { return data; } + /** + * 设置存储下载章节信息的列表数据,用于更新或替换原有的下载章节列表内容。 + * @param data 包含DownloadChapterBean元素的新列表,代表新的下载章节的具体信息集合。 + */ public void setData(List data) { this.data = data; } + /** + * 返回当前对象的描述信息,一般如果对象内部有文件描述符等特殊情况需要返回相应的描述标记,此处返回0表示没有特殊内容需要描述,这是实现Parcelable接口要求的方法。 + * @return 一般返回0,表示没有特殊描述内容。 + */ @Override public int describeContents() { return 0; } + /** + * 将DownloadChapterListBean对象的属性数据(即内部的下载章节列表数据)写入到Parcel对象中,以便进行对象的序列化操作,这是实现Parcelable接口要求的方法,用于对象的打包发送, + * 通过writeTypedList方法将data列表中的DownloadChapterBean对象依次写入到传入的Parcel对象中,方便后续进行传递和还原操作。 + * @param dest 要写入数据的Parcel对象。 + * @param flags 一些额外的标志位,一般使用默认值即可,可用于控制特殊的序列化行为等情况。 + */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeTypedList(data); } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/bean/LibraryBean.java b/app/src/main/java/com/monke/monkeybook/bean/LibraryBean.java index 97ae24d..6e486db 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/LibraryBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/LibraryBean.java @@ -5,24 +5,51 @@ import java.util.List; /** * 书城整体Data bean + * 此类用于封装书城相关的数据信息,作为一个整体的数据容器,方便在程序中传递和处理与书城功能相关的各类数据, + * 例如在从网络获取书城数据后,可将相关数据整理到这个类的对象中,再传递给其他模块进行展示、分析等操作。 */ public class LibraryBean { + + /** + * 用于存储新书相关的信息列表,每个元素是LibraryNewBookBean类型,代表一本新书的具体信息, + * 可以包含新书的书名、作者、简介、封面等相关属性,方便展示书城中的新书推荐等板块内容。 + */ private List libraryNewBooks; + + /** + * 用于存储按照分类划分后的书籍信息列表,每个元素是LibraryKindBookListBean类型, + * 其中可能包含了某一分类下的多本书籍信息,例如玄幻类书籍列表、言情类书籍列表等,便于在书城界面展示不同分类的书籍推荐情况。 + */ private List kindBooks; + /** + * 获取新书相关信息的列表,方便外部模块获取书城的新书数据进行展示或者其他处理操作。 + * @return 包含LibraryNewBookBean元素的列表,代表新书的具体信息集合。 + */ public List getLibraryNewBooks() { return libraryNewBooks; } + /** + * 设置新书相关信息的列表,用于更新或替换原有的新书列表数据,例如从网络重新获取新书数据后进行替换操作。 + * @param libraryNewBooks 包含LibraryNewBookBean元素的新列表,代表新的新书的具体信息集合。 + */ public void setLibraryNewBooks(List libraryNewBooks) { this.libraryNewBooks = libraryNewBooks; } + /** + * 获取按照分类划分后的书籍信息列表,方便外部模块获取书城不同分类的书籍数据进行展示或者其他处理操作。 + * @return 包含LibraryKindBookListBean元素的列表,代表分类书籍的具体信息集合。 + */ public List getKindBooks() { return kindBooks; } + /** + * 设置按照分类划分后的书籍信息列表,用于更新或替换原有的分类书籍列表数据,例如从网络重新获取分类书籍数据后进行替换操作。 + */ public void setKindBooks(List kindBooks) { this.kindBooks = kindBooks; } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/bean/LibraryKindBookListBean.java b/app/src/main/java/com/monke/monkeybook/bean/LibraryKindBookListBean.java index 867e85a..baff070 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/LibraryKindBookListBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/LibraryKindBookListBean.java @@ -5,33 +5,73 @@ import java.util.List; /** * 书城 书籍分类推荐列表 + * 此类用于表示书城中书的分类推荐相关信息,主要包含了分类名称、分类对应的链接(可能用于获取该分类下更多书籍等操作)以及属于该分类的书籍列表信息, + * 在书城展示不同分类书籍推荐内容时会用到此类来组织和传递相关数据。 */ public class LibraryKindBookListBean { + + /** + * 存储书籍分类的名称,例如“玄幻小说”“言情小说”“历史传记”等,用于在书城界面明确标识每个分类,方便用户直观知晓该分类下书籍的大致类型。 + */ private String kindName; + + /** + * 存储该书籍分类对应的链接地址,其具体含义可能因业务场景而异,比如对于网络书城,可能是指向获取该分类下更多书籍信息的网络接口地址; + * 对于本地书城,也可能是关联本地存储该分类书籍相关数据的文件路径等,可用于进一步获取更多此分类下的书籍详情。 + */ private String kindUrl; + + /** + * 存储属于该分类的书籍信息列表,每个元素是SearchBookBean类型,代表一本具体的书籍相关数据(包含书名、作者、简介等信息), + * 通过这个列表可以完整展示该分类下具体有哪些书籍推荐给用户。 + */ private List books; + /** + * 获取书籍分类的名称,方便外部代码获取该分类的标识名称进行展示或者其他相关逻辑处理。 + * @return 分类名称的字符串。 + */ public String getKindName() { return kindName; } + /** + * 设置书籍分类的名称,用于更新或替换原有的分类名称,例如根据服务器返回的最新分类名称进行修改等情况。 + * @param kindName 要设置的分类名称的字符串。 + */ public void setKindName(String kindName) { this.kindName = kindName; } - public List getBooks() { + /** + * 获取属于该分类的书籍信息列表,方便外部代码获取该分类下具体的书籍数据进行展示、排序或者其他相关逻辑处理。 + * @return 包含SearchBookBean元素的列表,代表该分类下的书籍具体信息集合。 + */ + public String getBooks() { return books; } + /** + * 设置属于该分类的书籍信息列表,用于更新或替换原有的该分类下书籍列表数据,例如从网络重新获取该分类的最新书籍推荐后进行替换操作。 + * @param books 包含SearchBookBean元素的新列表,代表新的该分类下的书籍具体信息集合。 + */ public void setBooks(List books) { this.books = books; } + /** + * 获取书籍分类对应的链接地址,方便外部代码根据此链接去获取更多该分类相关的数据或者进行其他关联操作。 + * @return 分类对应的链接地址字符串。 + */ public String getKindUrl() { return kindUrl; } + /** + * 设置书籍分类对应的链接地址,用于更新或替换原有的分类链接,例如服务器端分类链接发生变化后进行相应修改等情况。 + * @param kindUrl 要设置的分类对应的链接地址字符串。 + */ public void setKindUrl(String kindUrl) { this.kindUrl = kindUrl; } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/bean/LibraryNewBookBean.java b/app/src/main/java/com/monke/monkeybook/bean/LibraryNewBookBean.java index b35da20..fca6438 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/LibraryNewBookBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/LibraryNewBookBean.java @@ -1,12 +1,45 @@ //Copyright (c) 2017. 章钦豪. All rights reserved. package com.monke.monkeybook.bean; +/** + * LibraryNewBookBean类主要用于封装书城中新书的基础信息,方便在整个应用程序中传递和处理与新书相关的数据, + * 例如在从服务器获取新书推荐列表后,将每本新书的数据整理到此类的对象中,再传递给展示层进行界面呈现等操作。 + */ public class LibraryNewBookBean { + + /** + * 用于存储新书的书名,这是识别一本书最直观的属性,会展示给用户,方便用户快速知晓该书的基本情况, + * 在书城的新书推荐列表、详情页面等地方都会用到这个属性来呈现书籍信息。 + */ private String name; + + /** + * 存放新书对应的链接地址,其具体含义取决于书城的具体实现形式。 + * 在网络书城场景下,可能是指向该书详细介绍页面的网络链接,或者是用于获取该书更多详细内容(比如章节列表、全文内容等)的接口地址; + * 若是本地书城,则可能是指向本地存储该书相关数据文件的路径,通过这个地址可以进一步获取关于这本书更全面的信息。 + */ private String url; + + /** + * 用来保存新书的标签信息,该标签可根据业务需求进行自定义设置,常见的用途比如用于对新书进行分类、标记特殊属性等。 + * 例如可以按照书籍的风格(如玄幻、言情、科幻等)、推荐来源(如热门推荐、编辑推荐等)来设置标签,方便后续对新书进行筛选、分组展示以及个性化推荐等操作。 + */ private String tag; + + /** + * 记录新书的来源信息,明确该书是从哪里获取的,比如是来自某个特定的网络文学平台、出版社,或者是用户自行上传的本地书籍等, + * 这个属性有助于对书籍进行版权管理、数据溯源以及针对不同来源进行差异化处理(如不同来源的书籍更新方式、展示样式等可能有所不同)。 + */ private String orgin; + /** + * 构造函数,用于创建LibraryNewBookBean类的对象实例,通过传入新书的各项具体属性值(书名、链接、标签、来源), + * 来初始化对象内部对应的成员变量,从而构建一个完整的、包含新书详细信息的对象,方便后续在程序中使用。 + * @param name 新书的书名,必须传入有效的字符串值来表示新书的名称。 + * @param url 新书对应的链接地址,依据书城类型传入相应有效的链接形式(网络链接或本地路径等)。 + * @param tag 新书的标签信息,传入符合业务设定的用于分类或标记该书的字符串标签。 + * @param orgin 新书的来源信息,传入表示书籍出处的有效字符串描述。 + */ public LibraryNewBookBean(String name, String url, String tag, String orgin) { this.name = name; this.url = url; @@ -14,35 +47,75 @@ public class LibraryNewBookBean { this.orgin = orgin; } + /** + * 获取新书的来源信息,外部代码可以调用此方法来获取该新书是从何处而来的具体描述, + * 以便在需要了解书籍出处的业务逻辑中进行相应处理,比如根据来源显示不同的提示信息等。 + * @return 表示新书来源的字符串信息,例如具体的网络平台名称、出版社名称等。 + */ public String getOrgin() { return orgin; } + /** + * 设置新书的来源信息,用于在需要更新书籍来源的情况下(比如发现之前记录的来源有误,或者书籍来源发生了变更等), + * 对该对象内部存储的来源信息进行修改,确保数据的准确性和及时性。 + * @param orgin 要设置的新书来源信息的字符串,应传入符合业务规则的有效来源描述。 + */ public void setOrgin(String orgin) { this.orgin = orgin; } + /** + * 获取新书的标签信息,供外部代码获取该书所标记的分类、特性等相关标签内容, + * 以便在进行书籍筛选、分组展示等操作时使用,例如按照标签将新书归类到不同的推荐板块中。 + * @return 表示新书标签的字符串信息,如“玄幻”“热门推荐”等符合业务定义的标签内容。 + */ public String getTag() { return tag; } + /** + * 设置新书的标签信息,当需要重新对新书进行分类、标记,或者根据业务规则更新标签时, + * 可通过此方法传入新的标签字符串来修改对象内部存储的标签内容,实现对新书标签的动态管理。 + * @param tag 要设置的新书标签信息的字符串,需符合业务设定的标签格式和含义要求。 + */ public void setTag(String tag) { this.tag = tag; } + /** + * 获取新书的书名,方便外部代码在需要展示书籍名称的地方(如新书列表、详情页面标题等)获取并使用该信息, + * 是呈现书籍基本情况给用户的重要属性获取方法。 + * @return 表示新书书名的字符串,如《某某小说》等符合书籍命名规范的字符串内容。 + */ public String getName() { return name; } + /** + * 设置新书的书名,虽然在实际应用中书籍名称通常相对固定,但在某些特殊情况下(如书名发生变更等), + * 可以通过此方法传入新的书名字符串来更新对象内部存储的书名信息,确保数据与实际情况相符。 + * @param name 要设置的新书书名的字符串,应传入符合书籍命名规范的有效名称内容。 + */ public void setName(String name) { this.name = name; } + /** + * 获取新书对应的链接地址,外部代码可以利用这个链接去获取关于该书更详细的内容, + * 比如在用户点击新书推荐列表中的某本书时,通过获取的链接跳转到对应的详情页面或者获取章节内容等操作。 + * @return 表示新书链接地址的字符串,格式根据书城类型为网络链接或本地路径等形式。 + */ public String getUrl() { return url; } + /** + * 设置新书对应的链接地址,用于在链接发生变化时(如服务器端更新了接口地址、本地文件存储路径改变等情况), + * 对对象内部存储的链接信息进行更新,保证后续基于此链接的相关操作能够正常进行。 + * @param url 要设置的新书对应的链接地址的字符串,需传入符合书城对应链接格式要求的有效地址内容。 + */ public void setUrl(String url) { this.url = url; } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/bean/LocBookShelfBean.java b/app/src/main/java/com/monke/monkeybook/bean/LocBookShelfBean.java index 5583965..317993b 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/LocBookShelfBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/LocBookShelfBean.java @@ -1,28 +1,68 @@ //Copyright (c) 2017. 章钦豪. All rights reserved. package com.monke.monkeybook.bean; +/** + * LocBookShelfBean类主要用于对本地书架相关信息进行封装,将是否为新书的标识以及具体的书架书本信息(BookShelfBean类型)组合在一起, + * 方便在涉及本地书架操作的业务逻辑中传递和处理相关数据,例如在本地书架书籍更新、展示等场景下使用。 + */ public class LocBookShelfBean { + + /** + * 用于标识该书本是否为新书,布尔类型的值,true表示是新书,false表示不是新书, + * 通过这个标识可以在本地书架展示等功能中对新书进行特殊处理,比如突出显示新书、提醒用户有新添加的书籍等操作。 + */ private Boolean isNew; + + /** + * 存储具体的书架书本信息,是BookShelfBean类型的对象,包含了如书本的唯一标识、当前阅读章节、阅读进度、最后阅读时间等丰富的与书本在书架上相关的详细信息, + * 通过这个对象可以获取和操作具体书本在书架上的各项状态数据。 + */ private BookShelfBean bookShelfBean; - public LocBookShelfBean(Boolean isNew,BookShelfBean bookShelfBean){ + /** + * 构造函数,用于创建LocBookShelfBean类的对象实例,通过传入书本是否为新书的标识以及具体的书架书本信息对象, + * 来初始化对象内部对应的成员变量,从而构建一个完整的、包含本地书架相关信息的对象,方便后续在程序中使用。 + * @param isNew 表示书本是否为新书的布尔值,传入true表示新书,false表示非新书。 + * @param bookShelfBean 具体的书架书本信息对象,为BookShelfBean类型,包含了书本在书架上的各项详细状态数据。 + */ + public LocBookShelfBean(Boolean isNew, BookShelfBean bookShelfBean) { this.isNew = isNew; this.bookShelfBean = bookShelfBean; } + /** + * 获取书本是否为新书的标识,外部代码可以调用此方法来获取该书本的新书状态信息, + * 以便在本地书架展示、新书提醒等业务逻辑中根据这个标识进行相应处理,比如对新书进行特殊样式的展示等。 + * @return 布尔值,true表示书本是新书,false表示不是新书。 + */ public Boolean getNew() { return isNew; } + /** + * 设置书本是否为新书的标识,用于在书本新书状态发生变化时(比如原本不是新书,经过某些操作后变为新书了,或者反之), + * 对该对象内部存储的新书标识信息进行修改,确保数据的准确性和及时性,以便后续相关业务逻辑能正确处理。 + * @param aNew 要设置的表示书本是否为新书的布尔值,传入true表示新书,false表示非新书。 + */ public void setNew(Boolean aNew) { isNew = aNew; } + /** + * 获取具体的书架书本信息对象,外部代码可以通过调用此方法获取到BookShelfBean对象, + * 进而获取和操作书本在书架上的各项详细状态数据,比如获取当前阅读章节、更新阅读进度等操作。 + * @return BookShelfBean类型的对象,包含书本在书架上的各项详细状态数据。 + */ public BookShelfBean getBookShelfBean() { return bookShelfBean; } + /** + * 设置具体的书架书本信息对象,用于在需要更新书本在书架上的详细状态数据时(比如阅读进度变化、最后阅读时间更新等情况), + * 对该对象内部存储的BookShelfBean对象进行替换或修改,保证相关数据能反映书本的最新状态,以便后续业务逻辑基于准确的数据进行处理。 + * @param bookShelfBean 要设置的具体的书架书本信息对象,为BookShelfBean类型,包含了新的书本在书架上的各项详细状态数据。 + */ public void setBookShelfBean(BookShelfBean bookShelfBean) { this.bookShelfBean = bookShelfBean; } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/bean/ReadBookContentBean.java b/app/src/main/java/com/monke/monkeybook/bean/ReadBookContentBean.java index 235ca3e..1577288 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/ReadBookContentBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/ReadBookContentBean.java @@ -3,28 +3,68 @@ package com.monke.monkeybook.bean; import java.util.List; +/** + * ReadBookContentBean类主要用于封装阅读书籍时相关内容的信息,将书籍内容的具体数据(以BookContentBean列表形式)以及当前页面索引整合在一起, + * 方便在阅读书籍的业务流程中传递和处理这些数据,例如在翻页、章节切换等操作时使用,以保证阅读状态的准确记录与展示。 + */ public class ReadBookContentBean { + + /** + * 用于存储书籍内容的详细信息列表,每个元素是BookContentBean类型,BookContentBean中可能包含了如章节文本内容的具体段落、格式等详细信息, + * 通过这个列表可以完整地呈现出书籍的具体内容,方便在阅读过程中进行展示、排版等操作,是实现书籍阅读功能的核心数据部分。 + */ private List bookContentList; + + /** + * 记录当前阅读页面的索引值,用于标识读者当前所处的页面位置,在进行翻页操作(向前翻页或向后翻页)时,会根据这个索引值来更新显示相应页面的内容, + * 便于准确定位和切换阅读的具体页面,为用户提供流畅的阅读体验。 + */ private int pageIndex; - public ReadBookContentBean(List bookContentList,int pageIndex){ - this.bookContentList = bookContentList; + /** + * 构造函数,用于创建ReadBookContentBean类的对象实例,通过传入书籍内容信息列表以及当前页面索引值, + * 来初始化对象内部对应的成员变量,从而构建一个完整的、包含阅读书籍相关内容及页面位置信息的对象,方便后续在程序中使用。 + * @param bookContentList 包含BookContentBean元素的列表,代表书籍内容的详细信息集合,用于展示书籍的具体文本等内容。 + * @param pageIndex 当前阅读页面的索引值,用于定位当前所处的阅读页面位置。 + */ + public ReadBookContentBean(List bookContentList, int pageIndex) { + this.bookContentList = bookContentList; this.pageIndex = pageIndex; } + /** + * 获取书籍内容的详细信息列表,外部代码可以调用此方法来获取书籍完整的内容数据, + * 以便在阅读页面进行内容展示、排版以及其他与书籍内容相关的操作,例如根据不同的阅读设置(字体大小、排版样式等)对内容进行处理后展示给用户。 + * @return 包含BookContentBean元素的列表,代表书籍内容的详细信息集合。 + */ public List getBookContentList() { return bookContentList; } + /** + * 设置书籍内容的详细信息列表,用于在书籍内容发生更新(比如从网络重新获取了更完整准确的内容、本地内容有修改等情况)时, + * 对该对象内部存储的书籍内容数据进行替换或修改,确保展示给用户的内容是最新且准确的,保证阅读体验的连贯性和正确性。 + * @param bookContentList 包含BookContentBean元素的新列表,代表新的书籍内容的详细信息集合。 + */ public void setBookContentList(List bookContentList) { this.bookContentList = bookContentList; } + /** + * 获取当前阅读页面的索引值,外部代码可以通过调用此方法获取当前所处的页面位置信息, + * 例如在实现翻页按钮功能、页面滚动同步等操作时,依据这个索引值来确定要展示的具体页面内容,实现准确的阅读页面切换。 + * @return 当前阅读页面的索引值(整数),用于定位页面位置。 + */ public int getPageIndex() { return pageIndex; } + /** + * 设置当前阅读页面的索引值,用于在翻页操作(用户手动翻页或者根据阅读进度自动翻页等情况)、章节切换等场景下, + * 对该对象内部存储的页面索引信息进行更新,以便准确反映当前的阅读页面位置,保证后续页面展示内容的正确性。 + * @param pageIndex 要设置的当前阅读页面的索引值(整数),代表新的页面位置。 + */ public void setPageIndex(int pageIndex) { this.pageIndex = pageIndex; } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/bean/SearchBookBean.java b/app/src/main/java/com/monke/monkeybook/bean/SearchBookBean.java index 62ec1f2..81b6b4f 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/SearchBookBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/SearchBookBean.java @@ -4,36 +4,87 @@ package com.monke.monkeybook.bean; import android.os.Parcel; import android.os.Parcelable; -public class SearchBookBean implements Parcelable{ - +/** + * SearchBookBean类用于封装搜索书籍时所涉及的书籍相关信息,实现了Parcelable接口,方便在不同组件之间传递该书籍对象, + * 例如在搜索结果展示、书籍详情查看等场景中,可方便地将书籍数据进行传递和处理,是应用中与书籍搜索功能紧密相关的数据承载类。 + */ +public class SearchBookBean implements Parcelable { + + /** + * 对应书籍的唯一标识,其含义与前文相关类中的 `noteUrl` 类似,如果是来源网站,此处存储小说的根地址;如果是本地书本,则存储小说本地的MD5值, + * 用于区分不同的书籍资源,方便在后续的业务逻辑中(如查找、对比、关联等操作)准确地定位到具体的某一本书籍。 + */ private String noteUrl; + /** + * 存储书籍封面的地址,对于网络书籍可能是封面图片的网络链接,本地书籍则可能是本地封面图片文件的路径, + * 在展示搜索结果或者书籍详情页面时,可依据此地址来显示书籍的封面图片,增强书籍信息的展示效果,让用户更直观地了解书籍外观。 + */ private String coverUrl; + /** + * 书籍的名称,是识别一本书籍最基本且重要的属性,会展示给用户查看,方便用户快速知晓所搜索到的书籍是什么,在搜索结果列表等地方都会突出显示书名,以便用户识别。 + */ private String name; + /** + * 书籍的作者信息,记录了创作这本书的作者名字,一方面可以展示给用户了解书籍的创作来源,另一方面也可用于一些基于作者的搜索、分类或推荐等相关功能的实现,例如查找某一作者的所有作品等。 + */ private String author; + /** + * 书籍的字数统计,以长整型数据存储,表示书籍包含的字数总量,可用于向用户展示书籍篇幅情况,帮助用户大致判断阅读所需时间等,也能在书籍排序(如按字数多少排序)等功能中发挥作用。 + */ private long words; + /** + * 书籍的状态信息,具体含义可根据业务需求确定,比如可以表示书籍是否完结(如“已完结”“连载中”等状态),或者书籍的审核状态等其他相关状态描述,方便用户了解书籍的更新情况。 + */ private String state; + /** + * 书籍的最新章节名称,用于告知用户该书目前更新到了哪一章节,让用户知晓书籍的内容进度,特别是对于连载中的书籍,用户可通过此信息判断是否有新内容可读。 + */ private String lastChapter; + /** + * 用于标识书籍是否已添加的布尔值,初始值为 `false`,表示默认未添加,例如可以用来表示这本书是否已经添加到书架、收藏列表等用户个人的相关列表中,方便进行相应的业务逻辑处理和界面展示区分。 + */ private Boolean isAdd = false; + /** + * 用于给书籍添加额外的标识标签,具体含义可根据业务需求自定义,比如可以用来区分不同类型、不同风格(如玄幻、言情、科幻等风格标签)或者不同来源渠道等的书籍,便于对搜索结果进行筛选、分类展示等操作。 + */ private String tag; + /** + * 书籍所属的分类信息,例如“文学名著”“网络小说”“历史传记”等大分类,有助于在搜索结果中按照分类对书籍进行归类展示,方便用户更有条理地查找自己感兴趣的书籍类别。 + */ private String kind; + /** + * 书籍的来源信息,明确该书是从哪里获取的,比如是来自某个特定的网络文学平台、出版社,或者是用户自行导入的本地书籍等, + * 在数据溯源、针对不同来源进行差异化处理(如不同来源的书籍展示样式、更新方式等可能有所不同)以及版权管理等方面会用到该属性。 + */ private String origin; + /** + * 书籍的简介内容,通常是一段简要介绍书籍主要内容、情节亮点、主题思想等方面的文字,用于向用户展示书籍的大致情况,帮助用户在不阅读正文的情况下快速了解书籍是否符合自己的兴趣。 + */ private String desc; - public SearchBookBean(){ + /** + * 默认构造函数,用于创建SearchBookBean对象实例时进行默认的初始化操作,通常在没有初始值传入时使用,创建一个各成员变量为默认值的书籍信息对象,方便后续赋值操作。 + */ + public SearchBookBean() { } + /** + * 用于从一个Parcel对象中恢复SearchBookBean对象的构造函数,这是实现Parcelable接口要求的方法,用于对象的解包还原, + * 从传入的Parcel中按照顺序读取之前写入的各个属性值,来初始化当前对象的各个成员变量,确保对象能准确地从序列化数据中恢复出来。 + * @param in 包含对象序列化数据的Parcel对象。 + */ protected SearchBookBean(Parcel in) { noteUrl = in.readString(); coverUrl = in.readString(); @@ -42,13 +93,19 @@ public class SearchBookBean implements Parcelable{ words = in.readLong(); state = in.readString(); lastChapter = in.readString(); - isAdd = in.readByte() != 0; + isAdd = in.readByte()!= 0; tag = in.readString(); kind = in.readString(); origin = in.readString(); desc = in.readString(); } + /** + * 将SearchBookBean对象的属性数据写入到Parcel对象中,以便进行对象的序列化操作,这是实现Parcelable接口要求的方法,用于对象的打包发送, + * 按照一定顺序将对象的各个属性值写入到传入的Parcel对象中,方便后续在不同组件间传递对象并进行还原操作。 + * @param dest 要写入数据的Parcel对象。 + * @param flags 一些额外的标志位,一般使用默认值即可,可用于控制特殊的序列化行为等情况(但此处暂未体现特殊使用场景)。 + */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(noteUrl); @@ -58,18 +115,26 @@ public class SearchBookBean implements Parcelable{ dest.writeLong(words); dest.writeString(state); dest.writeString(lastChapter); - dest.writeByte((byte)(isAdd?1:0)); + dest.writeByte((byte) (isAdd? 1 : 0)); dest.writeString(tag); dest.writeString(kind); dest.writeString(origin); dest.writeString(desc); } + /** + * 返回当前对象的描述信息,一般如果对象内部有文件描述符等特殊情况需要返回相应的描述标记,此处返回0表示没有特殊内容需要描述,这是实现Parcelable接口要求的方法。 + * @return 一般返回0,表示没有特殊描述内容。 + */ @Override public int describeContents() { return 0; } + /** + * 用于创建SearchBookBean对象的静态内部类Creator,实现了Parcelable.Creator接口,提供了从Parcel对象创建SearchBookBean对象实例以及创建对象数组的方法,这是实现Parcelable接口要求的配套部分, + * 使得可以方便地从序列化数据中还原出单个对象或对象数组,满足不同场景下的对象传递和使用需求。 + */ public static final Creator CREATOR = new Creator() { @Override public SearchBookBean createFromParcel(Parcel in) { @@ -82,98 +147,193 @@ public class SearchBookBean implements Parcelable{ } }; + /** + * 获取书籍的唯一标识,方便外部代码获取该标识用于查找、对比等相关业务逻辑操作,例如判断两本书是否为同一本等情况。 + * @return 书籍唯一标识的字符串(noteUrl)。 + */ public String getNoteUrl() { return noteUrl; } + /** + * 设置书籍的唯一标识,用于在需要更新或修改书籍唯一标识的情况下(如数据同步后标识发生变化等)进行相应赋值操作,确保数据的准确性。 + * @param noteUrl 要设置的书籍唯一标识的字符串,需符合对应业务规则下的标识格式要求。 + */ public void setNoteUrl(String noteUrl) { this.noteUrl = noteUrl; } + /** + * 获取书籍封面的地址,外部代码可利用此地址来加载并显示书籍封面图片,例如在搜索结果列表或书籍详情页面展示封面,提升用户体验。 + * @return 书籍封面地址的字符串。 + */ public String getCoverUrl() { return coverUrl; } + /** + * 设置书籍封面的地址,用于在封面地址发生变化时(如服务器端更新了封面链接、本地封面文件路径改变等情况)进行相应赋值操作,保证封面能正确显示。 + * @param coverUrl 要设置的书籍封面地址的字符串,需符合相应的网络链接或本地路径格式要求。 + */ public void setCoverUrl(String coverUrl) { this.coverUrl = coverUrl; } + /** + * 获取书籍的名称,方便外部代码获取书名用于展示、搜索匹配等操作,例如在搜索结果列表中突出显示书名,或者根据书名进行二次搜索等情况。 + * @return 书籍名称的字符串。 + */ public String getName() { return name; } + /** + * 设置书籍的名称,虽然书籍名称通常相对固定,但在某些特殊情况下(如书名变更、数据修正等)可通过此方法进行赋值操作,更新对象内部存储的书名信息。 + * @param name 要设置的书籍名称的字符串,应传入符合书籍命名规范的有效名称内容。 + */ public void setName(String name) { this.name = name; } + /** + * 获取书籍的作者信息,外部代码可利用此信息进行基于作者的相关业务逻辑处理,如查找同一作者的其他作品、按照作者进行排序等操作。 + * @return 书籍作者信息的字符串。 + */ public String getAuthor() { return author; } + /** + * 设置书籍的作者信息,用于在作者信息发生变化(如发现之前记录有误、作者笔名更改等情况)时进行相应赋值操作,确保数据的准确性和及时性。 + * @param author 要设置的书籍作者信息的字符串,应传入真实有效的作者名字内容。 + */ public void setAuthor(String author) { this.author = author; } + /** + * 获取书籍是否已添加的标识,外部代码可根据此标识进行相应的界面展示和业务逻辑处理,例如对已添加的书籍在列表中显示不同的图标等情况。 + * @return 布尔值,true表示书籍已添加,false表示未添加。 + */ public Boolean getAdd() { return isAdd; } + /** + * 设置书籍是否已添加的标识,用于在书籍添加或移除操作(如添加到书架、从收藏列表移除等情况)发生后,更新对象内部的相应标识状态,以便后续业务逻辑能正确处理。 + * @param add 要设置的表示书籍是否已添加的布尔值,传入true表示已添加,false表示未添加。 + */ public void setAdd(Boolean add) { isAdd = add; } + /** + * 获取书籍的字数统计信息,外部代码可利用此数据向用户展示书籍篇幅情况,或者在进行书籍排序(如按字数多少排序)等功能中使用。 + * @return 书籍字数的长整型数值,表示书籍包含的总字数。 + */ public long getWords() { return words; } + /** + * 设置书籍的字数统计信息,用于在字数统计数据发生变化(如重新统计字数、数据修正等情况)时进行相应赋值操作,确保展示给用户的数据准确无误。 + * @param words 要设置的书籍字数的长整型数值,需传入合理有效的字数统计值。 + */ public void setWords(long words) { this.words = words; } + /** + * 获取书籍的状态信息,外部代码可根据此状态信息向用户展示书籍的更新情况,或者在进行筛选(如只显示完结书籍等情况)等功能中使用。 + * @return 书籍状态信息的字符串,如“已完结”“连载中”等符合业务定义的状态描述内容。 + */ public String getState() { return state; } + /** + * 设置书籍的状态信息,用于在书籍状态发生变化(如从连载变为完结、审核状态变更等情况)时进行相应赋值操作,保证展示给用户的状态信息准确反映书籍实际情况。 + * @param state 要设置的书籍状态信息的字符串,需传入符合业务规则的有效状态描述内容。 + */ public void setState(String state) { this.state = state; } + /** + * 获取书籍的最新章节名称,外部代码可利用此信息向用户展示书籍的内容进度,特别是对于连载书籍,方便用户了解是否有新内容可读。 + * @return 书籍最新章节名称的字符串,若值为null则返回空字符串,确保返回值的规范性。 + */ public String getLastChapter() { - return lastChapter==null?"":lastChapter; + return lastChapter == null? "" : lastChapter; } + /** + * 设置书籍的最新章节名称,用于在书籍更新新章节后,更新对象内部存储的最新章节名称信息,以便准确向用户展示书籍的最新内容进度。 + * @param lastChapter 要设置的书籍最新章节名称的字符串,应传入符合章节命名规范的有效章节名称内容。 + */ public void setLastChapter(String lastChapter) { this.lastChapter = lastChapter; } + /** + * 获取书籍所属的分类信息,外部代码可根据此分类信息对书籍进行归类展示、筛选等操作,例如在搜索结果中按照分类展示书籍列表,方便用户查找。 + * @return 书籍分类信息的字符串,如“文学名著”“网络小说”等符合业务定义的分类名称内容。 + */ public String getKind() { return kind; } + /** + * 设置书籍所属的分类信息,用于在书籍分类发生变化(如重新归类、分类标准调整等情况)时进行相应赋值操作,确保书籍能正确地在相应分类下展示和处理。 + * @param kind 要设置的书籍所属的分类信息的字符串,需传入符合业务规则的有效分类名称内容。 + */ public void setKind(String kind) { this.kind = kind; } + /** + * 获取书籍的标识标签,外部代码可利用此标签信息对书籍进行筛选、分类等操作,例如按照标签展示不同分组的书籍列表,方便用户查找感兴趣的书籍。 + * @return 书籍标识标签的字符串,如“玄幻”“热门推荐”等符合业务定义的标签内容。 + */ public String getTag() { return tag; } + /** + * 设置书籍的标识标签,用于在需要重新对书籍进行标记、分类,或者根据业务规则更新标签时进行相应赋值操作,实现对书籍标签的动态管理。 + * @param tag 要设置的书籍标识标签的字符串,需传入符合业务设定的标签格式和含义要求的内容。 + */ public void setTag(String tag) { this.tag = tag; } + /** + * 获取书籍的来源信息,外部代码可根据此来源信息进行数据溯源、差异化处理等相关业务逻辑操作,例如针对不同来源的书籍显示不同的提示信息等情况。 + * @return 书籍来源信息的字符串,如具体的网络平台名称、出版社名称等符合业务定义的来源描述内容。 + */ public String getOrigin() { return origin; } + /** + * 设置书籍的来源信息,用于在书籍来源发生变化(如更换了获取渠道、数据同步发现来源变更等情况)时进行相应赋值操作,确保数据的准确性和及时性。 + */ public void setOrigin(String origin) { this.origin = origin; } + /** + * 获取书籍的简介内容,外部代码可利用此简介向用户展示书籍的大致情况,帮助用户快速了解书籍是否符合自己的兴趣,例如在搜索结果列表或书籍详情页面展示简介内容。 + * @return 书籍简介内容的字符串,包含对书籍主要内容、亮点等方面的简要描述。 + */ public String getDesc() { return desc; } + /** + * 设置书籍的简介内容,用于在书籍简介发生变化(如更新了更准确详细的介绍、修改了描述内容等情况)时进行相应赋值操作,保证向用户展示的简介能准确反映书籍情况。 + * @param desc 要设置的书籍简介内容的字符串,需传入符合业务要求的有效简介文字内容。 + */ public void setDesc(String desc) { this.desc = desc; } diff --git a/app/src/main/java/com/monke/monkeybook/bean/SearchHistoryBean.java b/app/src/main/java/com/monke/monkeybook/bean/SearchHistoryBean.java index d5f6136..38fe7da 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/SearchHistoryBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/SearchHistoryBean.java @@ -6,43 +6,128 @@ import org.greenrobot.greendao.annotation.Id; import org.greenrobot.greendao.annotation.Unique; import org.greenrobot.greendao.annotation.Generated; +/** + * SearchHistoryBean类用于封装搜索历史相关的信息,通过使用GreenRobot的GreenDao框架相关注解(如@Entity、@Id等), + * 可方便地与数据库进行交互,实现搜索历史数据的持久化存储,便于在应用中记录和查询用户之前进行的搜索操作相关信息。 + */ @Entity public class SearchHistoryBean { + + /** + * @Id注解用于标识该字段作为数据库表中的主键,并且设置了`autoincrement = true`,表示这个主键字段的值会自动递增, + * 用于唯一标识每一条搜索历史记录,方便在数据库操作中对不同的搜索历史记录进行区分、查找、更新和删除等操作。 + * 初始值为`null`,在数据插入数据库时,数据库会根据规则自动为其赋予合适的自增值。 + */ @Id(autoincrement = true) private Long id = null; + + /** + * 用于表示搜索类型的整型字段,具体含义可根据业务需求定义,例如可以区分不同功能模块下的搜索(如在书城搜索书籍是一种类型,在本地书架搜索书籍又是另一种类型等), + * 通过这个字段可以对搜索历史按照类型进行分类统计或者筛选展示等操作。 + */ private int type; + + /** + * 存储用户实际输入的搜索内容,也就是用户在搜索框中输入的关键词等信息,方便后续展示给用户查看之前的搜索记录, + * 或者基于这些历史搜索内容进行智能提示、相关推荐等功能的实现,例如当用户再次打开搜索框时,自动显示之前搜索过的关键词供其选择。 + */ private String content; + + /** + * 记录搜索操作发生的时间戳,单位为毫秒,通过这个时间戳可以对搜索历史进行时间排序(如按照最近搜索的时间先后展示搜索历史列表), + * 也可以根据时间范围来筛选搜索历史记录(比如只显示最近一周、一个月内的搜索历史等),便于对搜索历史进行有效的管理和展示。 + */ private long date; + + /** + * 获取搜索操作发生的时间戳,外部代码可以调用此方法获取具体的时间信息,用于实现如按时间排序搜索历史记录、判断搜索记录是否过期等相关业务逻辑操作。 + * @return 搜索操作发生时间的长整型时间戳,单位为毫秒。 + */ public long getDate() { return this.date; } + + /** + * 设置搜索操作发生的时间戳,用于在需要更新或修正搜索历史记录的时间信息时(比如时间记录有误、进行时间同步等情况)进行相应赋值操作,确保时间数据的准确性。 + * @param date 要设置的搜索操作发生时间的长整型时间戳,单位为毫秒,需传入合理有效的时间值。 + */ public void setDate(long date) { this.date = date; } + + /** + * 获取用户输入的搜索内容,外部代码可利用此方法获取具体的搜索关键词等内容,用于展示搜索历史记录给用户查看, + * 或者在实现基于历史搜索内容的相关功能(如智能提示、联想搜索等)时使用这些数据。 + * @return 用户输入的搜索内容的字符串。 + */ public String getContent() { return this.content; } + + /** + * 设置用户输入的搜索内容,用于在需要更新搜索历史记录中的搜索关键词等情况时(比如用户修改了之前的搜索内容、纠正输入错误等)进行相应赋值操作,保证数据的准确性。 + * @param content 要设置的用户输入的搜索内容的字符串,需传入符合业务要求的有效搜索关键词内容。 + */ public void setContent(String content) { this.content = content; } + + /** + * 获取搜索的类型,外部代码可根据此类型信息对搜索历史记录进行分类处理,例如按照不同类型分别展示搜索历史、统计不同类型搜索的次数等操作, + * 以满足多样化的业务需求和用户体验优化需求。 + * @return 表示搜索类型的整型值,具体含义由业务定义。 + */ public int getType() { return this.type; } + + /** + * 设置搜索的类型,用于在搜索类型发生变化(如业务功能调整导致搜索类型重新划分等情况)时进行相应赋值操作,确保搜索历史记录中的类型信息准确反映实际情况。 + * @param type 要设置的表示搜索类型的整型值,需传入符合业务规则的有效类型定义值。 + */ public void setType(int type) { this.type = type; } + + /** + * 获取搜索历史记录的唯一标识(主键),外部代码在与数据库进行交互操作(如查找、删除特定搜索历史记录等)时, + * 会使用这个主键值来准确地定位到对应的记录,确保数据库操作的准确性和针对性。 + * @return 搜索历史记录的唯一标识(Long类型的主键值),在数据库中用于区分不同记录。 + */ public Long getId() { return this.id; } + + /** + * 设置搜索历史记录的唯一标识(主键),一般情况下不建议手动设置这个值,因为它通常是由数据库自动递增生成的, + * 但在一些特殊的数据迁移、初始化等场景下,可能需要手动赋值来确保数据的完整性和准确性,不过要谨慎操作以免破坏数据库的主键唯一性原则。 + * @param id 要设置的搜索历史记录的唯一标识(Long类型的主键值),需确保符合数据库主键的相关规则要求。 + */ public void setId(Long id) { this.id = id; } + /** + * 构造函数,用于创建SearchHistoryBean对象实例时,根据传入的搜索类型、搜索内容以及搜索时间信息来初始化对象的各个成员变量, + * 构建一个完整的搜索历史记录对象,方便在代码中快速创建并记录新的搜索历史信息,例如当用户执行一次搜索操作后,可使用此构造函数创建对应的搜索历史记录对象。 + * @param type 表示搜索类型的整型值,按照业务定义传入相应类型编号。 + * @param content 用户输入的搜索内容的字符串,传入有效的搜索关键词等内容。 + * @param date 搜索操作发生时间的长整型时间戳,单位为毫秒,传入合理的时间值表示搜索发生的时刻。 + */ public SearchHistoryBean(int type, String content, long date) { this.type = type; this.content = content; this.date = date; } + + /** + * 带有主键参数的构造函数,此构造函数是由GreenDao框架自动生成代码中使用的(通过@Generated注解标识), + * 一般在从数据库中查询数据并将其转换为SearchHistoryBean对象时会用到,根据传入的主键以及其他相关属性值来初始化对象,还原出完整的搜索历史记录对象。 + * @param id 搜索历史记录的唯一标识(Long类型的主键值),从数据库中获取对应记录的主键值传入。 + * @param type 表示搜索类型的整型值,从数据库中获取对应记录的类型值传入。 + * @param content 用户输入的搜索内容的字符串,从数据库中获取对应记录的搜索内容值传入。 + * @param date 搜索操作发生时间的长整型时间戳,单位为毫秒,从数据库中获取对应记录的时间值传入。 + */ @Generated(hash = 488115752) public SearchHistoryBean(Long id, int type, String content, long date) { this.id = id; @@ -50,8 +135,12 @@ public class SearchHistoryBean { this.content = content; this.date = date; } + + /** + * 默认构造函数,由GreenDao框架自动生成,用于创建一个默认状态的SearchHistoryBean对象实例,通常在一些框架内部初始化或者默认创建对象的场景下使用, + * 其成员变量会使用各自的默认初始值(如`id`为`null`,`type`等其他成员变量为对应类型的默认值),方便后续根据实际情况进行赋值操作。 + */ @Generated(hash = 1570282321) public SearchHistoryBean() { } - -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/bean/WebChapterBean.java b/app/src/main/java/com/monke/monkeybook/bean/WebChapterBean.java index a3a61a0..95385b9 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/WebChapterBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/WebChapterBean.java @@ -1,29 +1,68 @@ //Copyright (c) 2017. 章钦豪. All rights reserved. package com.monke.monkeybook.bean; +/** + * WebChapterBean类是一个泛型类,用于封装与网页章节相关的数据信息,它可以承载不同类型的数据(由泛型参数T决定)以及一个表示是否有下一章的布尔值, + * 在处理从网页获取章节内容等相关业务场景中,方便传递和操作章节相关的数据结构,具有较好的通用性和灵活性。 + */ public class WebChapterBean { + + /** + * 泛型成员变量,用于存储具体的章节相关数据,其类型由创建该类对象时指定的泛型参数决定,可以是各种类型,比如包含章节文本内容的字符串、 + * 章节详细信息的自定义对象等,通过这个变量能够灵活地适配不同格式或结构的章节数据,方便在不同业务场景下使用。 + */ private T data; + /** + * 用于标识是否存在下一章的布尔值,true表示存在下一章,false表示没有下一章了, + * 在网页章节浏览的业务逻辑中(如实现章节切换、判断是否能继续阅读下一章等操作),可以依据这个值来决定后续的行为和界面展示情况。 + */ private Boolean next; - public WebChapterBean(T data,Boolean next){ + /** + * 构造函数,用于创建WebChapterBean类的对象实例,通过传入具体的章节相关数据(由泛型参数指定类型)以及是否有下一章的布尔值, + * 来初始化对象内部对应的成员变量,从而构建一个完整的、包含章节信息及下一章标识的对象,方便后续在程序中使用。 + * @param data 具体的章节相关数据,其类型由泛型参数T决定,传入符合业务场景要求的对应类型的数据。 + * @param next 表示是否有下一章的布尔值,传入true表示存在下一章,false表示不存在下一章。 + */ + public WebChapterBean(T data, Boolean next) { this.data = data; this.next = next; } + /** + * 获取存储的具体章节相关数据,外部代码可以调用此方法来获取对应类型的章节数据, + * 以便进行后续的展示、处理或者其他与章节内容相关的操作,例如将获取到的章节文本内容显示在阅读界面上。 + * @return 泛型类型T的数据,代表章节相关信息,具体类型取决于创建对象时指定的泛型参数。 + */ public T getData() { return data; } + /** + * 设置存储的具体章节相关数据,用于在章节数据发生更新(比如重新从网页获取了更准确完整的数据、对数据进行了加工处理等情况)时, + * 对该对象内部存储的章节数据进行替换或修改,确保使用的数据是最新且符合业务需求的,保证相关业务逻辑的正确执行。 + * @param data 要设置的具体章节相关数据,其类型由泛型参数T决定,需传入符合业务场景要求的对应类型的新数据。 + */ public void setData(T data) { this.data = data; } + /** + * 获取是否存在下一章的标识,外部代码可以通过调用此方法获取该布尔值, + * 进而在章节切换、阅读导航等业务逻辑中根据这个标识来决定是否允许用户继续阅读下一章,或者进行相应的界面提示等操作。 + * @return 布尔值,true表示存在下一章,false表示不存在下一章。 + */ public Boolean getNext() { return next; } + /** + * 设置是否存在下一章的标识,用于在章节相关状态发生变化(比如初始判断没有下一章,但后续又检测到有新的章节可阅读等情况)时, + * 对该对象内部存储的下一章标识信息进行修改,以便准确反映当前的章节情况,确保业务逻辑(如章节切换按钮的可用性等)能正确处理。 + * @param next 要设置的表示是否有下一章的布尔值,传入true表示存在下一章,false表示不存在下一章。 + */ public void setNext(Boolean next) { this.next = next; } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/bean/WebContentBean.java b/app/src/main/java/com/monke/monkeybook/bean/WebContentBean.java index 1317d81..65fdc20 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/WebContentBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/WebContentBean.java @@ -1,28 +1,68 @@ //Copyright (c) 2017. 章钦豪. All rights reserved. package com.monke.monkeybook.bean; +/** + * WebContentBean类主要用于封装网页相关内容的信息,将网页的地址和网页对应的具体内容关联起来, + * 在涉及从网页获取并处理文本、展示网页内容等业务场景中,方便传递和操作相关数据,起到数据承载的作用。 + */ public class WebContentBean { + + /** + * 用于存储网页的地址,对于网络资源来说,这个地址可以是完整的URL(统一资源定位符),例如 "https://www.example.com/book/chapter1.html", + * 通过这个地址可以明确是从哪个网页获取的内容,也方便后续需要再次访问该网页或者进行相关的网络请求等操作时使用。 + */ private String url; + + /** + * 存储网页对应的具体内容,其格式和内容取决于网页本身,通常可能是HTML格式的文本内容(包含了网页中的文字、标签等信息),也可能是经过处理后的纯文本内容等, + * 这个内容会在需要展示网页文字信息、提取关键信息或者进行文本分析等业务操作中被使用到。 + */ private String content; - public WebContentBean(String url,String content){ + /** + * 构造函数,用于创建WebContentBean类的对象实例,通过传入网页的地址以及对应的内容, + * 来初始化对象内部对应的成员变量,从而构建一个完整的、包含网页地址和内容信息的对象,方便后续在程序中使用。 + * @param url 网页的地址字符串,需符合URL的格式规范,明确指向一个有效的网页资源。 + * @param content 网页对应的具体内容字符串,根据业务场景传入相应格式(如HTML文本、纯文本等)的内容信息。 + */ + public WebContentBean(String url, String content) { this.url = url; this.content = content; } + /** + * 获取网页的地址,外部代码可以调用此方法获取具体的网页地址信息, + * 例如在需要重新加载网页、根据地址判断内容来源或者进行与该网页相关的其他网络操作时使用这个地址。 + * @return 网页地址的字符串,格式符合URL规范。 + */ public String getUrl() { return url; } + /** + * 设置网页的地址,用于在网页地址发生变化(比如网页进行了重定向、地址更新等情况)时, + * 对该对象内部存储的网页地址信息进行修改,确保后续基于地址的相关操作能够准确地对应到正确的网页资源。 + * @param url 要设置的网页地址的字符串,需符合URL格式规范且指向有效的网页资源。 + */ public void setUrl(String url) { this.url = url; } + /** + * 获取网页对应的具体内容,外部代码可以调用此方法获取网页中的文本等相关内容, + * 例如在展示网页文字给用户、进行文本内容分析(如提取关键词、统计字数等)或者进行内容排版处理等业务操作中使用这些内容。 + * @return 网页对应的具体内容的字符串,格式根据业务场景可能为HTML文本、纯文本等形式。 + */ public String getContent() { return content; } + /** + * 设置网页对应的具体内容,用于在网页内容发生更新(比如重新获取了更新后的网页文本、对内容进行了加工处理等情况)时, + * 对该对象内部存储的网页内容信息进行修改,确保使用的内容是最新且符合业务需求的,保证相关业务操作基于准确的内容进行。 + * @param content 要设置的网页对应的具体内容的字符串,需传入符合业务场景要求的相应格式(如HTML文本、纯文本等)的新内容信息。 + */ public void setContent(String content) { this.content = content; } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/cache/ACache.java b/app/src/main/java/com/monke/monkeybook/cache/ACache.java index c56a77e..6030086 100644 --- a/app/src/main/java/com/monke/monkeybook/cache/ACache.java +++ b/app/src/main/java/com/monke/monkeybook/cache/ACache.java @@ -5,39 +5,68 @@ import android.content.Context; import android.content.SharedPreferences; /** - * 本地缓存 因本缓存只缓存书库主页 所以使用SP有条件可以替换成别的 + * 本地缓存类 ACache,用于在本地存储和获取一些数据。当前这个缓存主要是针对书库主页相关数据进行缓存操作, + * 由于其功能相对特定,所以暂时使用了 Android 系统提供的 SharedPreferences(简称 SP)来实现缓存功能。 + * 备注里提到如果有条件的话,可以替换成其他更合适的缓存机制,比如数据库缓存或者其他第三方缓存库等,具体取决于业务需求和性能等方面的考量。 */ public class ACache { + + /** + * 用于存储 SharedPreferences 实例,SharedPreferences 是 Android 中一种轻量级的数据存储方式, + * 可以方便地以键值对的形式存储和读取简单的数据类型(如字符串、整型、布尔型等),在这里它将作为缓存数据的存储容器, + * 通过它来实现对书库主页相关数据的持久化存储以及后续的读取操作。 + */ private SharedPreferences preference; - private ACache(Context ctx){ - preference = ctx.getSharedPreferences("ACache",0); + + /** + * 私有构造函数,用于创建 ACache 类的实例对象,它接收一个 Context 类型的参数,通过这个 Context 获取应用的 SharedPreferences 对象, + * 并且指定了 SharedPreferences 的名称为 "ACache",操作模式为 0(对应 MODE_PRIVATE,表示只有当前应用可以访问该 SharedPreferences 文件)。 + * 采用私有构造函数的设计模式可以控制类的实例化过程,保证缓存对象的创建符合特定规则并且在合适的上下文中进行。 + * @param ctx Android 的 Context 对象,用于获取应用的相关资源以及操作应用级别的功能,在这里用于获取 SharedPreferences。 + */ + private ACache(Context ctx) { + preference = ctx.getSharedPreferences("ACache", 0); } + /** + * 静态工厂方法,用于获取 ACache 类的实例对象,外部代码通过调用这个方法并传入 Context 参数来获取一个 ACache 实例, + * 这样的设计模式使得获取缓存实例的过程更加清晰、方便,并且符合单一职责原则,将对象的创建和使用分离开来。 + * @param ctx Android 的 Context 对象,用于创建对应的 ACache 实例,以便在正确的应用上下文中操作缓存。 + * @return 返回一个 ACache 实例对象,通过该对象可以进行缓存数据的读写等操作。 + */ public static ACache get(Context ctx) { return new ACache(ctx); } + /** + * 用于向缓存中写入数据,将指定的键(key)和对应的值(value,这里限定为字符串类型)存储到 SharedPreferences 中, + * 它首先获取 SharedPreferences 的编辑器(Editor)对象,通过编辑器来设置要存储的键值对,然后提交更改,使得数据真正写入到存储中。 + * 如果在操作过程中出现异常(比如存储空间不足等情况),则会捕获异常并进行简单处理(当前代码只是捕获异常但不做额外操作,可根据实际需求完善异常处理逻辑)。 + * @param key 用于标识存储数据的键,是一个字符串类型,需要保证其唯一性,以便后续准确地通过该键来获取对应的数据,通常根据缓存数据的业务含义来定义合适的键名。 + * @param value 要存储的字符串类型的值,即需要缓存的具体数据内容,可以是书库主页相关的各种文本数据,比如页面配置信息、缓存的部分 HTML 内容等。 + */ public void put(String key, String value) { - try{ + try { SharedPreferences.Editor editor = preference.edit(); editor.putString(key, value); editor.commit(); - }catch (Exception e){ + } catch (Exception e) { } } /** - * 读取 String数据 - * - * @param key - * @return String 数据 + * 读取缓存中存储的字符串类型数据的方法,根据传入的键(key)从 SharedPreferences 中查找对应的字符串值并返回。 + * 如果在读取过程中出现异常(比如键不存在、存储文件损坏等情况),则会捕获异常并返回 null,表示读取失败, + * 这样调用者可以根据返回值来判断是否成功获取到了期望的数据,进而进行相应的业务逻辑处理。 + * @param key 用于查找数据的键,是一个字符串类型,需要与之前存储数据时使用的键保持一致,以便准确获取对应的缓存数据。 + * @return 返回从缓存中读取到的字符串类型的数据,如果读取失败(出现异常情况)则返回 null。 */ public String getAsString(String key) { - try{ - return preference.getString(key,null); - }catch (Exception e){ + try { + return preference.getString(key, null); + } catch (Exception e) { return null; } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/widget/checkbox/SmoothCheckBox.java b/app/src/main/java/com/monke/monkeybook/widget/checkbox/SmoothCheckBox.java index c7ffa5a..0731865 100644 --- a/app/src/main/java/com/monke/monkeybook/widget/checkbox/SmoothCheckBox.java +++ b/app/src/main/java/com/monke/monkeybook/widget/checkbox/SmoothCheckBox.java @@ -19,83 +19,122 @@ import android.widget.Checkable; import com.monke.monkeybook.R; import com.monke.monkeybook.utils.DensityUtil; +// 自定义的CheckBox视图类,实现了平滑的勾选动画效果,并且实现了Checkable接口 public class SmoothCheckBox extends View implements Checkable { + // 用于保存和恢复视图状态的键 private static final String KEY_INSTANCE_STATE = "InstanceState"; + // 勾选标记的颜色,默认为白色 private static final int COLOR_TICK = Color.WHITE; + // 未选中时内部填充颜色,默认为白色 private static final int COLOR_UNCHECKED = Color.WHITE; + // 选中时的颜色,这里解析为特定的十六进制颜色值 private static final int COLOR_CHECKED = Color.parseColor("#FB4846"); + // 未选中时边框颜色,解析为特定十六进制颜色值 private static final int COLOR_FLOOR_UNCHECKED = Color.parseColor("#DFDFDF"); + // 默认的绘制尺寸(单位:dp),用于在未指定具体大小时的参考尺寸 private static final int DEF_DRAW_SIZE = 25; + // 默认的动画持续时间(单位:毫秒) private static final int DEF_ANIM_DURATION = 300; + // 用于绘制内部填充、勾选标记、边框等的画笔对象 private Paint mPaint, mTickPaint, mFloorPaint; + // 构成勾选标记的点坐标数组 private Point[] mTickPoints; + // 视图的中心点坐标 private Point mCenterPoint; + // 用于绘制勾选标记的路径对象 private Path mTickPath; - + // 记录勾选标记左边线已绘制的距离、右边线已绘制的距离、总的已绘制距离 private float mLeftLineDistance, mRightLineDistance, mDrewDistance; + // 用于控制内部填充缩放的比例值、边框缩放比例值 private float mScaleVal = 1.0f, mFloorScale = 1.0f; + // 视图的宽度、动画持续时间、画笔的描边宽度 private int mWidth, mAnimDuration, mStrokeWidth; + // 选中时颜色、未选中时颜色、边框颜色、未选中时边框原本颜色(初始与边框颜色一致,可能后续变化) private int mCheckedColor, mUnCheckedColor, mFloorColor, mFloorUnCheckedColor; + // 记录当前是否被选中 private boolean mChecked; + // 标记是否正在绘制勾选标记 private boolean mTickDrawing; + // 用于监听选中状态变化的监听器对象 private OnCheckedChangeListener mListener; + // 构造函数,调用含AttributeSet参数的构造函数并传入默认的属性集为null public SmoothCheckBox(Context context) { this(context, null); } + // 构造函数,调用含AttributeSet和默认样式属性参数的构造函数并传入默认样式属性为0 public SmoothCheckBox(Context context, AttributeSet attrs) { this(context, attrs, 0); } + // 主要的构造函数,用于初始化视图,获取自定义属性并进行一些初始化操作 public SmoothCheckBox(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); } + // 针对Android Lollipop及以上版本的构造函数,同样调用init方法进行初始化 @TargetApi(Build.VERSION_CODES.LOLLIPOP) public SmoothCheckBox(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(attrs); } + // 初始化方法,获取自定义属性,创建画笔对象,设置点击事件等 private void init(AttributeSet attrs) { - + // 获取自定义属性数组 TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.SmoothCheckBox); + // 获取勾选标记颜色,若未设置则使用默认颜色 int tickColor = ta.getColor(R.styleable.SmoothCheckBox_color_tick, COLOR_TICK); + // 获取动画持续时间,若未设置则使用默认时间 mAnimDuration = ta.getInt(R.styleable.SmoothCheckBox_duration, DEF_ANIM_DURATION); + // 获取未选中时边框颜色,若未设置则使用默认颜色 mFloorColor = ta.getColor(R.styleable.SmoothCheckBox_color_unchecked_stroke, COLOR_FLOOR_UNCHECKED); + // 获取选中时颜色,若未设置则使用默认颜色 mCheckedColor = ta.getColor(R.styleable.SmoothCheckBox_color_checked, COLOR_CHECKED); + // 获取未选中时内部填充颜色,若未设置则使用默认颜色 mUnCheckedColor = ta.getColor(R.styleable.SmoothCheckBox_color_unchecked, COLOR_UNCHECKED); + // 获取画笔描边宽度,若未设置则转换dp值为px值(这里为0时的处理) mStrokeWidth = ta.getDimensionPixelSize(R.styleable.SmoothCheckBox_stroke_width, DensityUtil.dp2px(getContext(), 0)); + // 回收属性数组资源 ta.recycle(); + // 初始化未选中时边框原本颜色,初始与边框颜色一致 mFloorUnCheckedColor = mFloorColor; + + // 创建勾选标记画笔,设置抗锯齿、描边样式、端点样式以及颜色 mTickPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTickPaint.setStyle(Paint.Style.STROKE); mTickPaint.setStrokeCap(Paint.Cap.ROUND); mTickPaint.setColor(tickColor); + // 创建边框画笔,设置抗锯齿、填充样式以及颜色 mFloorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mFloorPaint.setStyle(Paint.Style.FILL); mFloorPaint.setColor(mFloorColor); + // 创建内部填充画笔,设置抗锯齿、填充样式以及颜色 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(mCheckedColor); + // 创建绘制勾选标记的路径对象 mTickPath = new Path(); + // 创建中心点坐标对象 mCenterPoint = new Point(); + // 创建构成勾选标记的点坐标数组并初始化三个点对象 mTickPoints = new Point[3]; mTickPoints[0] = new Point(); mTickPoints[1] = new Point(); mTickPoints[2] = new Point(); + // 设置点击事件,点击时切换选中状态,重置相关绘制参数,并根据选中与否启动相应动画 setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -111,6 +150,7 @@ public class SmoothCheckBox extends View implements Checkable { }); } + // 保存视图状态,将当前选中状态和父类的状态一起保存到Bundle中 @Override protected Parcelable onSaveInstanceState() { Bundle bundle = new Bundle(); @@ -119,6 +159,7 @@ public class SmoothCheckBox extends View implements Checkable { return bundle; } + // 恢复视图状态,从Bundle中获取选中状态并设置,同时恢复父类的状态 @Override protected void onRestoreInstanceState(Parcelable state) { if (state instanceof Bundle) { @@ -131,31 +172,30 @@ public class SmoothCheckBox extends View implements Checkable { super.onRestoreInstanceState(state); } + // 获取当前是否被选中的状态 @Override public boolean isChecked() { return mChecked; } + // 切换选中状态 @Override public void toggle() { this.setChecked(!isChecked()); } + // 设置选中状态,更新选中标记,重绘视图,若有监听器则触发状态变化回调 @Override public void setChecked(boolean checked) { mChecked = checked; reset(); invalidate(); - if (mListener != null) { + if (mListener!= null) { mListener.onCheckedChanged(SmoothCheckBox.this, mChecked); } } - /** - * checked with animation - * @param checked checked - * @param animate change with animation - */ + // 设置选中状态,可选择是否带动画效果,根据参数决定是否启动相应动画以及触发监听器回调 public void setChecked(boolean checked, boolean animate) { if (animate) { mTickDrawing = false; @@ -166,7 +206,7 @@ public class SmoothCheckBox extends View implements Checkable { } else { startUnCheckedAnimation(); } - if (mListener != null) { + if (mListener!= null) { mListener.onCheckedChanged(SmoothCheckBox.this, mChecked); } @@ -175,14 +215,16 @@ public class SmoothCheckBox extends View implements Checkable { } } + // 重置一些绘制相关的参数,根据选中状态设置初始值 private void reset() { mTickDrawing = true; mFloorScale = 1.0f; - mScaleVal = isChecked() ? 0f : 1.0f; - mFloorColor = isChecked() ? mCheckedColor : mFloorUnCheckedColor; - mDrewDistance = isChecked() ? (mLeftLineDistance + mRightLineDistance) : 0; + mScaleVal = isChecked()? 0f : 1.0f; + mFloorColor = isChecked()? mCheckedColor : mFloorUnCheckedColor; + mDrewDistance = isChecked()? (mLeftLineDistance + mRightLineDistance) : 0; } + // 根据测量规格计算视图的尺寸,参考默认尺寸和测量规格中的尺寸限制 private int measureSize(int measureSpec) { int defSize = DensityUtil.dp2px(getContext(), DEF_DRAW_SIZE); int specSize = MeasureSpec.getSize(measureSpec); @@ -201,18 +243,20 @@ public class SmoothCheckBox extends View implements Checkable { return result; } + // 测量视图尺寸,调用measureSize方法确定宽高尺寸 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(measureSize(widthMeasureSpec), measureSize(heightMeasureSpec)); } + // 布局视图,确定视图的宽度、画笔描边宽度(进行一些边界处理),计算中心点坐标以及构成勾选标记的点坐标等 @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { mWidth = getMeasuredWidth(); - mStrokeWidth = (mStrokeWidth == 0 ? getMeasuredWidth() / 10 : mStrokeWidth); - mStrokeWidth = mStrokeWidth > getMeasuredWidth() / 5 ? getMeasuredWidth() / 5 : mStrokeWidth; - mStrokeWidth = (mStrokeWidth < 3) ? 3 : mStrokeWidth; + mStrokeWidth = (mStrokeWidth == 0? getMeasuredWidth() / 10 : mStrokeWidth); + mStrokeWidth = mStrokeWidth > getMeasuredWidth() / 5? getMeasuredWidth() / 5 : mStrokeWidth; + mStrokeWidth = (mStrokeWidth < 3)? 3 : mStrokeWidth; mCenterPoint.x = mWidth / 2; mCenterPoint.y = getMeasuredHeight() / 2; @@ -230,6 +274,7 @@ public class SmoothCheckBox extends View implements Checkable { mTickPaint.setStrokeWidth(mStrokeWidth); } + // 绘制视图,依次调用绘制边框、绘制内部填充、绘制勾选标记的方法 @Override protected void onDraw(Canvas canvas) { drawBorder(canvas); @@ -237,29 +282,34 @@ public class SmoothCheckBox extends View implements Checkable { drawTick(canvas); } + // 绘制内部填充,根据选中状态设置颜色,并根据缩放比例绘制圆形填充 private void drawCenter(Canvas canvas) { mPaint.setColor(mUnCheckedColor); float radius = (mCenterPoint.x - mStrokeWidth) * mScaleVal; canvas.drawCircle(mCenterPoint.x, mCenterPoint.y, radius, mPaint); } - private void drawBorder(Canvas canvas) { + // 绘制边框,设置边框颜色,根据边框缩放比例绘制圆形边框 + private void drawBorder(canvas) { mFloorPaint.setColor(mFloorColor); int radius = mCenterPoint.x; canvas.drawCircle(mCenterPoint.x, mCenterPoint.y, radius * mFloorScale, mFloorPaint); } + // 根据是否正在绘制以及是否选中来决定是否绘制勾选标记 private void drawTick(Canvas canvas) { if (mTickDrawing && isChecked()) { drawTickPath(canvas); } } - private void drawTickPath(Canvas canvas) { + // 绘制勾选标记的具体方法,根据已绘制距离逐步绘制勾选标记的线段,处理左边线、右边线的绘制逻辑, + // 并且根据是否绘制完成决定是否继续触发重绘来完成动画效果 + private void drawTickPath(canvas) { mTickPath.reset(); - // draw left of the tick + // 绘制左边的勾选标记线段 if (mDrewDistance < mLeftLineDistance) { - float step = (mWidth / 20.0f) < 3 ? 3 : (mWidth / 20.0f); + float step = (mWidth / 20.0f) < 3? 3 : (mWidth / 20.0f); mDrewDistance += step; float stopX = mTickPoints[0].x + (mTickPoints[1].x - mTickPoints[0].x) * mDrewDistance / mLeftLineDistance; float stopY = mTickPoints[0].y + (mTickPoints[1].y - mTickPoints[0].y) * mDrewDistance / mLeftLineDistance; @@ -277,7 +327,7 @@ public class SmoothCheckBox extends View implements Checkable { mTickPath.lineTo(mTickPoints[1].x, mTickPoints[1].y); canvas.drawPath(mTickPath, mTickPaint); - // draw right of the tick + // 绘制右边的勾选标记线段 if (mDrewDistance < mLeftLineDistance + mRightLineDistance) { float stopX = mTickPoints[1].x + (mTickPoints[2].x - mTickPoints[1].x) * (mDrewDistance - mLeftLineDistance) / mRightLineDistance; float stopY = mTickPoints[1].y - (mTickPoints[1].y - mTickPoints[2].y) * (mDrewDistance - mLeftLineDistance) / mRightLineDistance; @@ -287,7 +337,7 @@ public class SmoothCheckBox extends View implements Checkable { mTickPath.lineTo(stopX, stopY); canvas.drawPath(mTickPath, mTickPaint); - float step = (mWidth / 20) < 3 ? 3 : (mWidth / 20); + float step = (mWidth / 20) < 3? 3 : (mWidth / 20); mDrewDistance += step; } else { mTickPath.reset(); @@ -297,7 +347,7 @@ public class SmoothCheckBox extends View implements Checkable { } } - // invalidate + // 若还未完成勾选标记绘制,则延迟触发重绘来继续动画效果 if (mDrewDistance < mLeftLineDistance + mRightLineDistance) { postDelayed(new Runnable() { @Override @@ -306,97 +356,4 @@ public class SmoothCheckBox extends View implements Checkable { } }, 10); } - } - - private void startCheckedAnimation() { - ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0f); - animator.setDuration(mAnimDuration / 3 * 2); - animator.setInterpolator(new LinearInterpolator()); - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mScaleVal = (float) animation.getAnimatedValue(); - mFloorColor = getGradientColor(mUnCheckedColor, mCheckedColor, 1 - mScaleVal); - postInvalidate(); - } - }); - animator.start(); - - ValueAnimator floorAnimator = ValueAnimator.ofFloat(1.0f, 0.8f, 1.0f); - floorAnimator.setDuration(mAnimDuration); - floorAnimator.setInterpolator(new LinearInterpolator()); - floorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mFloorScale = (float) animation.getAnimatedValue(); - postInvalidate(); - } - }); - floorAnimator.start(); - - drawTickDelayed(); - } - - private void startUnCheckedAnimation() { - ValueAnimator animator = ValueAnimator.ofFloat(0f, 1.0f); - animator.setDuration(mAnimDuration); - animator.setInterpolator(new LinearInterpolator()); - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mScaleVal = (float) animation.getAnimatedValue(); - mFloorColor = getGradientColor(mCheckedColor, mFloorUnCheckedColor, mScaleVal); - postInvalidate(); - } - }); - animator.start(); - - ValueAnimator floorAnimator = ValueAnimator.ofFloat(1.0f, 0.8f, 1.0f); - floorAnimator.setDuration(mAnimDuration); - floorAnimator.setInterpolator(new LinearInterpolator()); - floorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mFloorScale = (float) animation.getAnimatedValue(); - postInvalidate(); - } - }); - floorAnimator.start(); - } - - private void drawTickDelayed() { - postDelayed(new Runnable() { - @Override - public void run() { - mTickDrawing = true; - postInvalidate(); - } - }, mAnimDuration); - } - - private static int getGradientColor(int startColor, int endColor, float percent) { - int startA = Color.alpha(startColor); - int startR = Color.red(startColor); - int startG = Color.green(startColor); - int startB = Color.blue(startColor); - - int endA = Color.alpha(endColor); - int endR = Color.red(endColor); - int endG = Color.green(endColor); - int endB = Color.blue(endColor); - - int currentA = (int) (startA * (1 - percent) + endA * percent); - int currentR = (int) (startR * (1 - percent) + endR * percent); - int currentG = (int) (startG * (1 - percent) + endG * percent); - int currentB = (int) (startB * (1 - percent) + endB * percent); - return Color.argb(currentA, currentR, currentG, currentB); - } - - public void setOnCheckedChangeListener(OnCheckedChangeListener l) { - this.mListener = l; - } - - public interface OnCheckedChangeListener { - void onCheckedChanged(SmoothCheckBox checkBox, boolean isChecked); - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/widget/contentswitchview/BookContentView.java b/app/src/main/java/com/monke/monkeybook/widget/contentswitchview/BookContentView.java index 9135460..05e1421 100644 --- a/app/src/main/java/com/monke/monkeybook/widget/contentswitchview/BookContentView.java +++ b/app/src/main/java/com/monke/monkeybook/widget/contentswitchview/BookContentView.java @@ -18,62 +18,95 @@ import com.monke.monkeybook.widget.MTextView; import java.util.List; +// 表示书籍内容展示的自定义视图类,继承自FrameLayout,用于展示书籍相关内容、加载状态等信息 public class BookContentView extends FrameLayout { + // 用于标记当前视图的一个唯一标识,这里初始化为当前系统时间的毫秒数,可能用于区分不同的数据请求等情况 public long qTag = System.currentTimeMillis(); + // 定义常量,表示章节起始页面索引的特殊值(从头开始) public static final int DURPAGEINDEXBEGIN = -1; + // 定义常量,表示章节结束页面索引的特殊值(从尾开始) public static final int DURPAGEINDEXEND = -2; + // 根视图对象,通过LayoutInflater加载布局文件得到 private View view; + // 用于显示背景的ImageView private ImageView ivBg; + // 用于显示章节标题的TextView private TextView tvTitle; + // 用于容纳书籍内容文本的LinearLayout private LinearLayout llContent; + // 自定义的用于显示书籍内容的TextView(MTextView类型,可能有特殊功能) private MTextView tvContent; + // 底部的视图,可能用于布局分割等作用 private View vBottom; + // 用于显示当前页码相关信息的TextView private TextView tvPage; + // 用于显示加载中的提示文本的TextView private TextView tvLoading; + // 用于显示加载出错相关信息的LinearLayout,包含错误提示和重新加载按钮等 private LinearLayout llError; + // 用于显示具体错误信息的TextView private TextView tvErrorInfo; + // 用于点击重新加载的TextView按钮 private TextView tvLoadAgain; + // 书籍章节标题 private String title; + // 书籍章节内容 private String content; + // 当前章节索引 private int durChapterIndex; + // 总章节数 private int chapterAll; - private int durPageIndex; //如果durPageIndex = -1 则是从头开始 -2则是从尾开始 + // 当前页面索引,如果值为 -1 表示从头开始, -2 表示从尾开始 + private int durPageIndex; + // 总页面数 private int pageAll; + // 用于监听数据加载的监听器接口对象,由外部传入,负责加载数据相关操作 private ContentSwitchView.LoadDataListener loadDataListener; - + // 用于监听设置数据完成的监听器接口对象,由外部传入,在数据设置完成后进行相应处理 private SetDataListener setDataListener; + // 定义设置数据完成的监听器接口,外部类实现此接口来处理数据设置完成后的逻辑 public interface SetDataListener { + // 当数据设置完成时调用的方法,传入相关章节、页面等索引信息 public void setDataFinish(BookContentView bookContentView, int durChapterIndex, int chapterAll, int durPageIndex, int pageAll, int fromPageIndex); } + // 构造函数,调用含AttributeSet参数的构造函数并传入默认的属性集为null public BookContentView(Context context) { this(context, null); } + // 构造函数,调用含AttributeSet和默认样式属性参数的构造函数并传入默认样式属性为0 public BookContentView(Context context, AttributeSet attrs) { this(context, attrs, 0); } + // 主要的构造函数,用于初始化视图,调用init方法进行初始化操作 public BookContentView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } + // 针对Android Lollipop及以上版本的构造函数,同样调用init方法进行初始化 @TargetApi(Build.VERSION_CODES.LOLLIPOP) public BookContentView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); } + // 初始化方法,加载布局文件,找到各个子视图组件,并设置重新加载按钮的点击事件 private void init() { + // 通过LayoutInflater从当前上下文加载指定布局文件,并且不立即添加到父视图(this) view = LayoutInflater.from(getContext()).inflate(R.layout.adapter_content_switch_item, this, false); + // 将加载的视图添加到当前的FrameLayout中 addView(view); + + // 通过findViewById方法找到布局中的各个子视图组件 ivBg = (ImageView) view.findViewById(R.id.iv_bg); tvTitle = (TextView) view.findViewById(R.id.tv_title); llContent = (LinearLayout) view.findViewById(R.id.ll_content); @@ -86,32 +119,36 @@ public class BookContentView extends FrameLayout { tvErrorInfo = (TextView) view.findViewById(R.id.tv_error_info); tvLoadAgain = (TextView) view.findViewById(R.id.tv_load_again); + // 设置重新加载按钮的点击事件,点击时如果加载数据监听器不为空,则调用loading方法进行数据重新加载 tvLoadAgain.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - if (loadDataListener != null) + if (loadDataListener!= null) loading(); } }); } + // 用于显示加载中的状态,隐藏错误信息视图,显示加载提示视图,隐藏内容视图,并更新qTag,同时调用加载数据监听器的加载方法 public void loading() { llError.setVisibility(GONE); tvLoading.setVisibility(VISIBLE); llContent.setVisibility(INVISIBLE); qTag = System.currentTimeMillis(); - //执行请求操作 - if (loadDataListener != null) { + // 如果加载数据监听器不为空,则调用其loaddata方法,传入当前视图、qTag以及章节、页面索引等信息进行数据加载 + if (loadDataListener!= null) { loadDataListener.loaddata(this, qTag, durChapterIndex, durPageIndex); } } + // 用于完成数据加载后的状态设置,隐藏错误信息视图,显示内容视图,隐藏加载提示视图 public void finishLoading() { llError.setVisibility(GONE); llContent.setVisibility(VISIBLE); tvLoading.setVisibility(GONE); } + // 设置无数据时的显示内容,更新当前内容,设置页码文本,并调用finishLoading方法完成加载状态设置 public void setNoData(String contentLines) { this.content = contentLines; @@ -120,9 +157,11 @@ public class BookContentView extends FrameLayout { finishLoading(); } + // 根据传入的标记、标题、内容列表等信息更新视图显示的数据,判断标记是否匹配,若匹配则调用设置数据监听器方法, + // 处理内容文本拼接、更新各个相关属性,并更新视图上的标题、内容、页码等显示信息,最后调用finishLoading方法 public void updateData(long tag, String title, List contentLines, int durChapterIndex, int chapterAll, int durPageIndex, int durPageAll) { if (tag == qTag) { - if (setDataListener != null) { + if (setDataListener!= null) { setDataListener.setDataFinish(this, durChapterIndex, chapterAll, durPageIndex, durPageAll, this.durPageIndex); } if (contentLines == null) { @@ -148,6 +187,7 @@ public class BookContentView extends FrameLayout { } } + // 用于加载数据的入口方法,设置标题、章节、页面索引等属性,更新标题和页码文本显示,然后调用loading方法开始加载数据 public void loadData(String title, int durChapterIndex, int chapterAll, int durPageIndex) { this.title = title; this.durChapterIndex = durChapterIndex; @@ -159,77 +199,95 @@ public class BookContentView extends FrameLayout { loading(); } + // 获取数据加载监听器对象 public ContentSwitchView.LoadDataListener getLoadDataListener() { return loadDataListener; } + // 设置数据加载监听器和设置数据监听器对象 public void setLoadDataListener(ContentSwitchView.LoadDataListener loadDataListener, SetDataListener setDataListener) { this.loadDataListener = loadDataListener; this.setDataListener = setDataListener; } + // 单独设置数据加载监听器对象 public void setLoadDataListener(ContentSwitchView.LoadDataListener loadDataListener) { this.loadDataListener = loadDataListener; } + // 用于显示加载出错的状态,显示错误信息视图,隐藏加载提示视图,隐藏内容视图 public void loadError() { llError.setVisibility(VISIBLE); tvLoading.setVisibility(GONE); llContent.setVisibility(INVISIBLE); } + // 获取总页面数 public int getPageAll() { return pageAll; } + // 设置总页面数 public void setPageAll(int pageAll) { this.pageAll = pageAll; } + // 获取当前页面索引 public int getDurPageIndex() { return durPageIndex; } + // 设置当前页面索引 public void setDurPageIndex(int durPageIndex) { this.durPageIndex = durPageIndex; } + // 获取当前章节索引 public int getDurChapterIndex() { return durChapterIndex; } + // 设置当前章节索引 public void setDurChapterIndex(int durChapterIndex) { this.durChapterIndex = durChapterIndex; } + // 获取总章节数 public int getChapterAll() { return chapterAll; } + // 设置总章节数 public void setChapterAll(int chapterAll) { this.chapterAll = chapterAll; } + // 获取设置数据监听器对象 public SetDataListener getSetDataListener() { return setDataListener; } + // 设置设置数据监听器对象 public void setSetDataListener(SetDataListener setDataListener) { this.setDataListener = setDataListener; } + // 获取用于标记的qTag值 public long getqTag() { return qTag; } + // 设置用于标记的qTag值 public void setqTag(long qTag) { this.qTag = qTag; } + // 获取用于显示书籍内容的TextView对象 public TextView getTvContent() { return tvContent; } + // 根据给定的高度计算可显示的文本行数,通过获取文本的ascent、descent来计算文本高度,结合行间距等信息进行计算 public int getLineCount(int height) { float ascent = tvContent.getPaint().ascent(); float descent = tvContent.getPaint().descent(); @@ -237,11 +295,13 @@ public class BookContentView extends FrameLayout { return (int) ((height * 1.0f - tvContent.getLineSpacingExtra()) / (textHeight + tvContent.getLineSpacingExtra())); } + // 设置阅读书籍相关的控制属性,调用设置文本样式和背景的方法 public void setReadBookControl(ReadBookControl readBookControl) { setTextKind(readBookControl); setBg(readBookControl); } + // 设置背景相关属性,包括背景图片、各个文本组件的颜色等,根据传入的ReadBookControl对象中的配置进行设置 public void setBg(ReadBookControl readBookControl) { ivBg.setImageResource(readBookControl.getTextBackground()); tvTitle.setTextColor(readBookControl.getTextColor()); @@ -252,8 +312,9 @@ public class BookContentView extends FrameLayout { tvErrorInfo.setTextColor(readBookControl.getTextColor()); } + // 设置文本相关样式,如文本大小、行间距等,根据传入的ReadBookControl对象中的配置进行设置 public void setTextKind(ReadBookControl readBookControl) { tvContent.setTextSize(readBookControl.getTextSize()); tvContent.setLineSpacing(readBookControl.getTextExtra(), 1); } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/widget/contentswitchview/ContentSwitchView.java b/app/src/main/java/com/monke/monkeybook/widget/contentswitchview/ContentSwitchView.java index d9b435f..9ab3b93 100644 --- a/app/src/main/java/com/monke/monkeybook/widget/contentswitchview/ContentSwitchView.java +++ b/app/src/main/java/com/monke/monkeybook/widget/contentswitchview/ContentSwitchView.java @@ -20,73 +20,97 @@ import com.monke.monkeybook.utils.DensityUtil; import java.util.ArrayList; import java.util.List; +// ContentSwitchView类继承自FrameLayout,并实现了BookContentView.SetDataListener接口 public class ContentSwitchView extends FrameLayout implements BookContentView.SetDataListener { + // 获取屏幕宽度 private final int screenWidth = DensityUtil.getWindowWidth(getContext()); + // 动画持续时间 private final long animDuration = 300; + // 表示没有上一页和下一页的状态常量 public final static int NONE = -1; + // 表示既有上一页又有下一页的状态常量 public final static int PREANDNEXT = 0; + // 表示只有上一页的状态常量 public final static int ONLYPRE = 1; + // 表示只有下一页的状态常量 public final static int ONLYNEXT = 2; - private int state = NONE; //0是有上一页 也有下一页 ; 2是只有下一页 ;1是只有上一页;-1是没有上一页 也没有下一页; - + // 当前视图的状态,初始化为NONE + private int state = NONE; + // 横向滚动的偏移量 private int scrollX; + // 表示是否正在移动的标志 private Boolean isMoving = false; + // 当前显示的页面视图 private BookContentView durPageView; + // 存储所有页面视图的列表 private List viewContents; + // 定义一个接口,用于在书籍阅读初始化成功时回调 public interface OnBookReadInitListener { public void success(); } + // 书籍阅读初始化监听器 private OnBookReadInitListener bookReadInitListener; + // 构造函数,用于在代码中创建视图时初始化 public ContentSwitchView(Context context) { super(context); init(); } + // 构造函数,用于在XML布局中创建视图时初始化,并接收属性集 public ContentSwitchView(Context context, AttributeSet attrs) { super(context, attrs); init(); } + // 构造函数,用于在XML布局中创建视图时初始化,并接收属性集和默认样式属性 public ContentSwitchView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } + // 构造函数,用于在XML布局中创建视图时初始化,并接收属性集、默认样式属性和特定版本的样式资源 @TargetApi(Build.VERSION_CODES.LOLLIPOP) public ContentSwitchView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); } + // 读取书籍控制实例 private ReadBookControl readBookControl; + // 初始化方法 private void init() { readBookControl = ReadBookControl.getInstance(); + // 将30dp转换为像素值,作为横向滚动的偏移量 scrollX = DensityUtil.dp2px(getContext(), 30f); + // 创建当前页面视图 durPageView = new BookContentView(getContext()); + // 设置当前页面视图的书籍控制实例 durPageView.setReadBookControl(readBookControl); viewContents = new ArrayList<>(); viewContents.add(durPageView); + // 将当前页面视图添加到布局中 addView(durPageView); } - + // 用于开始书籍阅读的初始化,并设置初始化监听器 public void bookReadInit(OnBookReadInitListener bookReadInitListener) { this.bookReadInitListener = bookReadInitListener; durPageView.getTvContent().getViewTreeObserver().addOnGlobalLayoutListener(layoutInitListener); } + // 开始加载数据 public void startLoading() { int height = durPageView.getTvContent().getHeight(); if (height > 0) { - if (loadDataListener != null && durHeight != height) { + if (loadDataListener!= null && durHeight!= height) { durHeight = height; loadDataListener.initData(durPageView.getLineCount(height)); } @@ -94,18 +118,22 @@ public class ContentSwitchView extends FrameLayout implements BookContentView.Se durPageView.getTvContent().getViewTreeObserver().addOnGlobalLayoutListener(layoutListener); } + // 测量视图的大小 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } + // 触摸事件的起始X坐标 private float startX = -1; + // 处理触摸事件 @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); if (!isMoving) { - int durWidth = screenWidth > 1400 ? 10 : 0; //当分辨率过大时,添加横向滑动冗余值 + // 当屏幕宽度大于1400时,设置横向滑动冗余值为10,否则为0 + int durWidth = screenWidth > 1400? 10 : 0; switch (action) { case MotionEvent.ACTION_DOWN: startX = event.getX(); @@ -115,7 +143,7 @@ public class ContentSwitchView extends FrameLayout implements BookContentView.Se if (startX == -1) startX = event.getX(); - //处理分辨率过大,移动冗余值,当横向滑动值超过冗余值则开始滑动 + // 处理分辨率过大时的横向滑动冗余值 int durX = (int) (event.getX() - startX); if(durX>durWidth){ durX = durX - durWidth; @@ -138,62 +166,62 @@ public class ContentSwitchView extends FrameLayout implements BookContentView.Se tempX = 0; else if (tempX < -getWidth()) tempX = -getWidth(); - int tempIndex = (state == PREANDNEXT ? 1 : 0); + int tempIndex = (state == PREANDNEXT? 1 : 0); viewContents.get(tempIndex).layout(tempX, viewContents.get(tempIndex).getTop(), tempX + getWidth(), viewContents.get(tempIndex).getBottom()); } } break; - case MotionEvent.ACTION_CANCEL: //小米8长按传送门会引导手势进入action_cancel + case MotionEvent.ACTION_CANCEL: // 小米8长按传送门会引导手势进入action_cancel case MotionEvent.ACTION_UP: if (startX == -1) startX = event.getX(); if (event.getX() - startX > durWidth) { if (state == PREANDNEXT || state == ONLYPRE) { - //注意冗余值 + // 注意冗余值,判断是否向前翻页成功 if (event.getX() - startX + durWidth> scrollX) { - //向前翻页成功 + // 向前翻页成功 initMoveSuccessAnim(viewContents.get(0), 0); } else { initMoveFailAnim(viewContents.get(0), -getWidth()); } } else { - //没有上一页 + // 没有上一页 noPre(); } } else if (event.getX() - startX < -durWidth) { if (state == PREANDNEXT || state == ONLYNEXT) { - int tempIndex = (state == PREANDNEXT ? 1 : 0); - //注意冗余值 + int tempIndex = (state == PREANDNEXT? 1 : 0); + // 注意冗余值,判断是否向后翻页成功 if (startX - event.getX() - durWidth > scrollX) { - //向后翻页成功 + // 向后翻页成功 initMoveSuccessAnim(viewContents.get(tempIndex), -getWidth()); } else { initMoveFailAnim(viewContents.get(tempIndex), 0); } } else { - //没有下一页 + // 没有下一页 noNext(); } } else { - //点击事件 + // 点击事件 if (readBookControl.getCanClickTurn() && event.getX() <= getWidth() / 3) { - //点击向前翻页 + // 点击向前翻页 if (state == PREANDNEXT || state == ONLYPRE) { initMoveSuccessAnim(viewContents.get(0), 0); } else { noPre(); } } else if (readBookControl.getCanClickTurn() && event.getX() >= getWidth() / 3 * 2) { - //点击向后翻页 + // 点击向后翻页 if (state == PREANDNEXT || state == ONLYNEXT) { - int tempIndex = (state == PREANDNEXT ? 1 : 0); + int tempIndex = (state == PREANDNEXT? 1 : 0); initMoveSuccessAnim(viewContents.get(tempIndex), -getWidth()); } else { noNext(); } } else { - //点击中间部位 - if (loadDataListener != null) + // 点击中间部位 + if (loadDataListener!= null) loadDataListener.showMenu(); } } @@ -206,6 +234,7 @@ public class ContentSwitchView extends FrameLayout implements BookContentView.Se return super.onTouchEvent(event); } + // 布局子视图 @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { if (viewContents.size() > 0) { @@ -227,14 +256,16 @@ public class ContentSwitchView extends FrameLayout implements BookContentView.Se } } + // 初始化翻页成功的动画 private void initMoveSuccessAnim(final View view, final int orderX) { - if (null != view) { + if (null!= view) { + // 根据视图的移动距离和屏幕宽度计算动画持续时间 long temp = Math.abs(view.getLeft() - orderX) / (getWidth() / animDuration); ValueAnimator tempAnim = ValueAnimator.ofInt(view.getLeft(), orderX).setDuration(temp); tempAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - if (null != view) { + if (null!= view) { int value = (int) animation.getAnimatedValue(); view.layout(value, view.getTop(), value + getWidth(), view.getBottom()); } @@ -250,9 +281,10 @@ public class ContentSwitchView extends FrameLayout implements BookContentView.Se public void onAnimationEnd(Animator animation) { isMoving = false; if (orderX == 0) { - //翻向前一页 + // 翻向前一页 durPageView = viewContents.get(0); if (state == PREANDNEXT) { + // 移除最后一页视图 ContentSwitchView.this.removeView(viewContents.get(viewContents.size() - 1)); viewContents.remove(viewContents.size() - 1); } @@ -264,11 +296,12 @@ public class ContentSwitchView extends FrameLayout implements BookContentView.Se else state = PREANDNEXT; } } else { - //翻向后一夜 + // 翻向后一页 if (state == ONLYNEXT) { durPageView = viewContents.get(1); } else { durPageView = viewContents.get(2); + // 移除第一页视图 ContentSwitchView.this.removeView(viewContents.get(0)); viewContents.remove(0); } @@ -280,7 +313,7 @@ public class ContentSwitchView extends FrameLayout implements BookContentView.Se else state = PREANDNEXT; } } - if (loadDataListener != null) + if (loadDataListener!= null) loadDataListener.updateProgress(durPageView.getDurChapterIndex(), durPageView.getDurPageIndex()); } @@ -298,14 +331,15 @@ public class ContentSwitchView extends FrameLayout implements BookContentView.Se } } + // 初始化翻页失败的动画 private void initMoveFailAnim(final View view, int orderX) { - if (null != view) { + if (null!= view) { long temp = Math.abs(view.getLeft() - orderX) / (getWidth() / animDuration); ValueAnimator tempAnim = ValueAnimator.ofInt(view.getLeft(), orderX).setDuration(temp); tempAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - if (null != view) { + if (null!= view) { int value = (int) animation.getAnimatedValue(); view.layout(value, view.getTop(), value + getWidth(), view.getBottom()); } @@ -315,27 +349,29 @@ public class ContentSwitchView extends FrameLayout implements BookContentView.Se } } + // 设置初始数据 public void setInitData(int durChapterIndex, int chapterAll, int durPageIndex) { updateOtherPage(durChapterIndex, chapterAll, durPageIndex, -1); durPageView.setLoadDataListener(loadDataListener, this); - durPageView.loadData(null != loadDataListener ? loadDataListener.getChapterTitle(durChapterIndex) : "", durChapterIndex, chapterAll, durPageIndex); + durPageView.loadData(null!= loadDataListener? loadDataListener.getChapterTitle(durChapterIndex) : "", durChapterIndex, chapterAll, durPageIndex); - if (loadDataListener != null) + if (loadDataListener!= null) loadDataListener.updateProgress(durPageView.getDurChapterIndex(), durPageView.getDurPageIndex()); } + // 根据当前页面的位置和总页数等信息更新其他页面的状态和视图 private void updateOtherPage(int durChapterIndex, int chapterAll, int durPageIndex, int pageAll) { if (chapterAll > 1 || pageAll > 1) { - if ((durChapterIndex == 0 && pageAll == -1) || (durChapterIndex == 0 && durPageIndex == 0 && pageAll != -1)) { - //ONLYNEXT + if ((durChapterIndex == 0 && pageAll == -1) || (durChapterIndex == 0 && durPageIndex == 0 && pageAll!= -1)) { + // ONLYNEXT,只有下一页的情况 addNextPage(durChapterIndex, chapterAll, durPageIndex, pageAll); if (state == ONLYPRE || state == PREANDNEXT) { this.removeView(viewContents.get(0)); viewContents.remove(0); } state = ONLYNEXT; - } else if ((durChapterIndex == chapterAll - 1 && pageAll == -1) || (durChapterIndex == chapterAll - 1 && durPageIndex == pageAll - 1 && pageAll != -1)) { - //ONLYPRE + } else if ((durChapterIndex == chapterAll - 1 && pageAll == -1) || (durChapterIndex == chapterAll - 1 && durPageIndex == pageAll - 1 && pageAll!= -1)) { + // ONLYPRE,只有上一页的情况 addPrePage(durChapterIndex, chapterAll, durPageIndex, pageAll); if (state == ONLYNEXT || state == PREANDNEXT) { this.removeView(viewContents.get(2)); @@ -343,13 +379,13 @@ public class ContentSwitchView extends FrameLayout implements BookContentView.Se } state = ONLYPRE; } else { - //PREANDNEXT + // PREANDNEXT,既有上一页又有下一页的情况 addNextPage(durChapterIndex, chapterAll, durPageIndex, pageAll); addPrePage(durChapterIndex, chapterAll, durPageIndex, pageAll); state = PREANDNEXT; } } else { - //NONE + // NONE,没有上一页和下一页的情况 if (state == ONLYPRE) { this.removeView(viewContents.get(0)); viewContents.remove(0); @@ -358,180 +394,4 @@ public class ContentSwitchView extends FrameLayout implements BookContentView.Se viewContents.remove(1); } else if (state == PREANDNEXT) { this.removeView(viewContents.get(0)); - this.removeView(viewContents.get(2)); - viewContents.remove(2); - viewContents.remove(0); - } - state = NONE; - } - } - - private void addNextPage(int durChapterIndex, int chapterAll, int durPageIndex, int pageAll) { - if (state == ONLYNEXT || state == PREANDNEXT) { - int temp = (state == ONLYNEXT ? 1 : 2); - if (pageAll > 0 && durPageIndex >= 0 && durPageIndex < pageAll - 1) - viewContents.get(temp).loadData(null != loadDataListener ? loadDataListener.getChapterTitle(durChapterIndex) : "", durChapterIndex, chapterAll, durPageIndex + 1); - else - viewContents.get(temp).loadData(null != loadDataListener ? loadDataListener.getChapterTitle(durChapterIndex + 1) : "", durChapterIndex + 1, chapterAll, BookContentView.DURPAGEINDEXBEGIN); - } else if (state == ONLYPRE || state == NONE) { - BookContentView next = new BookContentView(getContext()); - next.setReadBookControl(readBookControl); - next.setLoadDataListener(loadDataListener, this); - if (pageAll > 0 && durPageIndex >= 0 && durPageIndex < pageAll - 1) - next.loadData(null != loadDataListener ? loadDataListener.getChapterTitle(durChapterIndex) : "", durChapterIndex, chapterAll, durPageIndex + 1); - else - next.loadData(null != loadDataListener ? loadDataListener.getChapterTitle(durChapterIndex + 1) : "", durChapterIndex + 1, chapterAll, BookContentView.DURPAGEINDEXBEGIN); - viewContents.add(next); - this.addView(next, 0); - } - } - - private void addPrePage(int durChapterIndex, int chapterAll, int durPageIndex, int pageAll) { - if (state == ONLYNEXT || state == NONE) { - BookContentView pre = new BookContentView(getContext()); - pre.setReadBookControl(readBookControl); - pre.setLoadDataListener(loadDataListener, this); - if (pageAll > 0 && durPageIndex >= 0 && durPageIndex > 0) - pre.loadData(null != loadDataListener ? loadDataListener.getChapterTitle(durChapterIndex) : "", durChapterIndex, chapterAll, durPageIndex - 1); - else - pre.loadData(null != loadDataListener ? loadDataListener.getChapterTitle(durChapterIndex - 1) : "", durChapterIndex - 1, chapterAll, BookContentView.DURPAGEINDEXEND); - viewContents.add(0, pre); - this.addView(pre); - } else if (state == ONLYPRE || state == PREANDNEXT) { - if (pageAll > 0 && durPageIndex >= 0 && durPageIndex > 0) - viewContents.get(0).loadData(null != loadDataListener ? loadDataListener.getChapterTitle(durChapterIndex) : "", durChapterIndex, chapterAll, durPageIndex - 1); - else - viewContents.get(0).loadData(null != loadDataListener ? loadDataListener.getChapterTitle(durChapterIndex - 1) : "", durChapterIndex - 1, chapterAll, BookContentView.DURPAGEINDEXEND); - } - } - - - @Override - public void setDataFinish(BookContentView bookContentView, int durChapterIndex, int chapterAll, int durPageIndex, int pageAll, int fromPageIndex) { - if (null != getDurContentView() && bookContentView == getDurContentView() && chapterAll > 0 && pageAll > 0) { - updateOtherPage(durChapterIndex, chapterAll, durPageIndex, pageAll); - } - } - - public interface LoadDataListener { - public void loaddata(BookContentView bookContentView, long tag, int chapterIndex, int pageIndex); - - public void updateProgress(int chapterIndex, int pageIndex); - - public String getChapterTitle(int chapterIndex); - - public void initData(int lineCount); - - public void showMenu(); - } - - private LoadDataListener loadDataListener; - - public LoadDataListener getLoadDataListener() { - return loadDataListener; - } - - public void setLoadDataListener(LoadDataListener loadDataListener) { - this.loadDataListener = loadDataListener; - } - - public BookContentView getDurContentView() { - return durPageView; - } - - private void noPre() { - Toast.makeText(getContext(), "没有上一页", Toast.LENGTH_SHORT).show(); - } - - private void noNext() { - Toast.makeText(getContext(), "没有下一页", Toast.LENGTH_SHORT).show(); - } - - private ViewTreeObserver.OnGlobalLayoutListener layoutInitListener = new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - if (bookReadInitListener != null) { - bookReadInitListener.success(); - } - durPageView.getTvContent().getViewTreeObserver().removeOnGlobalLayoutListener(layoutInitListener); - } - }; - private ViewTreeObserver.OnGlobalLayoutListener layoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - int height = durPageView.getTvContent().getHeight(); - if (height > 0) { - if (loadDataListener != null && durHeight != height) { - durHeight = height; - loadDataListener.initData(durPageView.getLineCount(height)); - } - } - } - }; - - private int durHeight = 0; - - public Paint getTextPaint() { - return durPageView.getTvContent().getPaint(); - } - - public int getContentWidth() { - return durPageView.getTvContent().getWidth(); - } - - public void changeBg() { - for (BookContentView item : viewContents) { - item.setBg(readBookControl); - } - } - - public void changeTextSize() { - for (BookContentView item : viewContents) { - item.setTextKind(readBookControl); - } - loadDataListener.initData(durPageView.getLineCount(durHeight)); - } - - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (readBookControl.getCanKeyTurn() && keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { - if (state == PREANDNEXT || state == ONLYNEXT) { - int tempIndex = (state == PREANDNEXT ? 1 : 0); - initMoveSuccessAnim(viewContents.get(tempIndex), -getWidth()); - } else { - noNext(); - } - return true; - } else if (readBookControl.getCanKeyTurn() && keyCode == KeyEvent.KEYCODE_VOLUME_UP) { - if (state == PREANDNEXT || state == ONLYPRE) { - initMoveSuccessAnim(viewContents.get(0), 0); - } else { - noPre(); - } - return true; - } - return false; - } - - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (readBookControl.getCanKeyTurn() && keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { - return true; - } else if (readBookControl.getCanKeyTurn() && keyCode == KeyEvent.KEYCODE_VOLUME_UP) { - return true; - } - return false; - } - - public OnBookReadInitListener getBookReadInitListener() { - return bookReadInitListener; - } - - public void setBookReadInitListener(OnBookReadInitListener bookReadInitListener) { - this.bookReadInitListener = bookReadInitListener; - } - - public void loadError() { - if (durPageView != null) { - durPageView.loadError(); - } - } -} \ No newline at end of file + this.removeView(viewContents.get(2)); \ No newline at end of file