[Modify]圖片保存到本地適配

This commit is contained in:
wushaocheng
2022-12-20 18:44:30 +08:00
parent 8e872341fd
commit bec7657d43
8 changed files with 523 additions and 63 deletions

View File

@@ -106,6 +106,7 @@ import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
@@ -1461,6 +1462,20 @@ public class GiftDialog extends BottomSheetDialog implements View.OnClickListene
return;
}
for (List<GiftInfoVm> page : pagerList) {
// Iterator<GiftInfoVm> iterator = page.iterator();
// while (iterator.hasNext()) {
// GiftInfoVm item = iterator.next();
// if (item.data.getGiftId() == giftId) {
// int count = item.data.getCount() - sendNum;
// if(count == 0){
// iterator.remove();
// }else {
// item.data.setCount(Math.max(count, 0));
// item.updateCount();
// }
// break;
// }
// }
for (GiftInfoVm item : page) {
if (item.data.getGiftId() == giftId) {
int count = item.data.getCount() - sendNum;

View File

@@ -2,7 +2,6 @@ package com.yizhuan.erban.community.photo;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
@@ -12,18 +11,19 @@ import com.yizhuan.erban.R;
import com.yizhuan.erban.base.BaseActivity;
import com.yizhuan.erban.ui.widget.ButtonItem;
import com.yizhuan.erban.ui.widget.OnPageSelectedListener;
import com.yizhuan.xchat_android_core.community.download.DownloadModel;
import com.yizhuan.xchat_android_core.utils.DirectoryHelper;
import com.yizhuan.xchat_android_library.common.util.AlbumUtils;
import com.yizhuan.xchat_android_library.common.util.ExecutorCenter;
import com.yizhuan.xchat_android_library.utils.ResUtil;
import com.zhihu.matisse.internal.entity.CustomItem;
import com.zhihu.matisse.internal.ui.widget.PreviewViewPager;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
/**
* create by lvzebiao @2019/11/20
@@ -155,36 +155,18 @@ public class BigPhotoActivity extends BaseActivity implements OnFragmentOptionLi
if (item == null) {
return;
}
String format = item.getFormat();
if (format == null) {
format = ".jpg";
}
format = format.toLowerCase();
if (format.equals("jpeg")) {
format = ".jpg";
} else {
format = "." + format;
}
String fileName = "dynamic_" + System.currentTimeMillis() + format;
File dir = DirectoryHelper.get().getAppAlubmDir();
if (dir == null) {
toast(ResUtil.getString(R.string.community_photo_bigphotoactivity_03));
return;
}
LogUtil.print(ResUtil.getString(R.string.community_photo_bigphotoactivity_04));
LogUtil.print(dir);
LogUtil.print(fileName);
DownloadModel.get().download(
item.getPath(), dir.getPath(), fileName)
.doOnSuccess(s -> {
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(new File(dir, fileName));
intent.setData(uri);
sendBroadcast(intent);
toast(ResUtil.getString(R.string.community_photo_bigphotoactivity_05));
})
.doOnError(throwable -> toast(ResUtil.getString(R.string.community_photo_bigphotoactivity_06)))
.subscribe();
ExecutorCenter.getInstance().post(() -> {
AlbumUtils.INSTANCE.addUrlToAlbum(context, item.getPath(), new Function1<Boolean, Unit>() {
@Override
public Unit invoke(Boolean aBoolean) {
if (aBoolean) {
toast(ResUtil.getString(R.string.community_photo_bigphotoactivity_05));
}
return null;
}
});
});
}));
getDialogManager().showCommonPopupDialog(listBtn, ResUtil.getString(R.string.community_photo_bigphotoactivity_07));

View File

@@ -0,0 +1,313 @@
package com.yizhuan.xchat_android_library.common.util
import android.content.ContentValues
import android.content.Context
import android.graphics.Bitmap
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.yizhuan.xchat_android_library.common.application.BaseApp
import com.yizhuan.xchat_android_library.common.file.FileHelper
import com.yizhuan.xchat_android_library.common.glide.GlideUtils
import java.io.*
/**
* create by ysx 2020/9/25 0025
*文件工具类,为了适配android10,11
*/
object AlbumUtils {
/**
* 兼容android Q
* 网络图片保存本地
* 返回是否保存成功
*/
fun addUrlToAlbum(context: Context?, url: String?, callback: (Boolean) -> Unit) {
if (url == null) {
callback.invoke(false)
return
}
getGlideImagePath(context, url) { glideImagePath ->
glideImagePath?.also {
val fileName: String
val imageType: String
if (glideImagePath.endsWith(".gif", true)) {
fileName = System.currentTimeMillis().toString() + ".gif"
imageType = "image/gif"
} else {
fileName = System.currentTimeMillis().toString() + ".jpg"
imageType = "image/jpeg"
}
val values = ContentValues()
values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
values.put(MediaStore.MediaColumns.MIME_TYPE, imageType)
values.put(MediaStore.MediaColumns.SIZE, 1)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
} else {
values.put(
MediaStore.MediaColumns.DATA,
"${Environment.getExternalStorageDirectory().path}/${Environment.DIRECTORY_DCIM}/$fileName"
)
}
val contentResolver = BaseApp.getContext().contentResolver
val uri =
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
if (uri != null) {
try {
val oldFile = File(glideImagePath)
if (oldFile.exists()) { //文件存在时
val inStream = FileInputStream(glideImagePath) //读入原文件
val outputStream = contentResolver.openOutputStream(uri)
if (outputStream != null) {
val bos = BufferedOutputStream(outputStream)
val buffer = ByteArray(1024)
var bytes = inStream.read(buffer)
while (bytes >= 0) {
bos.write(buffer, 0, bytes)
bos.flush()
bytes = inStream.read(buffer)
}
bos.close()
callback.invoke(true)
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
callback.invoke(false)
}
/**
* 兼容android Q
* 将bitmap保存到本地图库
* displayName 文件名 "xxx.jpg"
* mimeType "image/jpeg"
*/
@JvmOverloads
@JvmStatic
fun addBitmapToAlbum(
bitmap: Bitmap?,
displayName: String = "${System.currentTimeMillis()}.jpg",
mimeType: String = "image/jpeg",
compressFormat: Bitmap.CompressFormat = Bitmap.CompressFormat.JPEG
): Boolean {
if (bitmap == null) return false
val values = ContentValues()
values.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName)
values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
} else {
values.put(
MediaStore.MediaColumns.DATA,
"${Environment.getExternalStorageDirectory().path}/${Environment.DIRECTORY_DCIM}/$displayName"
)
}
var outputStream: OutputStream? = null
try {
val contentResolver = BaseApp.getContext().contentResolver
val uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
if (uri != null) {
outputStream = contentResolver.openOutputStream(uri)
if (outputStream != null) {
bitmap.compress(compressFormat, 100, outputStream)
return true
}
}
} catch (e: Exception) {
} finally {
try {
outputStream?.close()
} catch (ex: Exception) {
}
}
return false
}
/**
* 兼容android Q
* 本地缓存文件保存本地相册
* 返回是否保存成功
*/
fun addImageFileToAlbum(file: File?): Boolean {
if (file == null) return false
val start: Int = file.name.lastIndexOf(".")
val suffix: String = file.name.substring(start + 1)
val fileName: String
val imageType: String
if (suffix == "gif" || suffix == "GIF") {
fileName = System.currentTimeMillis().toString() + ".gif"
imageType = "image/gif"
} else {
fileName = System.currentTimeMillis().toString() + ".jpg"
imageType = "image/jpeg"
}
val values = ContentValues()
values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
values.put(MediaStore.MediaColumns.MIME_TYPE, imageType)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
} else {
values.put(
MediaStore.MediaColumns.DATA,
"${Environment.getExternalStorageDirectory().path}/${Environment.DIRECTORY_DCIM}/$fileName"
)
}
val contentResolver = BaseApp.getContext().contentResolver
val uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
if (uri != null) {
var inStream: FileInputStream? = null
var outputStream: OutputStream? = null
var bos: BufferedOutputStream? = null
try {
if (file.exists()) { //文件存在时
inStream = FileInputStream(file) //读入原文件
outputStream = contentResolver.openOutputStream(uri)
if (outputStream != null) {
bos = BufferedOutputStream(outputStream)
val buffer = ByteArray(1024)
var bytes = inStream.read(buffer)
while (bytes >= 0) {
bos.write(buffer, 0, bytes)
bos.flush()
bytes = inStream.read(buffer)
}
return true
}
}
} catch (e: Exception) {
} finally {
try {
inStream?.close()
} catch (ex: Exception) {
}
try {
outputStream?.close()
} catch (ex: Exception) {
}
try {
bos?.close()
} catch (ex: Exception) {
}
}
}
return false
}
/**
* Glide 获得图片路径
*/
private fun getGlideImagePath(context: Context?, imgUrl: String, callback: (String?) -> Unit) {
try {
GlideUtils.instance().downloadFromUrl(context, imgUrl, object : RequestListener<File?> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<File?>?,
isFirstResource: Boolean
): Boolean {
callback.invoke("")
return false
}
override fun onResourceReady(
resource: File?,
model: Any?,
target: Target<File?>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
callback.invoke(resource?.absolutePath)
return false
}
})
} catch (e: Exception) {
callback.invoke("")
}
}
/**
* 动态获得h5图片路径
*/
fun getTrendImagePath(context: Context?, imgUrl: String, callback: (String?) -> Unit) {
try {
GlideUtils.instance().downloadFromUrl(context, imgUrl, object : RequestListener<File?> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<File?>?,
isFirstResource: Boolean
): Boolean {
callback.invoke("")
return false
}
override fun onResourceReady(
resource: File?,
model: Any?,
target: Target<File?>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
val fileDir =
FileHelper.getRootFilesDir(Environment.DIRECTORY_PICTURES).absolutePath + "/trend/test"
//获取到下载得到的图片,进行本地保存
//第二个参数为你想要保存的目录名称
val appDir = File(fileDir)
if (!appDir.exists()) {
appDir.mkdirs()
}
val fileName = System.currentTimeMillis().toString() + ".jpg"
val destFile = File(appDir, fileName)
//把gilde下载得到图片复制到定义好的目录中去
copy(resource, destFile) {
callback.invoke(destFile.absolutePath)
}
return false
}
})
} catch (e: Exception) {
callback.invoke("")
}
}
/**
* 复制文件
*
* @param source 输入文件
* @param target 输出文件
*/
fun copy(source: File?, target: File?, callback: () -> Unit) {
var fileInputStream: FileInputStream? = null
var fileOutputStream: FileOutputStream? = null
try {
fileInputStream = FileInputStream(source)
fileOutputStream = FileOutputStream(target)
val buffer = ByteArray(1024)
while (fileInputStream.read(buffer) > 0) {
fileOutputStream.write(buffer)
}
} catch (e: java.lang.Exception) {
e.printStackTrace()
} finally {
try {
fileInputStream?.close()
fileOutputStream?.close()
callback.invoke()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
}

View File

@@ -0,0 +1,57 @@
package com.yizhuan.xchat_android_library.common.util;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
public class ExecutorCenter {
private static final String TAG = "ExecutorCenter";
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static ExecutorCenter msInstance = null;
private static ScheduledExecutor mExecutor;
public static ExecutorCenter getInstance() {
if (null != msInstance) return msInstance;
synchronized (ExecutorCenter.class) {
if (null != msInstance) return msInstance;
msInstance = new ExecutorCenter();
return msInstance;
}
}
private ExecutorCenter() {
mExecutor = Pools.newScheduledThreadPoolExecutor("self-executor", CPU_COUNT + 1);
}
public Executor getExecutor() {
return mExecutor;
}
public void post(Runnable runnable) {
if (this.checkNull(runnable)) {
return;
}
mExecutor.execute(runnable);
}
public void postDelay(Runnable runnable, long delay) {
if (this.checkNull(runnable)) {
return;
}
mExecutor.execute(runnable, delay);
}
public Future submitDelay(Runnable runnable, long delay) {
if (this.checkNull(runnable)) {
return null;
}
return mExecutor.submit(runnable, delay);
}
private boolean checkNull(Runnable runnable) {
if (null == runnable) {
Logger.error(TAG, "runnable null!!!!");
return true;
}
return false;
}
}

View File

@@ -0,0 +1,36 @@
package com.yizhuan.xchat_android_library.common.util;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class Pools {
private static final String TAG = "Pools";
public static ScheduledExecutor newScheduledThreadPoolExecutor(String threadNamePrefix, int coreCount) {
return new ScheduledExecutorAdapter(new ScheduledThreadPoolExecutor(coreCount, new DefaultThreadFactory(threadNamePrefix)) {
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t != null) {
Logger.error(TAG, String.valueOf(t));
}
}
});
}
private static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory(String threadNamePrefix) {
this.namePrefix = threadNamePrefix + poolNumber.getAndIncrement() + "-thread-";
}
@Override
public Thread newThread(Runnable r) {
return new Thread(r, this.namePrefix + this.threadNumber.getAndIncrement());
}
}
}

View File

@@ -0,0 +1,11 @@
package com.yizhuan.xchat_android_library.common.util;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
public interface ScheduledExecutor extends Executor {
void execute(Runnable runnable, long delay);
Future submit(Runnable runnable, long delay);
}

View File

@@ -0,0 +1,34 @@
package com.yizhuan.xchat_android_library.common.util;
import androidx.annotation.NonNull;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledExecutorAdapter implements ScheduledExecutor {
private ScheduledExecutorService mExecutor;
public ScheduledExecutorAdapter(ScheduledExecutorService executor) {
if (null == executor) {
throw new NullPointerException("ScheduledThreadPoolExecutor may not be null");
}
this.mExecutor = executor;
}
@Override
public void execute(Runnable command, long delay) {
this.mExecutor.schedule(command, delay, TimeUnit.MILLISECONDS);
}
@Override
public void execute(@NonNull Runnable command) {
this.mExecutor.execute(command);
}
@Override
public Future submit(Runnable command, long delay) {
return this.mExecutor.schedule(command, delay, TimeUnit.MILLISECONDS);
}
}

View File

@@ -1,13 +1,11 @@
package com.netease.nim.uikit.business.session.activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
@@ -29,11 +27,8 @@ import com.netease.nim.uikit.common.ui.dialog.CustomAlertDialog;
import com.netease.nim.uikit.common.ui.dialog.CustomAlertDialog.onSeparateItemClickListener;
import com.netease.nim.uikit.common.ui.imageview.BaseZoomableImageView;
import com.netease.nim.uikit.common.ui.imageview.ImageGestureListener;
import com.netease.nim.uikit.common.util.C;
import com.netease.nim.uikit.common.util.file.AttachmentStore;
import com.netease.nim.uikit.common.util.media.BitmapDecoder;
import com.netease.nim.uikit.common.util.media.ImageUtil;
import com.netease.nim.uikit.common.util.storage.StorageUtil;
import com.netease.nim.uikit.common.util.sys.TimeUtil;
import com.netease.nimlib.sdk.AbortableFuture;
import com.netease.nimlib.sdk.NIMClient;
@@ -47,6 +42,8 @@ import com.netease.nimlib.sdk.msg.constant.AttachStatusEnum;
import com.netease.nimlib.sdk.msg.constant.MsgDirectionEnum;
import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum;
import com.netease.nimlib.sdk.msg.model.IMMessage;
import com.yizhuan.xchat_android_library.common.util.AlbumUtils;
import com.yizhuan.xchat_android_library.common.util.ExecutorCenter;
import com.yizhuan.xchat_android_library.utils.ResUtil;
import com.yizhuan.xchat_android_library.utils.SingleToastUtil;
@@ -55,6 +52,9 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
/**
* 查看聊天消息原图
@@ -222,7 +222,7 @@ public class WatchMessagePictureActivity extends UI {
@Override
public void onSuccess(List<IMMessage> param) {
for (IMMessage imMessage : param) {
if (!ImageUtil.isGif(((ImageAttachment) imMessage.getAttachment()).getExtension())){
if (!ImageUtil.isGif(((ImageAttachment) imMessage.getAttachment()).getExtension())) {
imageMsgList.add(imMessage);
}
}
@@ -558,29 +558,41 @@ public class WatchMessagePictureActivity extends UI {
return;
}
String srcFilename = attachment.getFileName();
//默认jpg
String extension = TextUtils.isEmpty(attachment.getExtension()) ? "jpg" : attachment.getExtension();
srcFilename += ("." + extension);
ExecutorCenter.getInstance().post(() -> {
AlbumUtils.INSTANCE.addUrlToAlbum(this, path, new Function1<Boolean, Unit>() {
@Override
public Unit invoke(Boolean aBoolean) {
if (aBoolean) {
SingleToastUtil.showToastShort(R.string.picture_save_to);
}
return null;
}
});
});
String picPath = StorageUtil.getSystemImagePath();
String dstPath = picPath + srcFilename;
if (AttachmentStore.copy(path, dstPath) != -1) {
try {
ContentValues values = new ContentValues(2);
values.put(MediaStore.Images.Media.MIME_TYPE, C.MimeType.MIME_JPEG);
values.put(MediaStore.Images.Media.DATA, dstPath);
getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
// Toast.makeText(WatchMessagePictureActivity.this, getString(R.string.picture_save_to), Toast.LENGTH_LONG).show();
SingleToastUtil.showToastShort(R.string.picture_save_to);
} catch (Exception e) {
// may be java.lang.UnsupportedOperationException
// Toast.makeText(WatchMessagePictureActivity.this, getString(R.string.picture_save_fail), Toast.LENGTH_LONG).show();
SingleToastUtil.showToastShort(R.string.picture_save_fail);
}
} else {
// Toast.makeText(WatchMessagePictureActivity.this, getString(R.string.picture_save_fail), Toast.LENGTH_LONG).show();
SingleToastUtil.showToastShort(R.string.picture_save_fail);
}
// String srcFilename = attachment.getFileName();
// //默认jpg
// String extension = TextUtils.isEmpty(attachment.getExtension()) ? "jpg" : attachment.getExtension();
// srcFilename += ("." + extension);
//
// String picPath = StorageUtil.getSystemImagePath();
// String dstPath = picPath + srcFilename;
// if (AttachmentStore.copy(path, dstPath) != -1) {
// try {
// ContentValues values = new ContentValues(2);
// values.put(MediaStore.Images.Media.MIME_TYPE, C.MimeType.MIME_JPEG);
// values.put(MediaStore.Images.Media.DATA, dstPath);
// getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
//// Toast.makeText(WatchMessagePictureActivity.this, getString(R.string.picture_save_to), Toast.LENGTH_LONG).show();
// SingleToastUtil.showToastShort(R.string.picture_save_to);
// } catch (Exception e) {
// // may be java.lang.UnsupportedOperationException
//// Toast.makeText(WatchMessagePictureActivity.this, getString(R.string.picture_save_fail), Toast.LENGTH_LONG).show();
// SingleToastUtil.showToastShort(R.string.picture_save_fail);
// }
// } else {
//// Toast.makeText(WatchMessagePictureActivity.this, getString(R.string.picture_save_fail), Toast.LENGTH_LONG).show();
// SingleToastUtil.showToastShort(R.string.picture_save_fail);
// }
}
}