具体需求:
(1)获取项目assets文件夹内的图片。
(2)图片文件转bitmap。
(3)bitmap压缩。
(4)压缩过的bitmap转成图片文件。
(5)图片文件转Base64。
(6)Base64转图片文件图片。
(7)图片文件转bitmap。
以下代码在项目里,项目地址:https://gitee.com/urasaki/RxJava2AndRetrofit2
1.先申请权限,关于如何申请权限请查看RxPermissions的使用(简单实用)_ErwinNakajima的博客-CSDN博客_rxpermissions
2.添加RxJava2依赖(如果同步失败,可能是因为公司的网络有好多情况下连不到Google的仓库,所以就要连接自己的手机热点进行同步,手机热点一般会同步成功的,但是注意流量消耗)。
//rxjava2框架導入
api 'io.reactivex.rxjava2:rxjava:2.2.10'
api 'io.reactivex.rxjava2:rxandroid:2.1.1'
使用RxPermissions搭配RxLifecycle3
//1.解决rxjava导致的内存泄漏的框架導入
api 'com.trello.rxlifecycle3:rxlifecycle:3.1.0'
// If you want to bind to Android-specific lifecycles
api 'com.trello.rxlifecycle3:rxlifecycle-android:3.1.0'
// If you want pre-written Activities and Fragments you can subclass as providers
api 'com.trello.rxlifecycle3:rxlifecycle-components:3.1.0'
// If you want pre-written support preference Fragments you can subclass as providers
api 'com.trello.rxlifecycle3:rxlifecycle-components-preference:3.1.0'
// If you want to use Android Lifecycle for providers
api 'com.trello.rxlifecycle3:rxlifecycle-android-lifecycle:3.1.0'
// If you want to use Kotlin syntax
api 'com.trello.rxlifecycle3:rxlifecycle-kotlin:3.1.0'
// If you want to use Kotlin syntax with Android Lifecycle
api 'com.trello.rxlifecycle3:rxlifecycle-android-lifecycle-kotlin:3.1.0'
// If you want to use Navi for providers
// DEPRECATED: Use rxlifecycle-android-lifecycle instead. This will be removed in a future release.
api 'com.trello.rxlifecycle3:rxlifecycle-navi:3.1.0'
3.在AndroidManifest.xml中添加自己需要用到的权限。
4.Bean类。
package com.phone.base64_and_file.bean;
import android.graphics.Bitmap;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class Base64AndFileBean {
private String dirsPath;
private String dirsPathCompressed;
private String dirsPathCompressedRecover;
private File file;
private File fileCompressed;
private File fileCompressedRecover;
private Bitmap bitmap;
private Bitmap bitmapCompressed;
private Bitmap bitmapCompressedRecover;
public String base64Str;
private String txtFilePath;
private List base64StrList = new ArrayList<>();
public String getDirsPath() {
return dirsPath;
}
public void setDirsPath(String dirsPath) {
this.dirsPath = dirsPath;
}
public String getDirsPathCompressed() {
return dirsPathCompressed;
}
public void setDirsPathCompressed(String dirsPathCompressed) {
this.dirsPathCompressed = dirsPathCompressed;
}
public String getDirsPathCompressedRecover() {
return dirsPathCompressedRecover;
}
public void setDirsPathCompressedRecover(String dirsPathCompressedRecover) {
this.dirsPathCompressedRecover = dirsPathCompressedRecover;
}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public File getFileCompressed() {
return fileCompressed;
}
public void setFileCompressed(File fileCompressed) {
this.fileCompressed = fileCompressed;
}
public File getFileCompressedRecover() {
return fileCompressedRecover;
}
public void setFileCompressedRecover(File fileCompressedRecover) {
this.fileCompressedRecover = fileCompressedRecover;
}
public Bitmap getBitmap() {
return bitmap;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
public Bitmap getBitmapCompressed() {
return bitmapCompressed;
}
public void setBitmapCompressed(Bitmap bitmapCompressed) {
this.bitmapCompressed = bitmapCompressed;
}
public Bitmap getBitmapCompressedRecover() {
return bitmapCompressedRecover;
}
public void setBitmapCompressedRecover(Bitmap bitmapCompressedRecover) {
this.bitmapCompressedRecover = bitmapCompressedRecover;
}
public String getBase64Str() {
return base64Str;
}
public void setBase64Str(String base64Str) {
this.base64Str = base64Str;
}
public String getTxtFilePath() {
return txtFilePath;
}
public void setTxtFilePath(String txtFilePath) {
this.txtFilePath = txtFilePath;
}
public List getBase64StrList() {
return base64StrList;
}
public void setBase64StrList(List base64StrList) {
this.base64StrList.clear();
this.base64StrList.addAll(base64StrList);
}
}
5.BitmapManager代码。
package com.phone.base64_and_file;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ImageFormat;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.YuvImage;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import com.phone.common_library.manager.LogManager;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
import java.text.DecimalFormat;
import id.zelory.compressor.Compressor;
public class BitmapManager {
private static final String TAG = "BitmapManager";
public static final int ROTATE0 = 0;
public static final int ROTATE90 = 90;
public static final int ROTATE180 = 180;
public static final int ROTATE270 = 270;
public static final int ROTATE360 = 360;
public static final int PIC_COMPRESS_SIZE = 4;
public static final int IMAGEBOUND = 128;
public static final int MAXLENTH = 1024;
private static final boolean DEBUG = false;
private static final int QUALITY = 100;
private static final int DEFAULT_MAX_SIZE_CELL_NETWORK = 600;
private static final int QUESTION_MAX_SIZE_CELL_NETWORK = 1024;
private static final int QUESTION_IMAGE_JPG_QUALITY = 75;
private static final int DEFAULT_IMAGE_JPG_QUALITY = 50;
private static final int CONNECTTIMEOUT = 3000;
private BitmapManager() {
}
public static Bitmap createBitmap(Bitmap bitmap, Bitmap mark) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int mW = mark.getWidth();
int mH = mark.getHeight();
Bitmap newbitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);// 创建一个长宽一样的位图
Canvas cv = new Canvas(newbitmap);
cv.drawBitmap(bitmap, 0, 0, null);// 在 0,0坐标开始画入bitmap
cv.drawBitmap(mark, w - mW, h - mH, null);// 在右下角画入水印mark
cv.save();// 保存
cv.restore();// 存储
return newbitmap;
}
public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Matrix matrix = new Matrix();
float scaleWidht = ((float) w / width);
float scaleHeight = ((float) h / height);
matrix.postScale(scaleWidht, scaleHeight);
return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
}
public static Bitmap rotate(Bitmap bitmap, int angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
}
public static Bitmap createCircleBitmap(Bitmap source, int strokeWidth, boolean bl, int edge, int color) {
int diameter = source.getWidth() < source.getHeight() ? source.getWidth() : source.getHeight();
Bitmap target = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(target);//创建画布
Paint paint = new Paint();
paint.setAntiAlias(true);
canvas.drawCircle(diameter / 2, diameter / 2, diameter / 2, paint);//绘制圆形
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));//取相交裁剪
canvas.drawBitmap(source, strokeWidth, strokeWidth, paint);
if (bl) {
if (color == 0) color = 0xFFFEA248;//默认橘黄色
paint.setColor(color);
paint.setStyle(Paint.Style.STROKE);//描边
paint.setStrokeWidth(edge);
canvas.drawCircle(diameter / 2, diameter / 2, diameter / 2, paint);
}
return target;
}
public static Bitmap createCornerBitmap(Bitmap bitmap, int rx, int ry, boolean bl, int edge, int color) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);//创建画布
Paint paint = new Paint();
paint.setAntiAlias(true);
Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
RectF rectF = new RectF(rect);
canvas.drawRoundRect(rectF, rx, ry, paint);//绘制圆角矩形
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));//取相交裁剪
canvas.drawBitmap(bitmap, rect, rect, paint);
if (bl) {
if (color == 0) color = 0xFFFEA248;//默认橘黄色
paint.setColor(color);
paint.setColor(color);
paint.setStyle(Paint.Style.STROKE);//描边
paint.setStrokeWidth(edge);
canvas.drawRoundRect(rectF, rx, ry, paint);
}
return output;
}
public static Bitmap cropBitmap(Bitmap bitmap, float wScale, float hScale) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int wh = (int) (w * wScale);
int hw = (int) (h * hScale);
int retX = (int) (w * (1 - wScale) / 2);
int retY = (int) (h * (1 - hScale) / 2);
return Bitmap.createBitmap(bitmap, retX, retY, wh, hw, null, false);
}
public static Bitmap createReflectionBitmap(Bitmap bitmap, float region) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Matrix matrix = new Matrix();
matrix.preScale(1, -1);//镜像缩放
Bitmap reflectionBitmap = Bitmap.createBitmap(
bitmap, 0
, (int) (height * (1 - region))//从哪个点开始绘制
, width
, (int) (height * region)//绘制多高
, matrix, false);
Bitmap reflectionWithBitmap = Bitmap.createBitmap(width, height + (int) (height * region),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(reflectionWithBitmap);
canvas.drawBitmap(bitmap, 0, 0, null);
canvas.drawBitmap(reflectionBitmap, 0, height, null);
LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0,
reflectionWithBitmap.getHeight()
, 0x70ffffff, 0x00ffffff, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setShader(shader);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));//取两层绘制交集。显示下层。
canvas.drawRect(0, height, width, reflectionWithBitmap.getHeight(), paint);
return reflectionWithBitmap;
}
public static Bitmap compressBitmap(Bitmap bitmap, float many) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, (int) many * 100, baos);
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
return BitmapFactory.decodeStream(isBm, null, null);
}
public static Bitmap imageZoom(Bitmap bitmap, double maxSize) {
// 将bitmap放至数组中,意在获得bitmap的大小(与实际读取的原文件要大)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 格式、质量、输出流
bitmap.compress(Bitmap.CompressFormat.PNG, 70, baos);
byte[] b = baos.toByteArray();
// 将字节换成KB
double mid = b.length / 1024;
// 获取bitmap大小 是允许最大大小的多少倍
double i = mid / maxSize;
// 判断bitmap占用空间是否大于允许最大空间 如果大于则压缩 小于则不压缩
doRecycledIfNot(bitmap);
if (i > 1) {
// 缩放图片 此处用到平方根 将宽带和高度压缩掉对应的平方根倍
// (保持宽高不变,缩放后也达到了最大占用空间的大小)
return scaleWithWH(bitmap, bitmap.getWidth() / Math.sqrt(i),
bitmap.getHeight() / Math.sqrt(i));
}
return null;
}
public static Bitmap scaleWithWH(Bitmap bitmap, double w, double h) {
if (w == 0 || h == 0 || bitmap == null) {
return bitmap;
} else {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Matrix matrix = new Matrix();
float scaleWidth = (float) (w / width);
float scaleHeight = (float) (h / height);
matrix.postScale(scaleWidth, scaleHeight);
return Bitmap.createBitmap(bitmap, 0, 0, width, height,
matrix, true);
}
}
public static Bitmap getBitmap(byte[] data, int width, int height) {
Bitmap bitmap;
YuvImage yuvimage = new YuvImage(data, ImageFormat.NV21, width, height, null);
//data是onPreviewFrame参数提供
ByteArrayOutputStream baos = new ByteArrayOutputStream();
yuvimage.compressToJpeg(new Rect(0, 0, yuvimage.getWidth(), yuvimage.getHeight()), 100, baos);//
// 80--JPG图片的质量[0-100],100最高
byte[] rawImage = baos.toByteArray();
BitmapFactory.Options options = new BitmapFactory.Options();
SoftReference softRef = new SoftReference(BitmapFactory.decodeByteArray(rawImage, 0, rawImage
.length, options));
bitmap = softRef.get();
return bitmap;
}
public static Bitmap getBitmapResources(Context context, int resId) {
return BitmapFactory.decodeResource(context.getResources(), resId);
}
public static Bitmap getBitmapPath(String path) {
return BitmapFactory.decodeFile(path);
}
public static boolean saveFile(String path, Bitmap bmp) {
if (TextUtils.isEmpty(path) || bmp == null) return false;
File file = new File(path);
if (file.exists()) {
file.delete();
} else {
File p = file.getParentFile();
if (!p.exists()) {
p.mkdirs();
}
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bmp.compress(Bitmap.CompressFormat.JPEG, 100, bos);
bos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
public static void doRecycledIfNot(Bitmap bitmap) {
if (!bitmap.isRecycled()) {
bitmap.recycle();
}
}
public static Bitmap scaleImage(Bitmap resBitmap, int desWidth, int desHeight) {
int resWidth = resBitmap.getWidth();
int resHeight = resBitmap.getHeight();
if (resHeight > desHeight || resWidth > desWidth) {
// 计算出实际宽高和目标宽高的比率
final float heightRatio = (float) desHeight / (float) resHeight;
final float widthRatio = (float) desWidth / (float) resWidth;
float scale = heightRatio < widthRatio ? heightRatio : widthRatio;
LogManager.i(TAG, "scaleImage scale*****" + scale);
//開平方會有一點損失精度
float prescription = (float) Math.sqrt(scale);
// float prescription2 = (float) Math.sqrt(prescription);
LogManager.i(TAG, "scaleImage prescription*****" + prescription);
// LogManager.i(TAG, "scaleImage prescription2*****" + prescription2);
Bitmap bitmap = null;
//循環壓縮bitmap,防止一次壓縮bitmap卡頓問題(子線程把主線成卡頓了)
for (int i = 0; i < 2; i++) {
if (bitmap != null) {
bitmap = scale(bitmap, prescription);
// bitmap = scale(bitmap, prescription2);
} else {
bitmap = scale(resBitmap, prescription);
// bitmap = scale(resBitmap, prescription2);
}
LogManager.i(TAG, i + "scaleImage prescription*****" + prescription);
// LogManager.i(TAG, i + "scaleImage prescription2*****" + prescription2);
}
return bitmap;
}
return resBitmap;
}
private static Bitmap scale(Bitmap bitmap, float scale) {
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
public static Bitmap scale(Bitmap bitmap, int w, int h) {
if (bitmap == null) {
return null;
}
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Matrix matrix = new Matrix();
float scaleWidth = ((float) w / width);
float scaleHeight = ((float) h / height);
matrix.postScale(scaleWidth, scaleHeight);
return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
}
public static Uri saveTakePictureImage(Context context, byte[] data) {
File file = context.getExternalFilesDir("file1");
file = new File(file.getAbsolutePath() + File.separator + System.currentTimeMillis() + ".jpg");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write(data);
fos.flush();
} catch (Exception e) {
e.printStackTrace();
// 异常时删除保存失败的文件
try {
if (file != null && file.exists() && file.isFile()) {
file.delete();
}
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Log.e(TAG, file.getAbsolutePath());
return Uri.fromFile(file);
}
public static Bitmap yuvToBitmap(byte[] data, int width, int height) {
int frameSize = width * height;
int[] rgba = new int[frameSize];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int y = (0xff & ((int) data[i * width + j]));
int u = (0xff & ((int) data[frameSize + (i >> 1) * width + (j & ~1) + 0]));
int v = (0xff & ((int) data[frameSize + (i >> 1) * width + (j & ~1) + 1]));
y = y < 16 ? 16 : y;
int r = Math.round(1.164f * (y - 16) + 1.596f * (v - 128));
int g = Math.round(1.164f * (y - 16) - 0.813f * (v - 128) - 0.391f * (u - 128));
int b = Math.round(1.164f * (y - 16) + 2.018f * (u - 128));
r = r < 0 ? 0 : (r > 255 ? 255 : r);
g = g < 0 ? 0 : (g > 255 ? 255 : g);
b = b < 0 ? 0 : (b > 255 ? 255 : b);
rgba[i * width + j] = 0xff000000 + (b << 16) + (g << 8) + r;
}
}
Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bmp.setPixels(rgba, 0, width, 0, 0, width, height);
return bmp;
}
public static Bitmap depthToBitmap(byte[] depthBytes, int width, int height) {
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int[] argbData = new int[width * height];
for (int i = 0; i < width * height; i++) {
argbData[i] = (((int) depthBytes[i * 2] + depthBytes[i * 2 + 1] * 256) / 10 & 0x000000ff)
| ((((int) depthBytes[i * 2] + depthBytes[i * 2 + 1] * 256) / 10) & 0x000000ff) << 8
| ((((int) depthBytes[i * 2] + depthBytes[i * 2 + 1] * 256) / 10) & 0x000000ff) << 16
| 0xff000000;
}
bitmap.setPixels(argbData, 0, width, 0, 0, width, height);
return bitmap;
}
public static Bitmap rGBToBitmap(byte[] bytes, int width, int height) {
// use Bitmap.Config.ARGB_8888 instead of type is OK
Bitmap stitchBmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
byte[] rgba = new byte[width * height * 4];
for (int i = 0; i < width * height; i++) {
byte b1 = bytes[i * 3 + 0];
byte b2 = bytes[i * 3 + 1];
byte b3 = bytes[i * 3 + 2];
// set value
rgba[i * 4 + 0] = b1;
rgba[i * 4 + 1] = b2;
rgba[i * 4 + 2] = b3;
rgba[i * 4 + 3] = (byte) 255;
}
stitchBmp.copyPixelsFromBuffer(ByteBuffer.wrap(rgba));
return stitchBmp;
}
public static Bitmap bGRToBitmap(byte[] bytes, int width, int height) {
// use Bitmap.Config.ARGB_8888 instead of type is OK
Bitmap stitchBmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
byte[] rgba = new byte[width * height * 4];
for (int i = 0; i < width * height; i++) {
byte b1 = bytes[i * 3 + 0];
byte b2 = bytes[i * 3 + 1];
byte b3 = bytes[i * 3 + 2];
// set value
rgba[i * 4 + 0] = b3;
rgba[i * 4 + 1] = b2;
rgba[i * 4 + 2] = b1;
rgba[i * 4 + 3] = (byte) 255;
}
stitchBmp.copyPixelsFromBuffer(ByteBuffer.wrap(rgba));
return stitchBmp;
}
public static byte[] aRGBToR(byte[] bytes, int width, int height) {
byte[] IR = new byte[width * height];
for (int i = 0; i < width * height; i++) {
IR[i] = bytes[i * 4];
}
return IR;
}
//
// public static Bitmap getInstaceBmp(BDFaceImageInstance newInstance) {
// Bitmap transBmp = null;
// if (newInstance.imageType == BDFaceSDKCommon.BDFaceImageType.BDFACE_IMAGE_TYPE_RGBA) {
// transBmp = Bitmap.createBitmap(newInstance.width, newInstance.height, Bitmap.Config.ARGB_8888);
// transBmp.copyPixelsFromBuffer(ByteBuffer.wrap(newInstance.data));
// } else if (newInstance.imageType == BDFaceSDKCommon.BDFaceImageType.BDFACE_IMAGE_TYPE_BGR) {
// transBmp = BitmapManager.BGR2Bitmap(newInstance.data, newInstance.width, newInstance.height);
// } else if (newInstance.imageType == BDFaceSDKCommon.BDFaceImageType.BDFACE_IMAGE_TYPE_YUV_NV21) {
// transBmp = BitmapManager.yuv2Bitmap(newInstance.data, newInstance.width, newInstance.height);
// } else if (newInstance.imageType == BDFaceSDKCommon.BDFaceImageType.BDFACE_IMAGE_TYPE_GRAY) {
// transBmp = Depth2Bitmap(newInstance.data, newInstance.width, newInstance.height);
// }
// return transBmp;
// }
public static Bitmap getBitmap(String path) {
FileInputStream fis = null;
BufferedInputStream bis = null;
Bitmap bm = null;
try {
fis = new FileInputStream(path);
BitmapFactory.Options options = new BitmapFactory.Options();
// options.inSampleSize = 8;//图片的长宽都是原来的1/8
bis = new BufferedInputStream(fis);
bm = BitmapFactory.decodeStream(bis, null, options);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return bm;
}
public static InputStream bitmapToInputStream(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
ByteArrayInputStream byteArrInputStream = new ByteArrayInputStream(
baos.toByteArray());
return byteArrInputStream;
}
public static byte[] readStream(String imagepath) {
FileInputStream fis = null;
BufferedInputStream bis = null;
ByteArrayOutputStream baos = null;
try {
fis = new FileInputStream(imagepath);
bis = new BufferedInputStream(fis);
baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while (-1 != (len = bis.read(buffer))) {
baos.write(buffer, 0, len);
}
//刷新此输出流并强制写出所有缓冲的输出字节
baos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bis != null) {
bis.close();
}
if (baos != null) {
baos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return baos.toByteArray();
}
public static File saveFile(Bitmap bitmap, String dirsPath, String fileName) {
File dirs = new File(dirsPath);
if (!dirs.exists()) {
dirs.mkdirs();
}
File captureFile = new File(dirs, fileName);
BufferedOutputStream bos = null;
try {
bos = new BufferedOutputStream(new FileOutputStream(captureFile));
//刷新此输出流并强制写出所有缓冲的输出字节
bos.flush();
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return captureFile;
}
public static long getFileSize(File file) {
long size = 0;
if (file.exists()) {
FileInputStream fis = null;
BufferedInputStream bis = null;
try {
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
size = bis.available();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return size;
}
return 0;
}
public static String getDataSize(long size) {
DecimalFormat formater = new DecimalFormat("####.00");
if (size < 1024) {
return size + "bytes";
} else if (size < 1024 * 1024) {
float kbsize = size / 1024f;
return formater.format(kbsize) + "KB";
} else if (size < 1024 * 1024 * 1024) {
float mbsize = size / 1024f / 1024f;
return formater.format(mbsize) + "MB";
} else if (size < 1024 * 1024 * 1024 * 1024) {
float gbsize = size / 1024f / 1024f / 1024f;
return formater.format(gbsize) + "GB";
} else {
return "size: error";
}
}
public static File initCompressorIO(Context context, String path, String dirsPath) {
File dirs2 = new File(dirsPath);
if (!dirs2.exists()) {
dirs2.mkdirs();
}
File file = null;
try {
file = new Compressor(context)
// .setMaxWidth(1280)
// .setMaxHeight(960)
.setQuality(50)
.setCompressFormat(Bitmap.CompressFormat.PNG)
.setDestinationDirectoryPath(dirsPath)
.compressToFile(new File(path));
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
public static File getAssetFile(Context context, String dirsPath, String assetFileName) {
AssetManager assetManager = context.getAssets();
File dirs = new File(dirsPath);
if (!dirs.exists()) {
dirs.mkdirs();
}
File file = new File(dirs, assetFileName);
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
InputStream is = null;
BufferedInputStream bis = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
is = assetManager.open(assetFileName);
bis = new BufferedInputStream(is);
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
byte[] buffer = new byte[1024];
int len = 0;
while (-1 != (len = bis.read(buffer))) {
bos.write(buffer, 0, len);
}
//刷新此输出流并强制写出所有缓冲的输出字节
bos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return file;
}
public static Bitmap base64ToBitmap(String base64String) {
base64String = Uri.decode(base64String);
byte[] decode = Base64.decode(base64String, Base64.DEFAULT);
Bitmap bitmap = BitmapFactory.decodeByteArray(decode, 0, decode.length);
return bitmap;
}
}
5.doOnNext的使用的主要代码。
private void initBase64AndFileTask() {
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
LogManager.i(TAG, "threadName*****" + Thread.currentThread().getName());
showLoading();
emitter.onNext(0);
}
}).subscribeOn(AndroidSchedulers.mainThread()) //给上面分配了UI线程
// .observeOn(AndroidSchedulers.mainThread()) //给下面分配了UI线程
// .doOnNext(new Consumer() {
// @Override
// public void accept(Integer integer) throws Exception {
// LogManager.i(TAG, "threadName*****" + Thread.currentThread().getName());
// showLoading();
// }
// })
.observeOn(Schedulers.io()) //给下面分配了异步线程
.map(new Function() {
@Override
public Base64AndFileBean apply(Integer integer) throws Exception {
LogManager.i(TAG, "threadName2*****" + Thread.currentThread().getName());
File file = BitmapManager.getAssetFile(baseApplication, dirsPath, "picture_large.png");
base64AndFileBean.setFile(file);
return base64AndFileBean;
}
})
.observeOn(Schedulers.io()) //给下面分配了异步线程
.doOnNext(new Consumer() {
@Override
public void accept(Base64AndFileBean base64AndFileBean) throws Exception {
LogManager.i(TAG, "threadName3*****" + Thread.currentThread().getName());
//把图片转化成bitmap
Bitmap bitmap = BitmapManager.getBitmap(base64AndFileBean.getFile().getAbsolutePath());
base64AndFileBean.setBitmap(bitmap);
}
})
.observeOn(Schedulers.io()) //给下面分配了异步线程
.doOnNext(new Consumer() {
@Override
public void accept(Base64AndFileBean base64AndFileBean) throws Exception {
LogManager.i(TAG, "threadName4*****" + Thread.currentThread().getName());
//再压缩bitmap
Bitmap bitmapCompressed = BitmapManager.scaleImage(base64AndFileBean.getBitmap(), 1280, 960);
base64AndFileBean.setBitmapCompressed(bitmapCompressed);
}
})
.observeOn(AndroidSchedulers.mainThread()) //给下面分配了异步线程
.doOnNext(new Consumer() {
@Override
public void accept(Base64AndFileBean base64AndFileBean) throws Exception {
LogManager.i(TAG, "threadName5*****" + Thread.currentThread().getName());
//展示压缩过的图片
tevCompressedPicture.setVisibility(View.GONE);
imvCompressedPicture.setVisibility(View.VISIBLE);
imvCompressedPicture.setImageBitmap(base64AndFileBean.getBitmapCompressed());
}
})
.observeOn(Schedulers.io()) //给下面分配了异步线程
.doOnNext(new Consumer() {
@Override
public void accept(Base64AndFileBean base64AndFileBean) throws Exception {
LogManager.i(TAG, "threadName6*****" + Thread.currentThread().getName());
//再把压缩后的bitmap保存到本地
File fileCompressed = BitmapManager.saveFile(base64AndFileBean.getBitmapCompressed(), base64AndFileBean.getDirsPathCompressed(), "picture_large_compressed.png");
base64AndFileBean.setFileCompressed(fileCompressed);
LogManager.i(TAG, "base64AndFileBean.getFileCompressed().getPath()*****" + base64AndFileBean.getFileCompressed().getPath());
LogManager.i(TAG, "base64AndFileBean.getFileCompressed().getAbsolutePath()*****" + base64AndFileBean.getFileCompressed().getAbsolutePath());
}
})
.observeOn(Schedulers.io()) //给下面分配了异步线程
.doOnNext(new Consumer() {
@Override
public void accept(Base64AndFileBean base64AndFileBean) throws Exception {
LogManager.i(TAG, "threadName7*****" + Thread.currentThread().getName());
String base64Str = null;
if (base64AndFileBean.getFileCompressed().exists()) {
base64Str = Base64AndFileManager.fileToBase64(base64AndFileBean.getFileCompressed());
// base64Str = Base64AndFileManager.fileToBase64Test(file);
// base64Str = Base64AndFileManager.fileToBase64Second(file);
base64AndFileBean.setBase64Str(base64Str);
}
if (!TextUtils.isEmpty(base64Str)) {
String fileName = "base64Str.txt";
String txtFilePath = FileManager.writeStrToTextFile(base64Str, base64AndFileBean.getDirsPathCompressed(), fileName);
base64AndFileBean.setTxtFilePath(txtFilePath);
base64AndFileBean.setBase64StrList(Base64AndFileManager.getBase64StrList(txtFilePath));
// base64Str = "";
// StringBuilder stringBuilder = new StringBuilder();
// for (int i = 0; i < base64StrList.size(); i++) {
// stringBuilder.append(base64StrList.get(i));
// }
// base64Str = stringBuilder.toString();
// //把字符串的最後一個打印出來,然後看看和RecyclerView顯示的最後一個字符串是否一致
// LogManager.i(TAG, "base64StrList******" + base64StrList.get(base64StrList.size() - 1));
}
}
})
.observeOn(AndroidSchedulers.mainThread()) //给下面分配了异步线程
.doOnNext(new Consumer() {
@Override
public void accept(Base64AndFileBean base64AndFileBean) throws Exception {
LogManager.i(TAG, "threadName8*****" + Thread.currentThread().getName());
tevPictureToBase64.setVisibility(View.GONE);
rcvBase64Str.setVisibility(View.VISIBLE);
base64StrAdapter.clearData();
base64StrAdapter.addAllData(base64AndFileBean.getBase64StrList());
Observable.timer(2000, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
//解决RxJava2导致的内存泄漏问题
.compose(bindUntilEvent(ActivityEvent.DESTROY))
.subscribe(new Consumer() {
@Override
public void accept(Long aLong) throws Exception {
LogManager.i(TAG, "threadNameC*****" + Thread.currentThread().getName());
if (base64AndFileBean.getBase64StrList().size() > 0) {
//RecyclerView自動滑動到底部,看看最後一個字符串和打印出來的字符串是否一致
rcvBase64Str.scrollToPosition(base64AndFileBean.getBase64StrList().size() - 1);
}
}
});
}
})
.observeOn(Schedulers.io()) //给下面分配了异步线程
.doOnNext(new Consumer() {
@Override
public void accept(Base64AndFileBean base64AndFileBean) throws Exception {
LogManager.i(TAG, "threadName9*****" + Thread.currentThread().getName());
//再把压缩后的bitmap保存到本地
File fileCompressedRecover = Base64AndFileManager.base64ToFile(base64AndFileBean.getBase64Str(),
base64AndFileBean.getDirsPathCompressedRecover(),
"picture_large_compressed_recover");
base64AndFileBean.setFileCompressedRecover(fileCompressedRecover);
}
})
.observeOn(Schedulers.io()) //给下面分配了异步线程
// .doOnNext(new Consumer() {
// @Override
// public void accept(Base64AndFileBean base64AndFileBean) throws Exception {
// LogManager.i(TAG, "threadName10*****" + Thread.currentThread().getName());
// Bitmap bitmapCompressedRecover = BitmapFactory.decodeFile(base64AndFileBean.getFileCompressedRecover().getAbsolutePath());
// base64AndFileBean.setBitmapCompressedRecover(bitmapCompressedRecover);
// }
// })
.map(new Function() {
@Override
public Bitmap apply(Base64AndFileBean base64AndFileBean) throws Exception {
LogManager.i(TAG, "threadName10*****" + Thread.currentThread().getName());
Bitmap bitmapCompressedRecover = BitmapFactory.decodeFile(base64AndFileBean.getFileCompressedRecover().getAbsolutePath());
return bitmapCompressedRecover;
}
})
.observeOn(AndroidSchedulers.mainThread()) //给下面分配了UI线程
//解决RxJava2导致的内存泄漏问题
.compose(bindUntilEvent(ActivityEvent.DESTROY))
.subscribe(new Consumer() {
@Override
public void accept(Bitmap bitmapCompressedRecover) throws Exception {
LogManager.i(TAG, "threadName11*****" + Thread.currentThread().getName());
tevBase64ToPicture.setVisibility(View.GONE);
imvBase64ToPicture.setVisibility(View.VISIBLE);
imvBase64ToPicture.setImageBitmap(bitmapCompressedRecover);
base64AndFileBean.setBitmapCompressedRecover(bitmapCompressedRecover);
hideLoading();
}
});
}
6.基础Activity文件。
package com.phone.common_library.base; import android.app.ActivityManager; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.drawable.GradientDrawable; import android.os.Bundle; import android.os.Looper; import android.view.Gravity; import android.view.View; import android.widget.FrameLayout; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.Nullable; import com.gyf.immersionbar.ImmersionBar; import com.phone.common_library.BaseApplication; import com.phone.common_library.R; import com.phone.common_library.manager.ActivityPageManager; import com.phone.common_library.manager.CrashHandlerManager; import com.phone.common_library.manager.LogManager; import com.phone.common_library.manager.ToolbarManager; import com.qmuiteam.qmui.widget.QMUILoadingView; import com.trello.rxlifecycle3.components.support.RxAppCompatActivity; import java.util.HashMap; import java.util.List; import java.util.Map; public abstract class BaseMvpRxAppActivity> extends RxAppCompatActivity { private static final String TAG = "BaseMvpRxAppActivity"; public QMUILoadingView loadView; protected FrameLayout.LayoutParams layoutParams; protected T presenter; protected String url; protected Map bodyParams = new HashMap<>(); protected Intent intent; protected Bundle bundle; protected RxAppCompatActivity rxAppCompatActivity; protected BaseApplication baseApplication; public ActivityPageManager activityPageManager; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); rxAppCompatActivity = this; baseApplication = (BaseApplication) getApplication(); activityPageManager = ActivityPageManager.getInstance(); activityPageManager.addActivity(this); setContentView(initLayoutId()); loadView = new QMUILoadingView(this); loadView.setVisibility(View.GONE); loadView.setSize(100); loadView.setColor(getResources().getColor(R.color.color_80000000)); layoutParams = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); layoutParams.gravity = Gravity.CENTER; // setToolbar(); presenter = attachPresenter(); initData(); initViews(); initLoadData(); // RxPermissionsManager rxPermissionsManager = RxPermissionsManager.getInstance(this); // rxPermissionsManager.initRxPermissionsActivity(new OnCommonRxPermissionsCallback() { // @Override // public void onRxPermissionsAllPass() { // CrashHandlerManager crashHandlerManager = CrashHandlerManager.getInstance(rxAppCompatActivity); // crashHandlerManager.sendPreviousReportsToServer(); // crashHandlerManager.init(); // } // // @Override // public void onNotCheckNoMorePromptError() { // // } // // @Override // public void onCheckNoMorePromptError() { // // } // }); } @Override public void onConfigurationChanged(Configuration newConfig) { //非默认值 if (newConfig.fontScale != 1) { getResources(); } super.onConfigurationChanged(newConfig); } @Override public Resources getResources() {//还原字体大小 Resources res = super.getResources(); //非默认值 if (res.getConfiguration().fontScale != 1) { Configuration newConfig = new Configuration(); newConfig.setToDefaults();//设置默认 res.updateConfiguration(newConfig, res.getDisplayMetrics()); } return res; } protected abstract int initLayoutId(); protected void setToolbar(boolean isDarkFont) { if (isDarkFont) { ImmersionBar.with(this) //原理:如果当前设备支持状态栏字体变色,会设置状态栏字体为黑色,如果当前设备不支持状态栏字体变色,会使当前状态栏加上透明度,否则不执行透明度 .statusBarDarkFont(isDarkFont) .statusBarColor(R.color.color_FFFFFFFF) //状态栏颜色,不写默认透明色 // .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦 .keyboardEnable(true) .init(); } else { ImmersionBar.with(this) .statusBarDarkFont(isDarkFont) .statusBarColor(R.color.color_FF198CFF) //状态栏颜色,不写默认透明色 // .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦 .keyboardEnable(true) .init(); } ToolbarManager.assistActivity(findViewById(android.R.id.content)); } protected void setToolbar(boolean isDarkFont, boolean isResizeChildOfContent) { if (isDarkFont) { ImmersionBar.with(this) //原理:如果当前设备支持状态栏字体变色,会设置状态栏字体为黑色,如果当前设备不支持状态栏字体变色,会使当前状态栏加上透明度,否则不执行透明度 .statusBarDarkFont(isDarkFont) .statusBarColor(R.color.color_FFFFFFFF) //状态栏颜色,不写默认透明色 // .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦 .keyboardEnable(true) .init(); } else { ImmersionBar.with(this) .statusBarDarkFont(isDarkFont) .statusBarColor(R.color.color_FF198CFF) //状态栏颜色,不写默认透明色 // .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦 .keyboardEnable(true) .init(); } if (isResizeChildOfContent) { ToolbarManager.assistActivity(findViewById(android.R.id.content)); } } protected void setToolbar(boolean isDarkFont, int color) { if (isDarkFont) { ImmersionBar.with(this) //原理:如果当前设备支持状态栏字体变色,会设置状态栏字体为黑色,如果当前设备不支持状态栏字体变色,会使当前状态栏加上透明度,否则不执行透明度 .statusBarDarkFont(isDarkFont) .statusBarColor(color) //状态栏颜色,不写默认透明色 // .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦 .init(); } else { ImmersionBar.with(this) .statusBarDarkFont(isDarkFont) .statusBarColor(color) //状态栏颜色,不写默认透明色 // .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦 .init(); } ToolbarManager.assistActivity(findViewById(android.R.id.content)); } protected void setToolbar(boolean isDarkFont, int color, boolean isResizeChildOfContent) { if (isDarkFont) { ImmersionBar.with(this) //原理:如果当前设备支持状态栏字体变色,会设置状态栏字体为黑色,如果当前设备不支持状态栏字体变色,会使当前状态栏加上透明度,否则不执行透明度 .statusBarDarkFont(isDarkFont) .statusBarColor(color) //状态栏颜色,不写默认透明色 // .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦 .init(); } else { ImmersionBar.with(this) .statusBarDarkFont(isDarkFont) .statusBarColor(color) //状态栏颜色,不写默认透明色 // .autoStatusBarDarkModeEnable(true, 0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦 .init(); } if (isResizeChildOfContent) { ToolbarManager.assistActivity(findViewById(android.R.id.content)); } } protected void initImmersionBar() { //设置共同沉浸式样式 ImmersionBar.with(this) .navigationBarColor(R.color.color_FFE066FF).init(); } protected abstract void initData(); protected abstract void initViews(); protected abstract void initLoadData(); protected abstract T attachPresenter(); protected void showToast(String message, boolean isLongToast) { // Toast.makeText(this, message, Toast.LENGTH_LONG).show(); if (!rxAppCompatActivity.isFinishing()) { Toast toast; int duration; if (isLongToast) { duration = Toast.LENGTH_LONG; } else { duration = Toast.LENGTH_SHORT; } toast = Toast.makeText(rxAppCompatActivity, message, duration); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); } } protected void showCustomToast(int left, int right, int textSize, int textColor, int bgColor, int height, int roundRadius, String message, boolean isLongToast) { FrameLayout frameLayout = new FrameLayout(this); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT); frameLayout.setLayoutParams(layoutParams); TextView textView = new TextView(this); FrameLayout.LayoutParams layoutParams1 = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, height); textView.setLayoutParams(layoutParams1); textView.setPadding(left, 0, right, 0); textView.setTextSize(textSize); textView.setTextColor(textColor); textView.setGravity(Gravity.CENTER); textView.setIncludeFontPadding(false); GradientDrawable gradientDrawable = new GradientDrawable();//创建drawable gradientDrawable.setColor(bgColor); gradientDrawable.setCornerRadius(roundRadius); textView.setBackground(gradientDrawable); textView.setText(message); frameLayout.addView(textView); Toast toast = new Toast(this); toast.setView(frameLayout); if (isLongToast) { toast.setDuration(Toast.LENGTH_LONG); } else { toast.setDuration(Toast.LENGTH_SHORT); } toast.show(); } public boolean isOnMainThread() { return Looper.getMainLooper().getThread().getId() == Thread.currentThread().getId(); } protected void startActivity(Class> cls) { intent = new Intent(this, cls); startActivity(intent); } protected void startActivityCarryParams(Class> cls, Map params) { intent = new Intent(this, cls); bundle = new Bundle(); if (params != null && params.size() > 0) { for (String key : params.keySet()) { if (params.get(key) != null) {//如果参数不是null,才把参数传给后台 bundle.putString(key, params.get(key)); } } intent.putExtras(bundle); } startActivity(intent); } protected void startActivityForResult(Class> cls, int requestCode) { intent = new Intent(this, cls); startActivityForResult(intent, requestCode); } protected void startActivityForResultCarryParams(Class> cls, Map params, int requestCode) { intent = new Intent(this, cls); bundle = new Bundle(); if (params != null && params.size() > 0) { for (String key : params.keySet()) { if (params.get(key) != null) {//如果参数不是null,才把参数传给后台 bundle.putString(key, params.get(key)); } } intent.putExtras(bundle); } startActivityForResult(intent, requestCode); } protected boolean isEmpty(String dataStr) { if (dataStr != null && !"".equals(dataStr)) { return false; } else { return true; } } protected void detachPresenter() { if (presenter != null) { presenter.detachView(); presenter = null; } } private void killAppProcess(Context context) { LogManager.i(TAG, "killAppProcess"); ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List processInfos = manager.getRunningAppProcesses(); // 先杀掉相关进程,最后再杀掉主进程 for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : processInfos) { if (runningAppProcessInfo.pid != android.os.Process.myPid()) { android.os.Process.killProcess(runningAppProcessInfo.pid); } } LogManager.i(TAG, "执行killAppProcess,應用開始自殺"); CrashHandlerManager crashHandlerManager = CrashHandlerManager.getInstance(context); crashHandlerManager.saveTrimMemoryInfoToFile("执行killAppProcess,應用開始自殺"); try { Thread.sleep(1000); } catch (InterruptedException e) { LogManager.i(TAG, "error"); } android.os.Process.killProcess(android.os.Process.myPid()); // 正常退出程序,也就是结束当前正在运行的 java 虚拟机 System.exit(0); } @Override protected void onDestroy() { detachPresenter(); if (bodyParams != null) { bodyParams.clear(); bodyParams = null; } if (activityPageManager != null) { if (activityPageManager.isLastAliveActivity().get()) { killAppProcess(baseApplication); } activityPageManager.removeActivity(rxAppCompatActivity); } super.onDestroy(); } }
7.Activity文件。
package com.phone.base64_and_file; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.provider.Settings; import android.text.TextUtils; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.Toolbar; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.phone.base64_and_file.adapter.Base64StrAdapter; import com.phone.base64_and_file.bean.Base64AndFileBean; import com.phone.base64_and_file.presenter.Base64AndFilePresenterImpl; import com.phone.common_library.base.BaseMvpRxAppActivity; import com.phone.common_library.base.IBaseView; import com.phone.common_library.callback.OnCommonRxPermissionsCallback; import com.phone.common_library.manager.LogManager; import com.phone.common_library.manager.RxPermissionsManager; import com.phone.common_library.manager.SystemManager; import com.qmuiteam.qmui.widget.QMUILoadingView; import com.trello.rxlifecycle3.android.ActivityEvent; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.TimeUnit; import io.reactivex.Observable; import io.reactivex.ObservableEmitter; import io.reactivex.ObservableOnSubscribe; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.functions.Consumer; import io.reactivex.functions.Function; import io.reactivex.schedulers.Schedulers; public class Base64AndFileActivity extends BaseMvpRxAppActivityimplements IBase64AndFileView { private static final String TAG = Base64AndFileActivity.class.getSimpleName(); private Toolbar toolbar; private TextView tevTitle; private TextView tevRequestPermissions; private TextView tevCompressedPicture; private ImageView imvCompressedPicture; private TextView tevPictureToBase64; private RecyclerView rcvBase64Str; private TextView tevBase64ToPicture; private ImageView imvBase64ToPicture; private TextView tevResetData; private QMUILoadingView loadView; // where this is an Activity or Fragment instance // private Binder binder; private String dirsPath; private String dirsPathCompressed; private String dirsPathCompressedRecover; private List base64StrList = new ArrayList<>(); private LinearLayoutManager linearLayoutManager; private Base64StrAdapter base64StrAdapter; private Timer timer; private TimerTask timerTask; private Handler handler; private AlertDialog mPermissionsDialog; private Base64AndFileBean base64AndFileBean; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override protected int initLayoutId() { return R.layout.activity_base64_and_file; } @Override protected void initData() { dirsPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "Pictures"; dirsPathCompressed = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "PicturesCompressed"; dirsPathCompressedRecover = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "PicturesCompressedRecover"; base64AndFileBean = new Base64AndFileBean(); base64AndFileBean.setDirsPath(dirsPath); base64AndFileBean.setDirsPathCompressed(dirsPathCompressed); base64AndFileBean.setDirsPathCompressedRecover(dirsPathCompressedRecover); handler = new Handler(Looper.getMainLooper()); } @Override protected void initViews() { toolbar = (Toolbar) findViewById(R.id.toolbar); tevTitle = (TextView) findViewById(R.id.tev_title); tevRequestPermissions = (TextView) findViewById(R.id.tev_request_permissions); tevCompressedPicture = (TextView) findViewById(R.id.tev_compressed_picture); imvCompressedPicture = (ImageView) findViewById(R.id.imv_compressed_picture); tevPictureToBase64 = (TextView) findViewById(R.id.tev_picture_to_base64); rcvBase64Str = (RecyclerView) findViewById(R.id.rcv_base64_str); tevBase64ToPicture = (TextView) findViewById(R.id.tev_base64_to_picture); imvBase64ToPicture = (ImageView) findViewById(R.id.imv_base64_to_picture); tevResetData = (TextView) findViewById(R.id.tev_reset_data); loadView = (QMUILoadingView) findViewById(R.id.load_view); setToolbar(false, R.color.color_54E066FF); tevRequestPermissions.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { LogManager.i(TAG, "tevRequestPermissions"); initRxPermissionsRxAppCompatActivity(); } }); // tevCompressedPicture.setOnClickListener(new View.OnClickListener() { // @Override // public void onClick(View v) { // initRxPermissionsRxAppCompatActivity(); // } // }); // tevPictureToBase64.setOnClickListener(new View.OnClickListener() { // @Override // public void onClick(View v) { // if (presenter != null) { // showLoading(); // presenter.showPictureToBase64(compressedPicturePath); // } // } // }); // tevBase64ToPicture.setOnClickListener(new View.OnClickListener() { // @Override // public void onClick(View v) { // if (presenter != null) { // showLoading(); // presenter.showBase64ToPicture(compressedPicturePath, base64Str); // } // } // }); tevResetData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { resetData(); } }); initAdapter(); } private void initAdapter() { linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setOrientation(RecyclerView.VERTICAL); rcvBase64Str.setLayoutManager(linearLayoutManager); rcvBase64Str.setItemAnimator(new DefaultItemAnimator()); base64StrAdapter = new Base64StrAdapter(this); rcvBase64Str.setAdapter(base64StrAdapter); base64StrAdapter.clearData(); base64StrAdapter.addAllData(base64StrList); } @Override protected void initLoadData() { // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // initRxPermissions(); // } else { // Intent bindIntent = new Intent(this, Base64AndFileService.class); // 绑定服务和活动,之后活动就可以去调服务的方法了 bindService(bindIntent, connection, BIND_AUTO_CREATE); // } } @Override protected Base64AndFilePresenterImpl attachPresenter() { return new Base64AndFilePresenterImpl(this); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { } } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 207) { // initRxPermissions(); } } private void showSystemSetupDialog() { cancelPermissionsDialog(); if (mPermissionsDialog == null) { mPermissionsDialog = new AlertDialog.Builder(this) .setTitle("权限设置") .setMessage("获取相关权限失败,将导致部分功能无法正常使用,请到设置页面手动授权") .setPositiveButton("去授权", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { cancelPermissionsDialog(); intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", getApplicationContext().getPackageName(), null); intent.setData(uri); startActivityForResult(intent, 207); } }) .create(); } mPermissionsDialog.setCancelable(false); mPermissionsDialog.setCanceledOnTouchOutside(false); mPermissionsDialog.show(); } private void cancelPermissionsDialog() { if (mPermissionsDialog != null) { mPermissionsDialog.cancel(); mPermissionsDialog = null; } } private void initRxPermissionsRxAppCompatActivity() { RxPermissionsManager rxPermissionsManager = new RxPermissionsManager(); rxPermissionsManager.initRxPermissionsRxAppCompatActivity(this, new OnCommonRxPermissionsCallback() { @Override public void onRxPermissionsAllPass() { if (TextUtils.isEmpty(baseApplication.getSystemId())) { String systemId = SystemManager.getSystemId(baseApplication); baseApplication.setSystemId(systemId); LogManager.i(TAG, "isEmpty systemId*****" + baseApplication.getSystemId()); } else { LogManager.i(TAG, "systemId*****" + baseApplication.getSystemId()); } // //第一种方法 // if (presenter != null) { // showLoading(); // // presenter.showCompressedPicture(baseApplication, // base64AndFileBean); // } //第二种方法 initBase64AndFileTask(); } @Override public void onNotCheckNoMorePromptError() { showSystemSetupDialog(); } @Override public void onCheckNoMorePromptError() { showSystemSetupDialog(); } }); } private void initBase64AndFileTask() { Observable.create(new ObservableOnSubscribe () { @Override public void subscribe(ObservableEmitter emitter) throws Exception { LogManager.i(TAG, "threadName*****" + Thread.currentThread().getName()); showLoading(); emitter.onNext(0); } }).subscribeOn(AndroidSchedulers.mainThread()) //给上面分配了UI线程 // .observeOn(AndroidSchedulers.mainThread()) //给下面分配了UI线程 // .doOnNext(new Consumer () { // @Override // public void accept(Integer integer) throws Exception { // LogManager.i(TAG, "threadName*****" + Thread.currentThread().getName()); // showLoading(); // } // }) .observeOn(Schedulers.io()) //给下面分配了异步线程 .map(new Function () { @Override public Base64AndFileBean apply(Integer integer) throws Exception { LogManager.i(TAG, "threadName2*****" + Thread.currentThread().getName()); File file = BitmapManager.getAssetFile(baseApplication, dirsPath, "picture_large.png"); base64AndFileBean.setFile(file); return base64AndFileBean; } }) .observeOn(Schedulers.io()) //给下面分配了异步线程 .doOnNext(new Consumer () { @Override public void accept(Base64AndFileBean base64AndFileBean) throws Exception { LogManager.i(TAG, "threadName3*****" + Thread.currentThread().getName()); //把图片转化成bitmap Bitmap bitmap = BitmapManager.getBitmap(base64AndFileBean.getFile().getAbsolutePath()); base64AndFileBean.setBitmap(bitmap); } }) .observeOn(Schedulers.io()) //给下面分配了异步线程 .doOnNext(new Consumer () { @Override public void accept(Base64AndFileBean base64AndFileBean) throws Exception { LogManager.i(TAG, "threadName4*****" + Thread.currentThread().getName()); //再压缩bitmap Bitmap bitmapCompressed = BitmapManager.scaleImage(base64AndFileBean.getBitmap(), 1280, 960); base64AndFileBean.setBitmapCompressed(bitmapCompressed); } }) .observeOn(AndroidSchedulers.mainThread()) //给下面分配了异步线程 .doOnNext(new Consumer () { @Override public void accept(Base64AndFileBean base64AndFileBean) throws Exception { LogManager.i(TAG, "threadName5*****" + Thread.currentThread().getName()); //展示压缩过的图片 tevCompressedPicture.setVisibility(View.GONE); imvCompressedPicture.setVisibility(View.VISIBLE); imvCompressedPicture.setImageBitmap(base64AndFileBean.getBitmapCompressed()); } }) .observeOn(Schedulers.io()) //给下面分配了异步线程 .doOnNext(new Consumer () { @Override public void accept(Base64AndFileBean base64AndFileBean) throws Exception { LogManager.i(TAG, "threadName6*****" + Thread.currentThread().getName()); //再把压缩后的bitmap保存到本地 File fileCompressed = BitmapManager.saveFile(base64AndFileBean.getBitmapCompressed(), base64AndFileBean.getDirsPathCompressed(), "picture_large_compressed.png"); base64AndFileBean.setFileCompressed(fileCompressed); LogManager.i(TAG, "base64AndFileBean.getFileCompressed().getPath()*****" + base64AndFileBean.getFileCompressed().getPath()); LogManager.i(TAG, "base64AndFileBean.getFileCompressed().getAbsolutePath()*****" + base64AndFileBean.getFileCompressed().getAbsolutePath()); } }) .observeOn(Schedulers.io()) //给下面分配了异步线程 .doOnNext(new Consumer () { @Override public void accept(Base64AndFileBean base64AndFileBean) throws Exception { LogManager.i(TAG, "threadName7*****" + Thread.currentThread().getName()); String base64Str = null; if (base64AndFileBean.getFileCompressed().exists()) { base64Str = Base64AndFileManager.fileToBase64(base64AndFileBean.getFileCompressed()); // base64Str = Base64AndFileManager.fileToBase64Test(file); // base64Str = Base64AndFileManager.fileToBase64Second(file); base64AndFileBean.setBase64Str(base64Str); } if (!TextUtils.isEmpty(base64Str)) { String fileName = "base64Str.txt"; String txtFilePath = FileManager.writeStrToTextFile(base64Str, base64AndFileBean.getDirsPathCompressed(), fileName); base64AndFileBean.setTxtFilePath(txtFilePath); base64AndFileBean.setBase64StrList(Base64AndFileManager.getBase64StrList(txtFilePath)); // base64Str = ""; // StringBuilder stringBuilder = new StringBuilder(); // for (int i = 0; i < base64StrList.size(); i++) { // stringBuilder.append(base64StrList.get(i)); // } // base64Str = stringBuilder.toString(); // //把字符串的最後一個打印出來,然後看看和RecyclerView顯示的最後一個字符串是否一致 // LogManager.i(TAG, "base64StrList******" + base64StrList.get(base64StrList.size() - 1)); } } }) .observeOn(AndroidSchedulers.mainThread()) //给下面分配了异步线程 .doOnNext(new Consumer () { @Override public void accept(Base64AndFileBean base64AndFileBean) throws Exception { LogManager.i(TAG, "threadName8*****" + Thread.currentThread().getName()); tevPictureToBase64.setVisibility(View.GONE); rcvBase64Str.setVisibility(View.VISIBLE); base64StrAdapter.clearData(); base64StrAdapter.addAllData(base64AndFileBean.getBase64StrList()); Observable.timer(2000, TimeUnit.MILLISECONDS) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) //解决RxJava2导致的内存泄漏问题 .compose(bindUntilEvent(ActivityEvent.DESTROY)) .subscribe(new Consumer () { @Override public void accept(Long aLong) throws Exception { LogManager.i(TAG, "threadNameC*****" + Thread.currentThread().getName()); if (base64AndFileBean.getBase64StrList().size() > 0) { //RecyclerView自動滑動到底部,看看最後一個字符串和打印出來的字符串是否一致 rcvBase64Str.scrollToPosition(base64AndFileBean.getBase64StrList().size() - 1); } } }); } }) .observeOn(Schedulers.io()) //给下面分配了异步线程 .doOnNext(new Consumer () { @Override public void accept(Base64AndFileBean base64AndFileBean) throws Exception { LogManager.i(TAG, "threadName9*****" + Thread.currentThread().getName()); //再把压缩后的bitmap保存到本地 File fileCompressedRecover = Base64AndFileManager.base64ToFile(base64AndFileBean.getBase64Str(), base64AndFileBean.getDirsPathCompressedRecover(), "picture_large_compressed_recover"); base64AndFileBean.setFileCompressedRecover(fileCompressedRecover); } }) .observeOn(Schedulers.io()) //给下面分配了异步线程 // .doOnNext(new Consumer () { // @Override // public void accept(Base64AndFileBean base64AndFileBean) throws Exception { // LogManager.i(TAG, "threadName10*****" + Thread.currentThread().getName()); // Bitmap bitmapCompressedRecover = BitmapFactory.decodeFile(base64AndFileBean.getFileCompressedRecover().getAbsolutePath()); // base64AndFileBean.setBitmapCompressedRecover(bitmapCompressedRecover); // } // }) .map(new Function () { @Override public Bitmap apply(Base64AndFileBean base64AndFileBean) throws Exception { LogManager.i(TAG, "threadName10*****" + Thread.currentThread().getName()); Bitmap bitmapCompressedRecover = BitmapFactory.decodeFile(base64AndFileBean.getFileCompressedRecover().getAbsolutePath()); return bitmapCompressedRecover; } }) .observeOn(AndroidSchedulers.mainThread()) //给下面分配了UI线程 //解决RxJava2导致的内存泄漏问题 .compose(bindUntilEvent(ActivityEvent.DESTROY)) .subscribe(new Consumer () { @Override public void accept(Bitmap bitmapCompressedRecover) throws Exception { LogManager.i(TAG, "threadName11*****" + Thread.currentThread().getName()); tevBase64ToPicture.setVisibility(View.GONE); imvBase64ToPicture.setVisibility(View.VISIBLE); imvBase64ToPicture.setImageBitmap(bitmapCompressedRecover); base64AndFileBean.setBitmapCompressedRecover(bitmapCompressedRecover); hideLoading(); } }); } @Override public void showLoading() { if (loadView != null && !loadView.isShown()) { loadView.setVisibility(View.VISIBLE); loadView.start(); } } @Override public void hideLoading() { if (loadView != null && loadView.isShown()) { loadView.stop(); loadView.setVisibility(View.GONE); } } // private ServiceConnection connection = new ServiceConnection() { // // // @Override // public void onServiceDisconnected(ComponentName name) { // } // // // @Override // public void onServiceConnected(ComponentName name, IBinder service) { // taskBinder = (TaskBinder) service; // } // }; // private Base64AndFileServiceConnection connection = new Base64AndFileServiceConnection(new OnCommonSingleParamCallback () { // @Override // public void onSuccess(Binder success) { // binder = success; // } // // @Override // public void onError(String error) { // // } // }); private void startTimer() { stopTimer(); if (timer == null) { timer = new Timer(); } if (timerTask == null) { timerTask = new TimerTask() { @Override public void run() { handler.post(new Runnable() { @Override public void run() { if (base64StrList.size() > 0) { //RecyclerView自動滑動到底部,看看最後一個字符串和打印出來的字符串是否一致 rcvBase64Str.scrollToPosition(base64StrList.size() - 1); } } }); } }; } if (timer != null && timerTask != null) { timer.schedule(timerTask, 500); } } private void stopTimer() { if (timer != null) { timer.cancel(); timer = null; } if (timerTask != null) { timerTask.cancel(); timerTask = null; } } @Override public void showCompressedPictureSuccess(Base64AndFileBean success) { base64AndFileBean = success; tevCompressedPicture.setVisibility(View.GONE); imvCompressedPicture.setVisibility(View.VISIBLE); imvCompressedPicture.setImageBitmap(base64AndFileBean.getBitmapCompressed()); hideLoading(); LogManager.i(TAG, "showCompressedPictureSuccess"); if (presenter != null) { showLoading(); presenter.showPictureToBase64(base64AndFileBean); } } @Override public void showCompressedPictureError(String error) { hideLoading(); Toast.makeText(this, error, Toast.LENGTH_SHORT).show(); } @Override public void showPictureToBase64Success(Base64AndFileBean success) { base64AndFileBean = success; tevPictureToBase64.setVisibility(View.GONE); rcvBase64Str.setVisibility(View.VISIBLE); this.base64StrList.clear(); this.base64StrList.addAll(base64AndFileBean.getBase64StrList()); base64StrAdapter.clearData(); base64StrAdapter.addAllData(this.base64StrList); hideLoading(); startTimer(); if (presenter != null) { showLoading(); presenter.showBase64ToPicture(success); } } @Override public void showPictureToBase64Error(String error) { hideLoading(); Toast.makeText(this, error, Toast.LENGTH_SHORT).show(); } @Override public void showBase64ToPictureSuccess(Base64AndFileBean success) { base64AndFileBean = success; tevBase64ToPicture.setVisibility(View.GONE); imvBase64ToPicture.setVisibility(View.VISIBLE); imvBase64ToPicture.setImageBitmap(success.getBitmap()); hideLoading(); } @Override public void showBase64ToPictureError(String error) { hideLoading(); Toast.makeText(this, error, Toast.LENGTH_SHORT).show(); resetData(); } private void resetData() { if (base64AndFileBean.getBitmap() != null && !base64AndFileBean.getBitmap().isRecycled()) { base64AndFileBean.getBitmap().recycle(); base64AndFileBean.setBitmap(null); } if (base64AndFileBean.getBitmapCompressed() != null && !base64AndFileBean.getBitmapCompressed().isRecycled()) { base64AndFileBean.getBitmapCompressed().recycle(); base64AndFileBean.setBitmapCompressed(null); } if (base64AndFileBean.getBitmapCompressedRecover() != null && !base64AndFileBean.getBitmapCompressedRecover().isRecycled()) { base64AndFileBean.getBitmapCompressedRecover().recycle(); base64AndFileBean.setBitmapCompressedRecover(null); } tevCompressedPicture.setVisibility(View.VISIBLE); imvCompressedPicture.setVisibility(View.GONE); tevPictureToBase64.setVisibility(View.VISIBLE); if (base64StrList.size() > 0) { rcvBase64Str.scrollToPosition(0); base64StrList.clear(); base64StrAdapter.clearData(); } rcvBase64Str.setVisibility(View.GONE); tevBase64ToPicture.setVisibility(View.VISIBLE); imvBase64ToPicture.setVisibility(View.GONE); } @Override protected void onDestroy() { stopTimer(); if (base64AndFileBean.getBitmap() != null && !base64AndFileBean.getBitmap().isRecycled()) { base64AndFileBean.getBitmap().recycle(); base64AndFileBean.setBitmap(null); } if (base64AndFileBean.getBitmapCompressed() != null && !base64AndFileBean.getBitmapCompressed().isRecycled()) { base64AndFileBean.getBitmapCompressed().recycle(); base64AndFileBean.setBitmapCompressed(null); } if (base64AndFileBean.getBitmapCompressedRecover() != null && !base64AndFileBean.getBitmapCompressedRecover().isRecycled()) { base64AndFileBean.getBitmapCompressedRecover().recycle(); base64AndFileBean.setBitmapCompressedRecover(null); } // if (connection != null) { // // 解绑服务,服务要记得解绑,不要造成内存泄漏 // unbindService(connection); // binder = null; // } super.onDestroy(); } }
8.Activity的layout文件。
9.values下的string的xml文件。
Base64AndFile
請求權限
如对此有疑问,请联系qq1164688204。
推荐Android开源项目
项目功能介绍:RxJava2和Retrofit2项目,添加自动管理token功能,添加RxJava2生命周期管理,使用App架构设计是MVP模式和MVVM模式,同时使用组件化,部分代码使用Kotlin,此项目持续维护中。
项目地址:https://gitee.com/urasaki/RxJava2AndRetrofit2



