[Modify]修改图片选择的逻辑
This commit is contained in:
@@ -60,7 +60,7 @@ android {
|
||||
|
||||
dependencies {
|
||||
|
||||
def glideVersion = "4.13.1"
|
||||
def glideVersion = "4.13.2"
|
||||
def retrofitVersion = "2.9.0"
|
||||
def okhttp3 = "4.9.3"
|
||||
def okio = "2.8.0"
|
||||
@@ -73,6 +73,7 @@ dependencies {
|
||||
def SmartRefreshLayoutVersion = "1.0.3"
|
||||
def eventbusVersion = "3.0.0"
|
||||
def fragment_version = "1.3.6"
|
||||
def GlideTransformationsVersion = "3.0.1"
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
@@ -124,6 +125,11 @@ dependencies {
|
||||
api 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
|
||||
api 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||
|
||||
//mmkv
|
||||
api 'com.tencent:mmkv:1.2.13'
|
||||
|
||||
api "jp.wasabeef:glide-transformations:${GlideTransformationsVersion}"
|
||||
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
@@ -0,0 +1,38 @@
|
||||
package com.yizhuan.xchat_android_library.common.application;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* Application的代理类
|
||||
*/
|
||||
public abstract class BaseApp extends Application{
|
||||
private static final String TAG = "BaseApp";
|
||||
public static Application gContext;
|
||||
|
||||
/**
|
||||
* @return 获取Application上下文对象
|
||||
*/
|
||||
public static Context getContext() {
|
||||
return gContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获取Application实例
|
||||
*/
|
||||
public static Application getApplication() {
|
||||
return gContext;
|
||||
}
|
||||
|
||||
public static void init(Application application) {
|
||||
gContext = application;
|
||||
}
|
||||
|
||||
/**
|
||||
* debug 环境 受到实验室模式影响
|
||||
*/
|
||||
public static boolean isDebug() {
|
||||
return Env.isDebug();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,146 @@
|
||||
package com.yizhuan.xchat_android_library.common.application;
|
||||
|
||||
import com.yizhuan.xchat_android_library.R;
|
||||
import com.yizhuan.xchat_android_library.utils.ResUtil;
|
||||
import com.yizhuan.xchat_android_library.utils.config.BasicConfig;
|
||||
import com.yizhuan.xchat_android_library.utils.pref.CommonPref;
|
||||
|
||||
/**
|
||||
* 环境配置类
|
||||
*/
|
||||
public class Env {
|
||||
|
||||
public static final String KEY_ENVIRONMENT = "environment";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 当前环境
|
||||
*/
|
||||
private static EnvType mEnvType;
|
||||
/**
|
||||
* 真实环境
|
||||
*/
|
||||
private static boolean mRealDebug;
|
||||
|
||||
|
||||
private Env() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public enum EnvType {
|
||||
/**
|
||||
* 测试环境
|
||||
*/
|
||||
Debug(0),
|
||||
/**
|
||||
* 待发布环境
|
||||
*/
|
||||
Staging(1),
|
||||
/**
|
||||
* 线上环境
|
||||
*/
|
||||
Release(2);
|
||||
|
||||
public int code;
|
||||
|
||||
EnvType(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
|
||||
public static EnvType create(int code) {
|
||||
EnvType env = null;
|
||||
if (code == EnvType.Debug.code) {
|
||||
env = Debug;
|
||||
} else if (code == EnvType.Staging.code) {
|
||||
env = Staging;
|
||||
} else if (code == EnvType.Release.code) {
|
||||
env = Release;
|
||||
}
|
||||
return env;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化环境参数
|
||||
*
|
||||
* @param defaultEnv 用于初始化最初环境
|
||||
* @param isRealDebug 判断是否是真的debug模式,不受环境影响
|
||||
*/
|
||||
public static void initEnv(String defaultEnv, boolean isRealDebug) {
|
||||
if (defaultEnv == null || defaultEnv.isEmpty()) {
|
||||
throw new RuntimeException(ResUtil.getString(R.string.yizhuan_xchat_android_core_env_01));
|
||||
}
|
||||
int environment = CommonPref.instance(BasicConfig.INSTANCE.getAppContext()).getInt(KEY_ENVIRONMENT);
|
||||
EnvType envType;
|
||||
if (environment == -1) {
|
||||
envType = EnvType.valueOf(firstChar2Up(defaultEnv));
|
||||
changeEnv(envType);
|
||||
} else {
|
||||
envType = EnvType.create(environment);
|
||||
}
|
||||
if (envType == null) {
|
||||
throw new RuntimeException(ResUtil.getString(R.string.yizhuan_xchat_android_core_env_02));
|
||||
}
|
||||
|
||||
mEnvType = envType;
|
||||
mRealDebug = isRealDebug;
|
||||
}
|
||||
|
||||
/**
|
||||
* 第一个字符大写,用于把字符串转成类名
|
||||
*
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
private static String firstChar2Up(String s) {
|
||||
if (s == null || s.length() < 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String newStr = s.substring(0, 1).toUpperCase() + s.substring(1);
|
||||
|
||||
return newStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改偏好设置里面的值
|
||||
*
|
||||
* @param env
|
||||
*/
|
||||
public static void changeEnv(EnvType env) {
|
||||
CommonPref.instance(BasicConfig.INSTANCE.getAppContext()).putInt(KEY_ENVIRONMENT, env.code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 受到环境印象(和实验室有关)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static boolean isDebug() {
|
||||
return mEnvType == EnvType.Debug && mRealDebug;
|
||||
}
|
||||
|
||||
/**
|
||||
* 真实包环境(不受实验室环境影响)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static boolean isRealDebug() {
|
||||
return mRealDebug;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前环境
|
||||
* @return
|
||||
*/
|
||||
public static EnvType getCurrentEnv() {
|
||||
if (mEnvType == null) {
|
||||
throw new RuntimeException(ResUtil.getString(R.string.yizhuan_xchat_android_core_env_03));
|
||||
}
|
||||
return mEnvType;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
package com.yizhuan.xchat_android_library.common.application;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
|
||||
public interface IAppLifeCycle {
|
||||
|
||||
void init(Application application);
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,50 @@
|
||||
package com.yizhuan.xchat_android_library.common.delegate
|
||||
|
||||
import com.yizhuan.xchat_android_library.common.application.BaseApp
|
||||
import com.yizhuan.xchat_android_library.common.util.SPUtils
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* author: wushaocheng
|
||||
* time: 2022/11/15
|
||||
* desc: sp存储和取出委托
|
||||
*/
|
||||
class SpDelegate<T>(private val key: String, private val default: T) : ReadWriteProperty<Any?, T> {
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||
val value = when (default) {
|
||||
is Boolean -> SPUtils.getBoolean(key, default)
|
||||
is String -> SPUtils.getString(key, default)
|
||||
is Long -> SPUtils.getLong(key, default)
|
||||
is Int -> SPUtils.getInt(key, default)
|
||||
is Float -> SPUtils.getFloat(key, default)
|
||||
is Double -> SPUtils.getDouble(key, default)
|
||||
is ByteArray -> SPUtils.getBytes(key, default)
|
||||
else -> {
|
||||
if (BaseApp.isDebug()) {
|
||||
throw IllegalArgumentException("SpDelegate: this type is no supported")
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
return (value as? T) ?: default
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||
when (value) {
|
||||
is Boolean -> SPUtils.putBoolean(key, value)
|
||||
is String -> SPUtils.putString(key, value)
|
||||
is Long -> SPUtils.putLong(key, value)
|
||||
is Int -> SPUtils.putInt(key, value)
|
||||
is Float -> SPUtils.putFloat(key, value)
|
||||
is Double -> SPUtils.putDouble(key, value)
|
||||
is ByteArray -> SPUtils.putBytes(key, value)
|
||||
else -> {
|
||||
if (BaseApp.isDebug()) {
|
||||
throw IllegalArgumentException("SpDelegate: this type is no supported")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,917 @@
|
||||
package com.yizhuan.xchat_android_library.common.file;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.qiniu.android.utils.StringUtils;
|
||||
import com.yizhuan.xchat_android_library.common.application.BaseApp;
|
||||
import com.yizhuan.xchat_android_library.common.util.Logger;
|
||||
import com.yizhuan.xchat_android_library.utils.FP;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
* 文件工具类
|
||||
*/
|
||||
public class FileHelper {
|
||||
private static final String TAG = "FileHelper";
|
||||
private static final String NO_MEDIA = ".nomedia";
|
||||
private static File rootCacheDir;
|
||||
private static HashMap<String, File> rootFileDirMap = new HashMap<>();
|
||||
private static final String[] mCs = new String[]{"/", "\\", "?", "*", ":", "<", ">", "|", "\""};
|
||||
private static final char UNICODE_SURROGATE_START_CHAR = '\ud800';
|
||||
private static final char UNICODE_SURROGATE_END_CHAR = '\udfff';
|
||||
|
||||
/**
|
||||
* 创建.nomedia文件
|
||||
*
|
||||
* @param parentFile 上级目录
|
||||
*/
|
||||
private static void createNoMediaFile(File parentFile) {
|
||||
File no_media = new File(parentFile, NO_MEDIA);
|
||||
if (!no_media.exists()) {
|
||||
try {
|
||||
no_media.createNewFile();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Android/data/当前应用包名/cache文件夹
|
||||
*
|
||||
* @return 当前应用缓存根目录
|
||||
*/
|
||||
public static File getRootCacheDir() {
|
||||
if (rootCacheDir != null) {
|
||||
//因为频繁调用getExternalCacheDir方法会在某些机器上面出现ANR,所以这里降低频率调用。
|
||||
return rootCacheDir;
|
||||
}
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
File file = BaseApp.getContext().getExternalCacheDir();
|
||||
if (file != null) {
|
||||
createNoMediaFile(file);
|
||||
//因为频繁调用getExternalCacheDir方法会在某些机器上面出现ANR,所以这里降低频率调用。
|
||||
rootCacheDir = file;
|
||||
return file;
|
||||
}
|
||||
}
|
||||
File file = BaseApp.getContext().getCacheDir();
|
||||
createNoMediaFile(file);
|
||||
//因为频繁调用getExternalCacheDir方法会在某些机器上面出现ANR,所以这里降低频率调用。
|
||||
rootCacheDir = file;
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Android/data/当前应用包名/files文件夹
|
||||
*
|
||||
* @param type 类型从以下方式中选择,也可以为null:
|
||||
* {@link Environment#DIRECTORY_MUSIC},
|
||||
* {@link Environment#DIRECTORY_PODCASTS},
|
||||
* {@link Environment#DIRECTORY_RINGTONES},
|
||||
* {@link Environment#DIRECTORY_ALARMS},
|
||||
* {@link Environment#DIRECTORY_NOTIFICATIONS},
|
||||
* {@link Environment#DIRECTORY_PICTURES},
|
||||
* {@link Environment#DIRECTORY_MOVIES},
|
||||
* {@link Environment#DIRECTORY_DOWNLOADS},
|
||||
* {@link Environment#DIRECTORY_DCIM},
|
||||
* {@link Environment#DIRECTORY_DOCUMENTS},
|
||||
* {@link Environment#DIRECTORY_AUDIOBOOKS}
|
||||
* @return 当前应用文件根目录
|
||||
*/
|
||||
public static File getRootFilesDir(@androidx.annotation.Nullable String type) {
|
||||
String dirName = (type != null && type.length() > 0) ? type.trim() : null;
|
||||
if (TextUtils.isEmpty(dirName)) {
|
||||
//因为频繁调用getExternalFilesDir方法会在某些机器上面出现ANR,所以这里降低频率调用。
|
||||
File file = rootFileDirMap.get("empty");
|
||||
if (file != null) {
|
||||
return file;
|
||||
}
|
||||
} else {
|
||||
//因为频繁调用getExternalFilesDir方法会在某些机器上面出现ANR,所以这里降低频率调用。
|
||||
File file = rootFileDirMap.get(dirName);
|
||||
if (file != null) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
File file = BaseApp.getContext().getExternalFilesDir(dirName);
|
||||
if (file != null) {
|
||||
createNoMediaFile(file);
|
||||
//因为频繁调用getExternalFilesDir方法会在某些机器上面出现ANR,所以这里降低频率调用。
|
||||
if (TextUtils.isEmpty(dirName)) {
|
||||
rootFileDirMap.put("empty", file);
|
||||
} else {
|
||||
rootFileDirMap.put(dirName, file);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
}
|
||||
File file = BaseApp.getContext().getFilesDir();
|
||||
createNoMediaFile(file);
|
||||
//因为频繁调用getExternalFilesDir方法会在某些机器上面出现ANR,所以这里降低频率调用。
|
||||
rootFileDirMap.put("empty", file);
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建临时文件
|
||||
*
|
||||
* @param dir 文件夹
|
||||
* @return 临时文件
|
||||
*/
|
||||
public static File createTempFile(File dir) {
|
||||
try {
|
||||
File file = File.createTempFile("pic", null, dir);
|
||||
file.deleteOnExit();
|
||||
return file;
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件或文件夹是否存在
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 是否存在这个文件或文件夹
|
||||
*/
|
||||
public static boolean isFileExist(String filePath) {
|
||||
if (TextUtils.isEmpty(filePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File file = new File(filePath);
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保文件夹存在,不存在的时候就创建该目录
|
||||
*
|
||||
* @param dirPath 文件夹路径
|
||||
* @return 确保是否已存在这个文件夹
|
||||
*/
|
||||
public static boolean ensureDirExists(String dirPath) {
|
||||
File dirFile = new File(dirPath);
|
||||
if (!dirFile.exists()) {
|
||||
return dirFile.mkdirs();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保该文件的文件夹存在,不存在的时候就创建该文件的文件夹
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 确保是否已存在该文件的文件夹
|
||||
*/
|
||||
public static boolean ensureFileDirExists(String filePath) {
|
||||
String dir = getDirOfFilePath(filePath);
|
||||
if (TextUtils.isEmpty(dir)) {
|
||||
return false;
|
||||
}
|
||||
ensureDirExists(dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保该文件存在,不存在的时候就创建该文件
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 确保是否已存在该文件
|
||||
*/
|
||||
public static File ensureFileExists(String filePath) {
|
||||
if (!ensureFileDirExists(filePath)) {
|
||||
return null;
|
||||
}
|
||||
File file = new File(filePath);
|
||||
if (file.exists()) {
|
||||
return file;
|
||||
}
|
||||
try {
|
||||
if (!file.exists() && !file.createNewFile()) {
|
||||
file = null;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
file = null;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从文件路径里提取文件夹的路径
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 文件夹的路径
|
||||
*/
|
||||
public static String getDirOfFilePath(String filePath) {
|
||||
if (TextUtils.isEmpty(filePath)) {
|
||||
return null;
|
||||
}
|
||||
int sepPos = filePath.lastIndexOf(File.separatorChar);
|
||||
if (sepPos == -1) {
|
||||
return null;
|
||||
}
|
||||
return filePath.substring(0, sepPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除单个文件
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
*/
|
||||
public static void removeFile(String filePath) {
|
||||
if (!TextUtils.isEmpty(filePath)) {
|
||||
try {
|
||||
File file = new File(filePath);
|
||||
file.delete();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件或文件夹下面所有的文件
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
public static boolean removeAllFile(String filePath) {
|
||||
if (TextUtils.isEmpty(filePath)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
File file = new File(filePath);
|
||||
if (!file.exists()) {
|
||||
return true;
|
||||
}
|
||||
if (file.isFile()) {
|
||||
try {
|
||||
return file.delete();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!file.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
File[] files = file.listFiles();
|
||||
if (files != null && files.length > 0) {
|
||||
for (File f : files) {
|
||||
if (f.isFile()) {
|
||||
try {
|
||||
f.delete();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else if (f.isDirectory()) {
|
||||
removeAllFile(f.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
return file.delete();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据存储到缓存文件夹里
|
||||
*
|
||||
* @param data 数据
|
||||
* @param filePath 文件路径
|
||||
*/
|
||||
public static void saveByteArrayIntoFile(byte[] data, String filePath) {
|
||||
try {
|
||||
File f = new File(filePath);
|
||||
if (f.createNewFile()) {
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
fos.write(data);
|
||||
fos.flush();
|
||||
fos.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Bitmap保存为JPEG图片
|
||||
*/
|
||||
public static void saveBitmapAsJPEG(Bitmap bmp, String filePath) {
|
||||
if (bmp == null) {
|
||||
return;
|
||||
}
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
if (!ensureFileDirExists(filePath)) {
|
||||
return;
|
||||
}
|
||||
File file = new File(filePath);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
fos = new FileOutputStream(file);
|
||||
bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);
|
||||
fos.flush();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (fos != null) {
|
||||
fos.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Bitmap保存为PNG图片
|
||||
*
|
||||
* @param bmp 图片
|
||||
* @param filePath 文件路径
|
||||
* @return 文件路径
|
||||
*/
|
||||
public static String saveBitmapAsPNG(Bitmap bmp, String filePath) {
|
||||
if (bmp == null) {
|
||||
return "";
|
||||
}
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
if (!ensureFileDirExists(filePath)) {
|
||||
return "";
|
||||
}
|
||||
File file = new File(filePath);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
fos = new FileOutputStream(file);
|
||||
bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||
fos.flush();
|
||||
return filePath;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (fos != null) {
|
||||
fos.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 解压zip到指定的路径
|
||||
*
|
||||
* @param zipFileString ZIP的名称
|
||||
* @param outPathString 要解压缩路径
|
||||
*/
|
||||
public static boolean unzipFile(String zipFileString, String outPathString) {
|
||||
ZipInputStream inZip = null;
|
||||
try {
|
||||
inZip = new ZipInputStream(new FileInputStream(zipFileString));
|
||||
ZipEntry zipEntry;
|
||||
while ((zipEntry = inZip.getNextEntry()) != null) {
|
||||
String szName = zipEntry.getName();
|
||||
if (szName.contains("/")) {
|
||||
szName = szName.substring(szName.indexOf("/") + 1);
|
||||
if (TextUtils.isEmpty(szName)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!zipEntry.isDirectory()) {
|
||||
File file = new File(outPathString + File.separator + szName);
|
||||
if (!file.exists()) {
|
||||
if (file.getParentFile() != null) {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
file.createNewFile();
|
||||
}
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
int len;
|
||||
byte[] buffer = new byte[1024];
|
||||
while ((len = inZip.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, len);
|
||||
out.flush();
|
||||
}
|
||||
out.close();
|
||||
} else {
|
||||
szName = szName.substring(0, szName.length() - 1);
|
||||
File folder = new File(outPathString + File.separator + szName);
|
||||
folder.mkdirs();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
try {
|
||||
if (inZip != null) {
|
||||
inZip.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解压压缩包
|
||||
*
|
||||
* @param srcZipPath 原压缩包路径
|
||||
* @param destFilePath 目标文件夹路径
|
||||
* @return 解压之后的文件组
|
||||
* @throws IOException 抛出异常
|
||||
*/
|
||||
public static File[] unzip(String srcZipPath, String destFilePath) throws IOException {
|
||||
if (TextUtils.isEmpty(destFilePath)) {
|
||||
throw new IOException();
|
||||
}
|
||||
if (!destFilePath.endsWith(File.separator)) {
|
||||
destFilePath = destFilePath + File.separator;
|
||||
}
|
||||
File destDir = new File(destFilePath);
|
||||
if (!destDir.isDirectory() || !destDir.exists()) {
|
||||
destDir.mkdir();
|
||||
}
|
||||
ArrayList<File> extractedFileList = new ArrayList<>();
|
||||
ZipInputStream inZip = null;
|
||||
try {
|
||||
ZipEntry zipEntry;
|
||||
inZip = new ZipInputStream(new FileInputStream(srcZipPath));
|
||||
String szName;
|
||||
while ((zipEntry = inZip.getNextEntry()) != null) {
|
||||
szName = zipEntry.getName();
|
||||
if (zipEntry.isDirectory()) {
|
||||
szName = szName.substring(0, szName.length() - 1);
|
||||
File folder = new File(destDir.getAbsolutePath() + File.separator + szName);
|
||||
folder.mkdirs();
|
||||
continue;
|
||||
}
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
int len;
|
||||
File file = new File(destDir.getAbsolutePath() + File.separator + szName);
|
||||
file = ensureFileExists(file.getAbsolutePath());
|
||||
if (file != null) {
|
||||
out = new FileOutputStream(file);
|
||||
byte[] buffer = new byte[1024];
|
||||
while ((len = inZip.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, len);
|
||||
out.flush();
|
||||
}
|
||||
out.close();
|
||||
extractedFileList.add(file);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (inZip != null) {
|
||||
inZip.close();
|
||||
}
|
||||
}
|
||||
File[] extractedFiles = new File[extractedFileList.size()];
|
||||
extractedFileList.toArray(extractedFiles);
|
||||
return extractedFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从文件路径里面提取文件的后缀
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 后缀,如.mp3
|
||||
*/
|
||||
public static String getFileExtension(String filePath) {
|
||||
String fileName = getFileName(filePath);
|
||||
if (TextUtils.isEmpty(fileName)) {
|
||||
return null;
|
||||
}
|
||||
int index = fileName.lastIndexOf(".");
|
||||
if (index != -1) {
|
||||
return fileName.substring(index);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从文件路径里面提取文件名
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 文件名称
|
||||
*/
|
||||
public static String getFileName(String filePath) {
|
||||
if (filePath != null) {
|
||||
String slash = "/";
|
||||
int pos = filePath.lastIndexOf(slash) + 1;
|
||||
if (pos > 0) {
|
||||
String name = filePath.substring(pos);
|
||||
if (!TextUtils.isEmpty(name)) {
|
||||
name = name.replace("?", "");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从URL里面提取版本名
|
||||
*
|
||||
* @param url 链接
|
||||
* @return 文件名
|
||||
*/
|
||||
public static String getFileNameWithVer(String url) {
|
||||
String versionName = "";
|
||||
String subName = getFileName(url);
|
||||
if (subName != null && subName.contains("?")) {
|
||||
String[] tempArr = subName.split("\\?");
|
||||
if (tempArr.length > 1) {
|
||||
subName = tempArr[0];
|
||||
versionName = tempArr[1];
|
||||
}
|
||||
}
|
||||
|
||||
String fileName = dropExt(subName);
|
||||
fileName = fileName + versionName;
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从文件名里面踢出点得到可用的文件名
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 文件名
|
||||
*/
|
||||
public static String dropExt(String fileName) {
|
||||
if (!TextUtils.isEmpty(fileName)) {
|
||||
int pos = fileName.lastIndexOf(".");
|
||||
if (pos != -1) {
|
||||
return FP.take(pos, fileName);
|
||||
}
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取文件内容转换为字符串
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
*/
|
||||
public static String getStringFromFile(String filePath) {
|
||||
String result = "";
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = new FileInputStream(filePath);
|
||||
int length = is.available();
|
||||
byte[] buffer = new byte[length];
|
||||
is.read(buffer);
|
||||
result = new String(buffer, StandardCharsets.UTF_8);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取Assets内容转换为字符串
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 字符串内容
|
||||
*/
|
||||
public static String getStringFromAssets(String fileName) {
|
||||
String result = "";
|
||||
try {
|
||||
InputStream is = BaseApp.getContext().getAssets().open(fileName);
|
||||
int length = is.available();
|
||||
byte[] buffer = new byte[length];
|
||||
is.read(buffer);
|
||||
result = new String(buffer, StandardCharsets.UTF_8);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Assets里面读取内容覆盖本地文件
|
||||
*
|
||||
* @param dir 文件夹路径
|
||||
* @param fileName 文件名称
|
||||
* @param overwrite 是否覆盖,即删除旧文件重新创建新文件
|
||||
* @return 操作是否成功
|
||||
*/
|
||||
public static boolean copyFileFromAssets(String dir, String fileName, boolean overwrite) {
|
||||
String path = dir + File.separator + fileName;
|
||||
File file = new File(path);
|
||||
if (file.exists() && overwrite) {
|
||||
file.delete();
|
||||
}
|
||||
if (!file.exists()) {
|
||||
try {
|
||||
if (!ensureDirExists(dir)) {
|
||||
return false;
|
||||
}
|
||||
file.createNewFile();
|
||||
InputStream in = BaseApp.getContext().getAssets().open(fileName);
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
while ((n = in.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
out.flush();
|
||||
in.close();
|
||||
out.close();
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
file.delete();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字节数组写入文件中
|
||||
*
|
||||
* @param buffer 字节数组
|
||||
* @param folderPath 文件夹路径
|
||||
* @param fileName 文件名称
|
||||
*/
|
||||
public static void saveDataToFile(byte[] buffer, String folderPath, String fileName) {
|
||||
File fileDir = new File(folderPath);
|
||||
if (!fileDir.exists()) {
|
||||
fileDir.mkdirs();
|
||||
}
|
||||
|
||||
File file = new File(folderPath + File.separator + fileName);
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(file);
|
||||
out.write(buffer);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化大小,带单位
|
||||
*/
|
||||
public static String formatSize(long size) {
|
||||
//获取到的size为:1705230
|
||||
int GB = 1024 * 1024 * 1024;//定义GB的计算常量
|
||||
int MB = 1024 * 1024;//定义MB的计算常量
|
||||
int KB = 1024;//定义KB的计算常量
|
||||
DecimalFormat df = new DecimalFormat("0.0");//格式化小数
|
||||
String resultSize = "";
|
||||
if (size / GB >= 1) {
|
||||
//如果当前Byte的值大于等于1GB
|
||||
resultSize = df.format(size / (float) GB) + "GB";
|
||||
} else if (size / MB >= 1) {
|
||||
//如果当前Byte的值大于等于1MB
|
||||
resultSize = df.format(size / (float) MB) + "MB";
|
||||
} else if (size / KB >= 1) {
|
||||
//如果当前Byte的值大于等于1KB
|
||||
resultSize = df.format(size / (float) KB) + "KB";
|
||||
} else {
|
||||
resultSize = size + "B";
|
||||
}
|
||||
return resultSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileName 文件名
|
||||
* @return 文件名是否正确
|
||||
*/
|
||||
public static boolean isFileNameCorrect(String fileName) {
|
||||
if (null == fileName) {
|
||||
return false;
|
||||
} else {
|
||||
fileName = fileName.trim();
|
||||
if (fileName.length() == 0) {
|
||||
return false;
|
||||
} else {
|
||||
for (String c : mCs) {
|
||||
if (fileName.contains(c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !containsSurrogateChar(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string 字符串
|
||||
* @return 是否包含需要替代的字符串
|
||||
*/
|
||||
public static boolean containsSurrogateChar(String string) {
|
||||
if (TextUtils.isEmpty(string)) {
|
||||
return false;
|
||||
} else {
|
||||
int length = string.length();
|
||||
boolean hasSurrogateChar = false;
|
||||
for (int i = 0; i < length; ++i) {
|
||||
char c = string.charAt(i);
|
||||
if (UNICODE_SURROGATE_START_CHAR <= c && c <= UNICODE_SURROGATE_END_CHAR) {
|
||||
hasSurrogateChar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hasSurrogateChar;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 把Uri转换为文件
|
||||
*
|
||||
* @param uri 源文件的Uri的路径
|
||||
* @param path 要存入的文件的路径
|
||||
* @param overwrite 是否需要复写
|
||||
* @return 是否已经把Uri转换成功为文件了
|
||||
*/
|
||||
public static boolean copyFileFromUri(Uri uri, String path, boolean overwrite) {
|
||||
File file = new File(path);
|
||||
if (file.exists() && overwrite) {
|
||||
file.delete();
|
||||
}
|
||||
if (!file.exists()) {
|
||||
try {
|
||||
if (!FileHelper.ensureDirExists(file.getParentFile().getAbsolutePath())) {
|
||||
return false;
|
||||
}
|
||||
InputStream stream = BaseApp.getContext().getContentResolver().openInputStream(uri);
|
||||
if (stream != null) {
|
||||
file.createNewFile();
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
byte buffer[] = new byte[4096];
|
||||
int n;
|
||||
while ((n = stream.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
out.flush();
|
||||
stream.close();
|
||||
out.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
file.delete();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将文件转换成字节数组
|
||||
*
|
||||
* @param file 文件
|
||||
* @return 字节数组
|
||||
*/
|
||||
public static byte[] fileToByteArray(File file) {
|
||||
if (file.exists() && file.canRead()) {
|
||||
try {
|
||||
return streamToBytes(new FileInputStream(file));
|
||||
} catch (Exception e) {
|
||||
Logger.error(TAG, String.valueOf(e));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将文件流转换成字节数组
|
||||
*
|
||||
* @param inputStream 输入流
|
||||
* @return 字节数组
|
||||
*/
|
||||
public static byte[] streamToBytes(InputStream inputStream) {
|
||||
byte[] content = null;
|
||||
ByteArrayOutputStream baos = null;
|
||||
BufferedInputStream bis = null;
|
||||
try {
|
||||
baos = new ByteArrayOutputStream();
|
||||
bis = new BufferedInputStream(inputStream);
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
while ((length = bis.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, length);
|
||||
}
|
||||
content = baos.toByteArray();
|
||||
if (content.length == 0) {
|
||||
content = null;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Logger.error(TAG, String.valueOf(e));
|
||||
} finally {
|
||||
if (baos != null) {
|
||||
try {
|
||||
baos.close();
|
||||
} catch (IOException e) {
|
||||
Logger.error(TAG, String.valueOf(e));
|
||||
}
|
||||
}
|
||||
if (bis != null) {
|
||||
try {
|
||||
bis.close();
|
||||
} catch (IOException e) {
|
||||
Logger.error(TAG, String.valueOf(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件转换成字符串
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 字符串内容
|
||||
*/
|
||||
public static String getTxtFileContent(String filePath) {
|
||||
String content = "";
|
||||
if (!StringUtils.isNullOrEmpty(filePath)) {
|
||||
File file = new File(filePath);
|
||||
if (file.isFile()) {
|
||||
FileInputStream inputStream = null;
|
||||
try {
|
||||
inputStream = new FileInputStream(file);
|
||||
String line;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
BufferedReader buffReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
while ((line = buffReader.readLine()) != null) {
|
||||
sb.append(line).append("\n");
|
||||
}
|
||||
content = sb.toString();
|
||||
} catch (Exception e) {
|
||||
Logger.error(TAG, "getTxtFileContent read fail, e = " + e);
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
package com.yizhuan.xchat_android_library.common.glide;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.widget.ImageView;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.yizhuan.xchat_android_library.easyphoto.engine.ImageEngine;
|
||||
|
||||
/**
|
||||
* Created by wushaocheng on 2021/3/29 15:18.
|
||||
* Desc:Glide实现类
|
||||
*/
|
||||
public class GlideEngine implements ImageEngine {
|
||||
/**
|
||||
* 加载图片到ImageView
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param uri 图片路径Uri
|
||||
* @param imageView 加载到的ImageView
|
||||
*/
|
||||
//安卓10推荐uri,并且path的方式不再可用
|
||||
@Override
|
||||
public void loadPhoto(@NonNull Context context, @NonNull Uri uri, @NonNull ImageView imageView) {
|
||||
GlideUtils.instance().loadUriCrossFade(uri, imageView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载gif动图图片到ImageView,gif动图不动
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param gifUri gif动图路径Uri
|
||||
* @param imageView 加载到的ImageView
|
||||
* <p>
|
||||
* 备注:不支持动图显示的情况下可以不写
|
||||
*/
|
||||
//安卓10推荐uri,并且path的方式不再可用
|
||||
@Override
|
||||
public void loadGifAsBitmap(@NonNull Context context, @NonNull Uri gifUri, @NonNull ImageView imageView) {
|
||||
GlideUtils.instance().loadUriGift(gifUri, imageView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载gif动图到ImageView,gif动图动
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param gifUri gif动图路径Uri
|
||||
* @param imageView 加载动图的ImageView
|
||||
* <p>
|
||||
* 备注:不支持动图显示的情况下可以不写
|
||||
*/
|
||||
//安卓10推荐uri,并且path的方式不再可用
|
||||
@Override
|
||||
public void loadGif(@NonNull Context context, @NonNull Uri gifUri, @NonNull ImageView imageView) {
|
||||
GlideUtils.instance().loadUriGiftAndCrossFade(gifUri, imageView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取图片加载框架中的缓存Bitmap,不用拼图功能可以直接返回null
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param uri 图片路径
|
||||
* @param width 图片宽度
|
||||
* @param height 图片高度
|
||||
* @return Bitmap
|
||||
* @throws Exception 异常直接抛出,EasyPhotos内部处理
|
||||
*/
|
||||
//安卓10推荐uri,并且path的方式不再可用
|
||||
@Override
|
||||
public Bitmap getCacheBitmap(@NonNull Context context, @NonNull Uri uri, int width, int height) throws Exception {
|
||||
return null;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,226 @@
|
||||
package com.yizhuan.xchat_android_library.common.photo
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.yizhuan.xchat_android_library.common.application.BaseApp
|
||||
import com.yizhuan.xchat_android_library.common.delegate.SpDelegate
|
||||
import com.yizhuan.xchat_android_library.common.file.FileHelper
|
||||
import com.yizhuan.xchat_android_library.common.glide.GlideEngine
|
||||
import com.yizhuan.xchat_android_library.common.util.Logger
|
||||
import com.yizhuan.xchat_android_library.easyphoto.EasyPhotos
|
||||
import com.yizhuan.xchat_android_library.easyphoto.constant.Type.*
|
||||
import com.yizhuan.xchat_android_library.easyphoto.models.album.entity.Photo
|
||||
import com.yizhuan.xchat_android_library.utils.TimeUtils
|
||||
import com.yizhuan.xchat_android_library.utils.TimeUtils.TIME_FORMAT
|
||||
import kotlinx.coroutines.*
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Created by wushaocheng on 2022/11/15
|
||||
* Desc:图片选择二次封装
|
||||
*/
|
||||
object PhotoProvider {
|
||||
private const val TAG = "PhotoProvider"
|
||||
|
||||
//上一次选择的时间,避免用户连续进入选择图片页导致删除缓存
|
||||
private var mLastSelectTime: Long by SpDelegate("PhotoProvider_last_select_time", 0L)
|
||||
|
||||
/**
|
||||
* easyPhoto库选择文件copy到内部的目录名
|
||||
*/
|
||||
private const val FOLD_EASY_PHOTO_INTERNAL = "selectPhotoTemp"
|
||||
private var mPhotoJob: Job? = null
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun photoCamera(fragment: Fragment, resultCode: Int, isClearCache: Boolean = true) {
|
||||
cancelJop()
|
||||
mPhotoJob = MainScope().launch {
|
||||
if (isClearCache && isClearByTime()) {
|
||||
withContext(Dispatchers.IO) { clearCache() }
|
||||
}
|
||||
EasyPhotos.createCamera(fragment, false)//参数说明:上下文,是否使用宽高数据(false时宽高数据为0,扫描速度更快)
|
||||
.setFileProviderAuthority("${BaseApp.getApplication().packageName}.fileprovider")//参数说明:见下方`FileProvider的配置`
|
||||
.start(resultCode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 喵圈发布动态专用,去掉bmp格式的图片
|
||||
*/
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun photoProviderPublish(activity: Activity, maxSelect: Int = 1, canChooseGif: Boolean = false, resultCode: Int, isClearCache: Boolean = true) {
|
||||
cancelJop()
|
||||
mPhotoJob = MainScope().launch {
|
||||
if (isClearCache && isClearByTime()) {
|
||||
withContext(Dispatchers.IO) { clearCache() }
|
||||
}
|
||||
EasyPhotos.createAlbum(activity, false, false, GlideEngine())//参数说明:上下文,是否显示相机按钮,是否使用宽高数据(false时宽高数据为0,扫描速度更快),[配置Glide为图片加载引擎](https://github.com/HuanTanSheng/EasyPhotos/wiki/12-%E9%85%8D%E7%BD%AEImageEngine%EF%BC%8C%E6%94%AF%E6%8C%81%E6%89%80%E6%9C%89%E5%9B%BE%E7%89%87%E5%8A%A0%E8%BD%BD%E5%BA%93)
|
||||
.setCount(maxSelect)//参数说明:最大可选数,默认1
|
||||
.setGif(canChooseGif)
|
||||
.filter(JPEG, JPG, PNG, WEBP)
|
||||
.setPuzzleMenu(false)
|
||||
.setCleanMenu(false)
|
||||
.start(resultCode)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun videoProvider(activity: Activity, maxSelect: Int = 1, resultCode: Int, isClearCache: Boolean = true) {
|
||||
cancelJop()
|
||||
mPhotoJob = MainScope().launch {
|
||||
if (isClearCache && isClearByTime()) {
|
||||
withContext(Dispatchers.IO) { clearCache() }
|
||||
}
|
||||
EasyPhotos.createAlbum(activity, false, false, GlideEngine())
|
||||
.setCount(maxSelect)//参数说明:最大可选数,默认1
|
||||
.setPuzzleMenu(false)
|
||||
.onlyVideo()
|
||||
.setCleanMenu(false)
|
||||
.start(resultCode)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun photoProvider(activity: Activity, maxSelect: Int = 1, canChooseGif: Boolean = false, resultCode: Int, isClearCache: Boolean = true) {
|
||||
cancelJop()
|
||||
mPhotoJob = MainScope().launch {
|
||||
if (isClearCache && isClearByTime()) {
|
||||
withContext(Dispatchers.IO) { clearCache() }
|
||||
}
|
||||
EasyPhotos.createAlbum(activity, false, false, GlideEngine())//参数说明:上下文,是否显示相机按钮,是否使用宽高数据(false时宽高数据为0,扫描速度更快),[配置Glide为图片加载引擎](https://github.com/HuanTanSheng/EasyPhotos/wiki/12-%E9%85%8D%E7%BD%AEImageEngine%EF%BC%8C%E6%94%AF%E6%8C%81%E6%89%80%E6%9C%89%E5%9B%BE%E7%89%87%E5%8A%A0%E8%BD%BD%E5%BA%93)
|
||||
.setCount(maxSelect)//参数说明:最大可选数,默认1
|
||||
.setGif(canChooseGif)
|
||||
.setPuzzleMenu(false)
|
||||
.setCleanMenu(false)
|
||||
.start(resultCode)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun photoProvider(activity: FragmentActivity, maxSelect: Int = 1, canChooseGif: Boolean = false, resultCode: Int, isClearCache: Boolean = true) {
|
||||
cancelJop()
|
||||
mPhotoJob = MainScope().launch {
|
||||
if (isClearCache && isClearByTime()) {
|
||||
withContext(Dispatchers.IO) { clearCache() }
|
||||
}
|
||||
EasyPhotos.createAlbum(activity, false, false, GlideEngine())//参数说明:上下文,是否显示相机按钮,是否使用宽高数据(false时宽高数据为0,扫描速度更快),[配置Glide为图片加载引擎](https://github.com/HuanTanSheng/EasyPhotos/wiki/12-%E9%85%8D%E7%BD%AEImageEngine%EF%BC%8C%E6%94%AF%E6%8C%81%E6%89%80%E6%9C%89%E5%9B%BE%E7%89%87%E5%8A%A0%E8%BD%BD%E5%BA%93)
|
||||
.setCount(maxSelect)//参数说明:最大可选数,默认1
|
||||
.setGif(canChooseGif)
|
||||
.setPuzzleMenu(false)
|
||||
.setCleanMenu(false)
|
||||
.start(resultCode)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun photoProvider(fragment: Fragment, maxSelect: Int = 1, canChooseGif: Boolean = false, resultCode: Int, isClearCache: Boolean = true, minFileSize: Long = 0L) {
|
||||
cancelJop()
|
||||
mPhotoJob = MainScope().launch {
|
||||
if (isClearCache && isClearByTime()) {
|
||||
withContext(Dispatchers.IO) { clearCache() }
|
||||
}
|
||||
EasyPhotos.createAlbum(fragment, false, false, GlideEngine())//参数说明:上下文,是否显示相机按钮,是否使用宽高数据(false时宽高数据为0,扫描速度更快),[配置Glide为图片加载引擎](https://github.com/HuanTanSheng/EasyPhotos/wiki/12-%E9%85%8D%E7%BD%AEImageEngine%EF%BC%8C%E6%94%AF%E6%8C%81%E6%89%80%E6%9C%89%E5%9B%BE%E7%89%87%E5%8A%A0%E8%BD%BD%E5%BA%93)
|
||||
.setCount(maxSelect)//参数说明:最大可选数,默认1
|
||||
.setGif(canChooseGif)
|
||||
.setMinFileSize(minFileSize)
|
||||
.setPuzzleMenu(false)
|
||||
.setCleanMenu(false)
|
||||
.start(resultCode)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getResultUriList(data: Intent?): List<Uri>? {
|
||||
val list: List<Photo>? = data?.getParcelableArrayListExtra(EasyPhotos.RESULT_PHOTOS)
|
||||
return list?.takeIf { it.isNotEmpty() }?.map { it.uri }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getResultPhotoList(data: Intent?): List<Photo>? {
|
||||
return data?.getParcelableArrayListExtra(EasyPhotos.RESULT_PHOTOS)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getResultPathListAsync(data: Intent?, resultListener: ((List<String>?) -> Unit)) {
|
||||
cancelJop()
|
||||
mPhotoJob = MainScope().launch {
|
||||
val list: List<Photo>? = data?.getParcelableArrayListExtra(EasyPhotos.RESULT_PHOTOS)
|
||||
val result = withContext(Dispatchers.IO) { copyToInternalCache(list) }
|
||||
resultListener.invoke(result)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 外部的文件复制到项目目录下,再获取对应路径
|
||||
* 修改方案原因:
|
||||
* 1. android Q 外部文件path变更为类似这种结构:/external/images/media/{文件id},导致无法通过path读取文件信息,文件名字及格式
|
||||
* 2. android Q 支持Uri获取文件,但uri获取不到文件类型及不少自身或者sdk的函数从参数需要用到path
|
||||
* 3. 原本项目功能逻辑很多用到了path(包括不仅仅文件大小,文件类型,作为参数传给其他函数使用(比如BitmapFactory.decodeFile)),直接全局替换为Uri,影响面过大,直接copy一份到自己内部,返回内部的路径,使得外部调用无感知
|
||||
*
|
||||
* 发现几个重点问题:
|
||||
* 1. 项目使用到BitmapFactory.decodeFile(imgPath, options)之类的方法,该方法在android Q直接使用外部path测试中发现,获取图片信息失败
|
||||
*
|
||||
*/
|
||||
private fun copyToInternalCache(photos: List<Photo>?): List<String>? {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val foldPath = getInternalPath() + File.separator
|
||||
val newPaths = ArrayList<String>()
|
||||
photos?.forEach {
|
||||
if (it.uri != null && !it.name.isNullOrEmpty()) {
|
||||
val path = "$foldPath${it.name}"
|
||||
if (FileHelper.copyFileFromUri(it.uri, path, true)) {
|
||||
newPaths.add(path)
|
||||
Logger.debug(TAG, "path: ${it.path} , displayName: ${it.name} , newPath: $path ")
|
||||
}
|
||||
}
|
||||
}
|
||||
newPaths
|
||||
} else {
|
||||
photos?.takeIf { it.isNotEmpty() }?.map { it.path }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除复制缓存
|
||||
*/
|
||||
fun clearCache() {
|
||||
Logger.debug(
|
||||
TAG, "clearCache => mLastSelectTime: ${TimeUtils.getDateTimeString(
|
||||
mLastSelectTime, TIME_FORMAT)}")
|
||||
FileHelper.removeAllFile(getInternalPath() + File.separator)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查时间,判断是否要删除缓冲
|
||||
*/
|
||||
private fun isClearByTime(): Boolean {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
val isClear = currentTime - mLastSelectTime > 10 * 60 * 1000
|
||||
mLastSelectTime = currentTime
|
||||
return isClear
|
||||
}
|
||||
|
||||
private fun cancelJop() {
|
||||
if (mPhotoJob?.isActive == true) {
|
||||
mPhotoJob?.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* easyPhoto内部复制缓存的路径
|
||||
*/
|
||||
private fun getInternalPath(): String {
|
||||
return ("${FileHelper.getRootFilesDir(Environment.DIRECTORY_PICTURES).absolutePath}${File.separator}$FOLD_EASY_PHOTO_INTERNAL")
|
||||
}
|
||||
}
|
@@ -0,0 +1,96 @@
|
||||
package com.yizhuan.xchat_android_library.common.transform
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
import android.graphics.RectF
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
|
||||
import java.security.MessageDigest
|
||||
|
||||
/**
|
||||
* author: lishangming
|
||||
* e-mail: lishangming@miya818.com
|
||||
* time: 2021/09/17
|
||||
* desc: glide转化器,原图片宽高短的一边设置为指定目标值,长的自适应拉伸,按照指定宽高比例和截取方式进行截取
|
||||
*/
|
||||
class AssignScaleTransformation(private val targetSize: Int, private val whRadio: Float, private val clipType: ClipType) : BitmapTransformation() {
|
||||
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
|
||||
messageDigest.update(("AssignScaleTransformation(${targetSize}_${whRadio}_${clipType})").toByteArray())
|
||||
}
|
||||
|
||||
override fun transform(pool: BitmapPool, toTransform: Bitmap, outWidth: Int, outHeight: Int): Bitmap {
|
||||
return crop(pool, toTransform) ?: toTransform
|
||||
}
|
||||
|
||||
private fun crop(pool: BitmapPool, source: Bitmap?): Bitmap? {
|
||||
if (targetSize <= 0 || whRadio <= 0) return null
|
||||
if (source == null) return null
|
||||
//计算截取原文件的宽高
|
||||
var clipWidth = 0
|
||||
var clipHeight = 0
|
||||
when {
|
||||
source.width / whRadio <= source.height -> {
|
||||
//用宽度计算,按比例拉伸高度比原本的小,故宽度不变,高度按比例设置
|
||||
clipWidth = source.width
|
||||
clipHeight = (source.width / whRadio).toInt()
|
||||
}
|
||||
source.height * whRadio <= source.width -> {
|
||||
//用高度计算,按比例拉伸宽度比原本的小,故高度不变,宽度按比例设置
|
||||
clipWidth = (source.height * whRadio).toInt()
|
||||
clipHeight = source.height
|
||||
|
||||
}
|
||||
else -> {
|
||||
clipWidth = source.width
|
||||
clipHeight = source.height
|
||||
}
|
||||
}
|
||||
|
||||
//需要生成图片的宽高
|
||||
val resultWidth = targetSize
|
||||
val resultHeight = (targetSize / whRadio).toInt()
|
||||
//截取比例
|
||||
val left = if (clipWidth < source.width) (source.width - clipWidth) / 2 else 0
|
||||
val right = left + clipWidth
|
||||
var result: Bitmap? = pool[resultWidth, resultHeight, Bitmap.Config.ARGB_8888]
|
||||
if (result == null) {
|
||||
result = Bitmap.createBitmap(resultWidth, resultHeight, Bitmap.Config.ARGB_8888)
|
||||
}
|
||||
val targetRect = RectF(0f, 0f, resultWidth.toFloat(), resultHeight.toFloat())
|
||||
val sourceRect = when (clipType) {
|
||||
ClipType.TOP -> {
|
||||
//顶部截取,固定截取高度
|
||||
Rect(left, 0, right, clipHeight)
|
||||
}
|
||||
else -> {
|
||||
//默认中间截取
|
||||
val top = if (clipHeight < source.height) (source.height - clipHeight) / 2 else 0
|
||||
val bottom = top + clipHeight
|
||||
Rect(left, top, right, bottom)
|
||||
}
|
||||
}
|
||||
if (result != null) {
|
||||
val canvas = Canvas(result)
|
||||
if (clipWidth < source.width || clipHeight < source.height) {
|
||||
canvas.drawBitmap(source, sourceRect, targetRect, null)
|
||||
} else {
|
||||
canvas.drawBitmap(source, null, targetRect, null)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun equals(obj: Any?): Boolean {
|
||||
return obj is AssignScaleTransformation
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return javaClass.name.hashCode()
|
||||
}
|
||||
|
||||
enum class ClipType {
|
||||
TOP,//截取顶部
|
||||
CENTER,//截取中间
|
||||
}
|
||||
}
|
@@ -0,0 +1,152 @@
|
||||
package com.yizhuan.xchat_android_library.common.transform;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/**
|
||||
* Created by zhl on 2020/1/3.
|
||||
*/
|
||||
public class ComplexTransformation extends BitmapTransformation {
|
||||
|
||||
private ComplexParamsBuilder mBuilder;
|
||||
|
||||
public ComplexTransformation(@NonNull ComplexParamsBuilder builder) {
|
||||
mBuilder = builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
|
||||
return crop(pool, toTransform, mBuilder);
|
||||
}
|
||||
|
||||
private static Bitmap crop(BitmapPool pool, Bitmap source, ComplexParamsBuilder builder) {
|
||||
if (source == null) return null;
|
||||
|
||||
int resultWidth = builder.mMaxWidth == 0 ? source.getWidth() : builder.mMaxWidth;
|
||||
int resultHeight = builder.mMaxHeight == 0 ? source.getHeight() : builder.mMaxHeight;
|
||||
|
||||
if (builder.mIsNeedScale) {
|
||||
if ((source.getWidth() > resultWidth || source.getHeight() > resultHeight)) {
|
||||
float scaleX = (float) resultWidth / source.getWidth();
|
||||
float scaleY = (float) resultHeight / source.getHeight();
|
||||
float scale = Math.min(scaleX, scaleY);
|
||||
resultWidth = (int) (scale * source.getWidth());
|
||||
resultHeight = (int) (scale * source.getHeight());
|
||||
} else {
|
||||
resultWidth = source.getWidth();
|
||||
resultHeight = source.getHeight();
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap result = pool.get(resultWidth, resultHeight, Bitmap.Config.ARGB_8888);
|
||||
|
||||
RectF targetRect = new RectF(0, 0, resultWidth, resultHeight);
|
||||
Canvas canvas = new Canvas(result);
|
||||
if (builder.mIsNeedCorner && source.getWidth() == resultWidth && source.getHeight() == resultHeight) {
|
||||
//该图没有过缩放,可直接绘制圆角
|
||||
Paint paint = new Paint();
|
||||
paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
|
||||
paint.setAntiAlias(true);
|
||||
canvas.drawRoundRect(targetRect, builder.mCorner, builder.mCorner, paint);
|
||||
return result;
|
||||
}
|
||||
if (builder.mIsNeedCropCenter && source.getHeight() != source.getWidth()) {
|
||||
int min = Math.min(source.getWidth(), source.getHeight());
|
||||
Rect sourceRect = new Rect((source.getWidth() - min) / 2,
|
||||
(source.getHeight() - min) / 2,
|
||||
(source.getWidth() - min) / 2 + min,
|
||||
(source.getHeight() - min) / 2 + min);
|
||||
canvas.drawBitmap(source, sourceRect, targetRect, null);
|
||||
} else {
|
||||
canvas.drawBitmap(source, null, targetRect, null);
|
||||
}
|
||||
if (builder.mIsNeedCorner) {
|
||||
Paint paint = new Paint();
|
||||
paint.setShader(new BitmapShader(result, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
|
||||
paint.setAntiAlias(true);
|
||||
Bitmap cornerResult = pool.get(resultWidth, resultHeight, Bitmap.Config.ARGB_8888);
|
||||
Canvas cornerCanvas = new Canvas(cornerResult);
|
||||
cornerCanvas.drawRoundRect(targetRect, builder.mCorner, builder.mCorner, paint);
|
||||
return cornerResult;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
|
||||
messageDigest.update(("ComplexTransformation(" + mBuilder.toString() + ")").getBytes());
|
||||
}
|
||||
|
||||
public static class ComplexParamsBuilder {
|
||||
int mMaxWidth;
|
||||
int mMaxHeight;
|
||||
boolean mIsNeedScale;
|
||||
boolean mIsNeedCropCenter;
|
||||
boolean mIsNeedCorner;
|
||||
float mCorner;
|
||||
|
||||
public ComplexParamsBuilder setMaxWidth(int mMaxWidth) {
|
||||
this.mMaxWidth = mMaxWidth;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ComplexParamsBuilder setMaxHeight(int mMaxHeight) {
|
||||
this.mMaxHeight = mMaxHeight;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ComplexParamsBuilder setIsNeedScale(boolean mIsNeedScale) {
|
||||
this.mIsNeedScale = mIsNeedScale;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ComplexParamsBuilder setIsNeedCropCenter(boolean mIsNeedCropCenter) {
|
||||
this.mIsNeedCropCenter = mIsNeedCropCenter;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ComplexParamsBuilder setIsNeedCorner(boolean mIsNeedCorner) {
|
||||
this.mIsNeedCorner = mIsNeedCorner;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ComplexParamsBuilder setCorner(float mCorner) {
|
||||
this.mCorner = mCorner;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ComplexParamsBuilder{" +
|
||||
"mMaxWidth=" + mMaxWidth +
|
||||
", mMaxHeight=" + mMaxHeight +
|
||||
", mIsNeedScale=" + mIsNeedScale +
|
||||
", mIsNeedCropCenter=" + mIsNeedCropCenter +
|
||||
", mIsNeedCorner=" + mIsNeedCorner +
|
||||
", mCorner=" + mCorner +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
return obj instanceof ComplexTransformation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getClass().getName().hashCode();
|
||||
}
|
||||
}
|
@@ -0,0 +1,195 @@
|
||||
package com.yizhuan.xchat_android_library.common.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.tencent.mmkv.MMKV;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* author: wushaocheng
|
||||
* time: 2022/11/15
|
||||
* desc: 使用腾讯MMKV框架替代SharedPreference,参考文档:https://github.com/Tencent/MMKV/wiki/android_tutorial_cn
|
||||
*/
|
||||
public class Config {
|
||||
private volatile static Config instance = null;
|
||||
private MMKV mmkv;
|
||||
|
||||
public static Config getInstance(Context context) {
|
||||
if (instance == null) {
|
||||
synchronized (Config.class) {
|
||||
if (instance == null) {
|
||||
instance = new Config(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private Config(Context context) {
|
||||
try {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
MMKV.initialize(context);
|
||||
mmkv = MMKV.mmkvWithID("config", MMKV.MULTI_PROCESS_MODE);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener) {
|
||||
if (listener != null && mmkv != null) {
|
||||
mmkv.registerOnSharedPreferenceChangeListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************** 编码方法 **************************************/
|
||||
|
||||
public boolean putBytes(String key, byte[] bytes) {
|
||||
if (mmkv == null) {
|
||||
return false;
|
||||
}
|
||||
return mmkv.encode(key, bytes);
|
||||
}
|
||||
|
||||
public boolean putInt(String key, int value) {
|
||||
if (mmkv == null) {
|
||||
return false;
|
||||
}
|
||||
return mmkv.encode(key, value);
|
||||
}
|
||||
|
||||
public boolean putLong(String key, long value) {
|
||||
if (mmkv == null) {
|
||||
return false;
|
||||
}
|
||||
return mmkv.encode(key, value);
|
||||
}
|
||||
|
||||
public boolean putFloat(String key, float value) {
|
||||
if (mmkv == null) {
|
||||
return false;
|
||||
}
|
||||
return mmkv.encode(key, value);
|
||||
}
|
||||
|
||||
public boolean putDouble(String key, double value) {
|
||||
if (mmkv == null) {
|
||||
return false;
|
||||
}
|
||||
return mmkv.encode(key, value);
|
||||
}
|
||||
|
||||
public boolean putBoolean(String key, boolean value) {
|
||||
if (mmkv == null) {
|
||||
return false;
|
||||
}
|
||||
return mmkv.encode(key, value);
|
||||
}
|
||||
|
||||
public boolean putString(String key, String value) {
|
||||
if (mmkv == null) {
|
||||
return false;
|
||||
}
|
||||
return mmkv.encode(key, value);
|
||||
}
|
||||
|
||||
public boolean putStringSet(String key, Set<String> value) {
|
||||
if (mmkv == null) {
|
||||
return false;
|
||||
}
|
||||
return mmkv.encode(key, value);
|
||||
}
|
||||
|
||||
public boolean putParcelable(String key, Parcelable value) {
|
||||
if (mmkv == null) {
|
||||
return false;
|
||||
}
|
||||
return mmkv.encode(key, value);
|
||||
}
|
||||
|
||||
/************************************** 解码方法 **************************************/
|
||||
|
||||
public byte[] getBytes(String key, byte[] defaultValue) {
|
||||
if (mmkv == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return mmkv.decodeBytes(key, defaultValue);
|
||||
}
|
||||
|
||||
public int getInt(String key, int defaultValue) {
|
||||
if (mmkv == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return mmkv.decodeInt(key, defaultValue);
|
||||
}
|
||||
|
||||
public long getLong(String key, long defaultValue) {
|
||||
if (mmkv == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return mmkv.decodeLong(key, defaultValue);
|
||||
}
|
||||
|
||||
public float getFloat(String key, float defaultValue) {
|
||||
if (mmkv == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return mmkv.decodeFloat(key, defaultValue);
|
||||
}
|
||||
|
||||
public double getDouble(String key, double defaultValue) {
|
||||
if (mmkv == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return mmkv.decodeDouble(key, defaultValue);
|
||||
}
|
||||
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
if (mmkv == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return mmkv.decodeBool(key, defaultValue);
|
||||
}
|
||||
|
||||
public String getString(String key, String defaultValue) {
|
||||
if (mmkv == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return mmkv.decodeString(key, defaultValue);
|
||||
}
|
||||
|
||||
public Set<String> getStringSet(String key, Set<String> defaultValue) {
|
||||
if (mmkv == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return mmkv.decodeStringSet(key, defaultValue);
|
||||
}
|
||||
|
||||
public <T extends Parcelable> T getParcelable(String key, Class<T> tClass, T defaultValue) {
|
||||
if (mmkv == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return mmkv.decodeParcelable(key, tClass, defaultValue);
|
||||
}
|
||||
|
||||
/************************************** 清理方法 **************************************/
|
||||
|
||||
public void remove(String key) {
|
||||
if (mmkv == null) {
|
||||
return;
|
||||
}
|
||||
mmkv.remove(key);
|
||||
}
|
||||
|
||||
public void clearAll() {
|
||||
if (mmkv == null) {
|
||||
return;
|
||||
}
|
||||
mmkv.clearAll();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,107 @@
|
||||
package com.yizhuan.xchat_android_library.common.util;
|
||||
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.yizhuan.xchat_android_library.common.application.BaseApp;
|
||||
import com.yizhuan.xchat_android_library.utils.TimeUtils;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* author: wushaocheng
|
||||
* time: 2022/11/15
|
||||
* desc: 封装底层com.tcloud.core.util.Config,方便使用
|
||||
*/
|
||||
public class SPUtils {
|
||||
|
||||
private static Config sConfig = Config.getInstance(BaseApp.getContext());
|
||||
|
||||
public static void putBytes(String key, byte[] bytes) {
|
||||
sConfig.putBytes(key, bytes);
|
||||
}
|
||||
|
||||
public static void putInt(String key, int value) {
|
||||
sConfig.putInt(key, value);
|
||||
}
|
||||
|
||||
public static void putLong(String key, long value) {
|
||||
sConfig.putLong(key, value);
|
||||
}
|
||||
|
||||
public static void putFloat(String key, float value) {
|
||||
sConfig.putFloat(key, value);
|
||||
}
|
||||
|
||||
public static void putDouble(String key, double value) {
|
||||
sConfig.putDouble(key, value);
|
||||
}
|
||||
|
||||
public static void putBoolean(String key, boolean value) {
|
||||
sConfig.putBoolean(key, value);
|
||||
}
|
||||
|
||||
public static void putString(String key, String value) {
|
||||
sConfig.putString(key, value);
|
||||
}
|
||||
|
||||
public static void putStringSet(String key, Set<String> value) {
|
||||
sConfig.putStringSet(key, value);
|
||||
}
|
||||
|
||||
public static void putParcelable(String key, Parcelable value) {
|
||||
sConfig.putParcelable(key, value);
|
||||
}
|
||||
|
||||
public static byte[] getBytes(String key, byte[] defaultValue) {
|
||||
return sConfig.getBytes(key, defaultValue);
|
||||
}
|
||||
|
||||
public static int getInt(String key, int defaultValue) {
|
||||
return sConfig.getInt(key, defaultValue);
|
||||
}
|
||||
|
||||
public static long getLong(String key, long defaultValue) {
|
||||
return sConfig.getLong(key, defaultValue);
|
||||
}
|
||||
|
||||
public static float getFloat(String key, float defaultValue) {
|
||||
return sConfig.getFloat(key, defaultValue);
|
||||
}
|
||||
|
||||
public static double getDouble(String key, double defaultValue) {
|
||||
return sConfig.getDouble(key, defaultValue);
|
||||
}
|
||||
|
||||
public static boolean getBoolean(String key, boolean defaultValue) {
|
||||
return sConfig.getBoolean(key, defaultValue);
|
||||
}
|
||||
|
||||
public static String getString(String key, String defaultValue) {
|
||||
return sConfig.getString(key, defaultValue);
|
||||
}
|
||||
|
||||
public static Set<String> getStringSet(String key, Set<String> defaultValue) {
|
||||
return sConfig.getStringSet(key, defaultValue);
|
||||
}
|
||||
|
||||
public static <T extends Parcelable> T getParcelable(String key, Class<T> tClass, T defaultValue) {
|
||||
return sConfig.getParcelable(key, tClass, defaultValue);
|
||||
}
|
||||
|
||||
public static void remove(String key) {
|
||||
sConfig.remove(key);
|
||||
}
|
||||
|
||||
public static void clearAll() {
|
||||
sConfig.clearAll();
|
||||
}
|
||||
|
||||
public static String getSharedDataKey(String constants, long playerId) {
|
||||
String toDayStr = TimeUtils.date2Str(new Date(), "yyyy-MM-dd");
|
||||
return getAccountKey(constants, playerId) + toDayStr;
|
||||
}
|
||||
public static String getAccountKey(String key, long playerId) {
|
||||
return key + playerId ;
|
||||
}
|
||||
}
|
@@ -1,4 +1,7 @@
|
||||
<resources>
|
||||
<string name="text_bitmap_too_large">上傳失敗,圖片太大啦~</string>
|
||||
<string name="text_bitmap_too_small">上傳圖片不能小於20kb</string>
|
||||
<string name="yizhuan_xchat_android_core_env_01">請輸入正確的環境</string>
|
||||
<string name="yizhuan_xchat_android_core_env_02">請輸入正確的環境</string>
|
||||
<string name="yizhuan_xchat_android_core_env_03">請先初始化環境</string>
|
||||
</resources>
|
||||
|
Reference in New Issue
Block a user