张冉
zhangran 1 year ago
parent 1c7a09a015
commit b49af947dd

@ -4,15 +4,34 @@ package com.monke.monkeybook;
import java.util.HashMap;
import java.util.Map;
/**
* BitIntentDataManagerIntent
* 便ActivityFragment
*/
public class BitIntentDataManager {
public static Map<String,Object> bigData;
/**
* 使bigDataMapStringObject
* 便
*/
public static Map<String, Object> bigData;
/**
* instanceBitIntentDataManagernull
*/
private static BitIntentDataManager instance = null;
public static BitIntentDataManager getInstance(){
if(instance == null){
synchronized (BitIntentDataManager.class){
if(instance == null){
/**
* BitIntentDataManager
* instancenull使synchronized线线
* instancenullnullBitIntentDataManagerinstance
* 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(){
/**
* BitIntentDataManagerbigDataMap
* 使getInstance
*/
private BitIntentDataManager() {
bigData = new HashMap<>();
}
public Object getData(String key){
/**
* keybigDataMapObject
* null
* @param key 使便
* @return bigDataObjectnull
*/
public Object getData(String key) {
return bigData.get(key);
}
public void putData(String key,Object data){
bigData.put(key,data);
/**
* keyObjectbigDataMap便
*
* @param key 便
* @param data Object
*/
public void putData(String key, Object data) {
bigData.put(key, data);
}
public void cleanData(String key){
/**
* keybigDataMap
*
* @param key 使便
*/
public void cleanData(String key) {
bigData.remove(key);
}
}
}

@ -12,16 +12,36 @@ import io.reactivex.ObservableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
/**
* ErrorAnalyContentManagerURL
* 便
*/
public class ErrorAnalyContentManager {
private ErrorAnalyContentManager(){
/**
*
* 使 `getInstance`
*/
private ErrorAnalyContentManager() {
}
/**
* ErrorAnalyContentManagernull
*/
private static ErrorAnalyContentManager instance;
public static ErrorAnalyContentManager getInstance(){
if(instance == null){
synchronized (ErrorAnalyContentManager.class){
if(instance == null){
/**
* ErrorAnalyContentManager
* `instance` null使 `synchronized` 线线
* `instance` nullnullErrorAnalyContentManager `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){
/**
* URLURL
* RxJava `Observable` 线线线
* @param url URL
*/
public void writeNewErrorUrl(final String url) {
// 创建一个Observable对象用于定义一个异步可观察的操作序列这里传入一个实现了ObservableOnSubscribe接口的匿名内部类用于定义具体的操作逻辑即文件写入等操作
Observable.create(new ObservableOnSubscribe<Boolean>() {
@Override
public void subscribe(ObservableEmitter<Boolean> 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<Boolean>() {
@Override
public void onNext(Boolean value) {
// 当上游的Observable发送数据这里是发送了布尔值为true的数据会调用这个方法当前方法体为空可以根据业务需求在这里添加相应的逻辑比如进行一些简单的日志记录等操作表示文件写入操作的某一步骤成功完成了
}
@Override
public void onError(Throwable e) {
// 当在异步操作过程中出现错误(比如文件读写出现异常等情况)时,会调用这个方法,当前方法体为空,可以在这里添加相应的错误处理逻辑,比如记录错误日志、提示用户等操作
}
});
}
public void writeMayByNetError(final String url){
/**
* URLRxJavaURL "ErrorNetUrl.txt" 便
* @param url URL
*/
public void writeMayByNetError(final String url) {
Observable.create(new ObservableOnSubscribe<Boolean>() {
@Override
public void subscribe(ObservableEmitter<Boolean> 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<Boolean>() {
@Override
public void onNext(Boolean value) {
// 当上游的Observable发送数据这里是发送了布尔值为true的数据会调用这个方法当前方法体为空可以根据业务需求在这里添加相应的逻辑比如进行一些简单的日志记录等操作表示文件写入操作的某一步骤成功完成了
}
@Override
public void onError(Throwable e) {
// 当在异步操作过程中出现错误(比如文件读写出现异常等情况)时,会调用这个方法,当前方法体为空,可以在这里添加相应的错误处理逻辑,比如记录错误日志、提示用户等操作
}
});
}
}
}

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

@ -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\\-\\.,@?^=%&amp;:/~\\+#]*[\\w\\-\\@?^=%&amp;/~\\+#])?";//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\\-\\.,@?^=%&amp;:/~\\+#]*[\\w\\-\\@?^=%&amp;/~\\+#])?";
// 定义一个常量字符串,用于表示代理包名加密的密钥,具体加密相关功能可能在其他地方实现,
// 这里只是定义了这个密钥的常量表示,用于相关的加密操作或者与加密相关逻辑的标识。
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;
}
}
}
}

@ -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<Map<String,Integer>> textKind;
private static List<Map<String,Integer>> textDrawable;
// 用于存储不同文字样式相关配置信息的列表每个元素是一个Map其中包含如文字大小、文字间距等具体配置项方便根据不同索引获取对应的文字样式配置。
private static List<Map<String, Integer>> textKind;
// 用于存储不同文字绘制相关配置信息的列表主要涉及文字颜色和文字背景相关设置每个元素是一个Map方便根据不同索引获取对应的文字绘制相关配置。
private static List<Map<String, Integer>> 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
* readBookControlnull使synchronized线线
* readBookControlnullnullReadBookControlreadBookControl
* 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){
/**
* ReadBookControlSharedPreferences
* getInstance
*/
private ReadBookControl() {
// 如果textKind列表为空即还未初始化则进行初始化操作创建不同文字样式相关的配置信息并添加到textKind列表中。
if (null == textKind) {
textKind = new ArrayList<>();
Map<String,Integer> temp1 = new HashMap<>();
// 创建一个临时的Map用于存储一种文字样式的配置信息这里设置文字大小为14单位可能是像素等具体看后续使用情况文字间距通过DensityUtil工具类将dp值转换为像素值6.5dp转换后的像素值然后将这个配置信息添加到textKind列表中。
Map<String, Integer> 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<String,Integer> temp2 = new HashMap<>();
// 类似地创建另一种文字样式的配置信息文字大小设置为16文字间距通过DensityUtil转换对应dp值后的像素值再添加到textKind列表中方便后续根据索引选择不同的文字大小和间距配置。
Map<String, Integer> 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<String,Integer> temp3 = new HashMap<>();
Map<String, Integer> 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<String,Integer> temp4 = new HashMap<>();
Map<String, Integer> 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<String,Integer> temp5 = new HashMap<>();
Map<String, Integer> 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<String,Integer> 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<String, Integer> temp1 = new HashMap<>();
temp1.put("textColor", Color.parseColor("#3E3D3B"));
temp1.put("textBackground", R.drawable.shape_bg_readbook_white);
textDrawable.add(temp1);
Map<String,Integer> temp2 = new HashMap<>();
temp2.put("textColor",Color.parseColor("#5E432E"));
temp2.put("textBackground",R.drawable.bg_readbook_yellow);
Map<String, Integer> temp2 = new HashMap<>();
temp2.put("textColor", Color.parseColor("#5E432E"));
temp2.put("textBackground", R.drawable.bg_readbook_yellow);
textDrawable.add(temp2);
Map<String,Integer> temp3 = new HashMap<>();
temp3.put("textColor",Color.parseColor("#22482C"));
temp3.put("textBackground",R.drawable.bg_readbook_green);
Map<String, Integer> temp3 = new HashMap<>();
temp3.put("textColor", Color.parseColor("#22482C"));
temp3.put("textBackground", R.drawable.bg_readbook_green);
textDrawable.add(temp3);
Map<String,Integer> temp4 = new HashMap<>();
temp4.put("textColor",Color.parseColor("#808080"));
temp4.put("textBackground",R.drawable.bg_readbook_black);
Map<String, Integer> 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 AndroidARGB
*/
public int getTextColor() {
return textColor;
}
/**
*
* @return R.drawableID
*/
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<Map<String, Integer>> getTextKind() {
return textKind;
}
/**
*
* 便
* @return Map
*/
public static List<Map<String, Integer>> getTextDrawable() {
return textDrawable;
}
/**
*
* @return truefalse
*/
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();
}
}
/**
* SharedPreferences
*
Loading…
Cancel
Save