mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-08 15:57:29 +00:00
Memory efficient bitmap decoding in DownloadWorker. Fixes austinhuang0131/barinsta#930.
This commit is contained in:
parent
b2822b27a1
commit
d819928eb3
@ -127,47 +127,9 @@ public final class BitmapUtils {
|
|||||||
final boolean addToCache,
|
final boolean addToCache,
|
||||||
final ThumbnailLoadCallback callback) {
|
final ThumbnailLoadCallback callback) {
|
||||||
if (contentResolver == null || uri == null || callback == null) return;
|
if (contentResolver == null || uri == null || callback == null) return;
|
||||||
final ListenableFuture<BitmapResult> future = appExecutors.tasksThread().submit(() -> {
|
final ListenableFuture<BitmapResult> future = appExecutors
|
||||||
BitmapFactory.Options bitmapOptions;
|
.tasksThread()
|
||||||
float actualReqWidth = reqWidth;
|
.submit(() -> getBitmapResult(contentResolver, uri, reqWidth, reqHeight, maxDimenSize, addToCache));
|
||||||
float actualReqHeight = reqHeight;
|
|
||||||
try (InputStream input = contentResolver.openInputStream(uri)) {
|
|
||||||
BitmapFactory.Options outBounds = new BitmapFactory.Options();
|
|
||||||
outBounds.inJustDecodeBounds = true;
|
|
||||||
outBounds.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
|
||||||
BitmapFactory.decodeStream(input, null, outBounds);
|
|
||||||
if ((outBounds.outWidth == -1) || (outBounds.outHeight == -1)) return null;
|
|
||||||
bitmapOptions = new BitmapFactory.Options();
|
|
||||||
if (maxDimenSize > 0) {
|
|
||||||
// Raw height and width of image
|
|
||||||
final int height = outBounds.outHeight;
|
|
||||||
final int width = outBounds.outWidth;
|
|
||||||
final float ratio = (float) width / height;
|
|
||||||
if (height > width) {
|
|
||||||
actualReqHeight = maxDimenSize;
|
|
||||||
actualReqWidth = actualReqHeight * ratio;
|
|
||||||
} else {
|
|
||||||
actualReqWidth = maxDimenSize;
|
|
||||||
actualReqHeight = actualReqWidth / ratio;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bitmapOptions.inSampleSize = calculateInSampleSize(outBounds, actualReqWidth, actualReqHeight);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "loadBitmap: ", e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try (InputStream input = contentResolver.openInputStream(uri)) {
|
|
||||||
bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
|
||||||
Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
|
|
||||||
if (addToCache) {
|
|
||||||
addBitmapToMemoryCache(uri.toString(), bitmap, true);
|
|
||||||
}
|
|
||||||
return new BitmapResult(bitmap, (int) actualReqWidth, (int) actualReqHeight);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "loadBitmap: ", e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
Futures.addCallback(future, new FutureCallback<BitmapResult>() {
|
Futures.addCallback(future, new FutureCallback<BitmapResult>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(@Nullable final BitmapResult result) {
|
public void onSuccess(@Nullable final BitmapResult result) {
|
||||||
@ -185,8 +147,56 @@ public final class BitmapUtils {
|
|||||||
}, callbackHandlers);
|
}, callbackHandlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class BitmapResult {
|
@Nullable
|
||||||
Bitmap bitmap;
|
public static BitmapResult getBitmapResult(final ContentResolver contentResolver,
|
||||||
|
final Uri uri,
|
||||||
|
final float reqWidth,
|
||||||
|
final float reqHeight,
|
||||||
|
final float maxDimenSize,
|
||||||
|
final boolean addToCache) {
|
||||||
|
BitmapFactory.Options bitmapOptions;
|
||||||
|
float actualReqWidth = reqWidth;
|
||||||
|
float actualReqHeight = reqHeight;
|
||||||
|
try (InputStream input = contentResolver.openInputStream(uri)) {
|
||||||
|
BitmapFactory.Options outBounds = new BitmapFactory.Options();
|
||||||
|
outBounds.inJustDecodeBounds = true;
|
||||||
|
outBounds.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
||||||
|
BitmapFactory.decodeStream(input, null, outBounds);
|
||||||
|
if ((outBounds.outWidth == -1) || (outBounds.outHeight == -1)) return null;
|
||||||
|
bitmapOptions = new BitmapFactory.Options();
|
||||||
|
if (maxDimenSize > 0) {
|
||||||
|
// Raw height and width of image
|
||||||
|
final int height = outBounds.outHeight;
|
||||||
|
final int width = outBounds.outWidth;
|
||||||
|
final float ratio = (float) width / height;
|
||||||
|
if (height > width) {
|
||||||
|
actualReqHeight = maxDimenSize;
|
||||||
|
actualReqWidth = actualReqHeight * ratio;
|
||||||
|
} else {
|
||||||
|
actualReqWidth = maxDimenSize;
|
||||||
|
actualReqHeight = actualReqWidth / ratio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bitmapOptions.inSampleSize = calculateInSampleSize(outBounds, actualReqWidth, actualReqHeight);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "loadBitmap: ", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try (InputStream input = contentResolver.openInputStream(uri)) {
|
||||||
|
bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
||||||
|
Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
|
||||||
|
if (addToCache) {
|
||||||
|
addBitmapToMemoryCache(uri.toString(), bitmap, true);
|
||||||
|
}
|
||||||
|
return new BitmapResult(bitmap, (int) actualReqWidth, (int) actualReqHeight);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "loadBitmap: ", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BitmapResult {
|
||||||
|
public Bitmap bitmap;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ import android.content.ContentResolver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.media.MediaMetadataRetriever;
|
import android.media.MediaMetadataRetriever;
|
||||||
import android.media.MediaScannerConnection;
|
import android.media.MediaScannerConnection;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@ -16,6 +15,7 @@ import android.os.Looper;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
import androidx.core.content.FileProvider;
|
import androidx.core.content.FileProvider;
|
||||||
@ -33,7 +33,6 @@ import java.io.BufferedInputStream;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -48,14 +47,17 @@ import java.util.concurrent.ExecutionException;
|
|||||||
import awais.instagrabber.BuildConfig;
|
import awais.instagrabber.BuildConfig;
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
import awais.instagrabber.services.DeleteImageIntentService;
|
import awais.instagrabber.services.DeleteImageIntentService;
|
||||||
|
import awais.instagrabber.utils.BitmapUtils;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
import awais.instagrabber.utils.DownloadUtils;
|
import awais.instagrabber.utils.DownloadUtils;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
import awais.instagrabber.utils.Utils;
|
import awais.instagrabber.utils.Utils;
|
||||||
//import awaisomereport.LogCollector;
|
|
||||||
|
|
||||||
|
import static awais.instagrabber.utils.BitmapUtils.THUMBNAIL_SIZE;
|
||||||
import static awais.instagrabber.utils.Constants.DOWNLOAD_CHANNEL_ID;
|
import static awais.instagrabber.utils.Constants.DOWNLOAD_CHANNEL_ID;
|
||||||
import static awais.instagrabber.utils.Constants.NOTIF_GROUP_NAME;
|
import static awais.instagrabber.utils.Constants.NOTIF_GROUP_NAME;
|
||||||
|
|
||||||
|
//import awaisomereport.LogCollector;
|
||||||
//import static awais.instagrabber.utils.Utils.logCollector;
|
//import static awais.instagrabber.utils.Utils.logCollector;
|
||||||
|
|
||||||
public class DownloadWorker extends Worker {
|
public class DownloadWorker extends Worker {
|
||||||
@ -253,40 +255,7 @@ public class DownloadWorker extends Worker {
|
|||||||
MediaScannerConnection.scanFile(context, new String[]{file.getAbsolutePath()}, null, null);
|
MediaScannerConnection.scanFile(context, new String[]{file.getAbsolutePath()}, null, null);
|
||||||
final Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file);
|
final Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file);
|
||||||
final ContentResolver contentResolver = context.getContentResolver();
|
final ContentResolver contentResolver = context.getContentResolver();
|
||||||
Bitmap bitmap = null;
|
final Bitmap bitmap = getThumbnail(context, file, uri, contentResolver);
|
||||||
final String mimeType = Utils.getMimeType(uri, contentResolver);
|
|
||||||
if (!TextUtils.isEmpty(mimeType)) {
|
|
||||||
if (mimeType.startsWith("image")) {
|
|
||||||
try (final InputStream inputStream = contentResolver.openInputStream(uri)) {
|
|
||||||
bitmap = BitmapFactory.decodeStream(inputStream);
|
|
||||||
} catch (final Exception e) {
|
|
||||||
// if (logCollector != null)
|
|
||||||
// logCollector.appendException(e, LogCollector.LogFile.ASYNC_DOWNLOADER, "onPostExecute::bitmap_1");
|
|
||||||
if (BuildConfig.DEBUG) Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
} else if (mimeType.startsWith("video")) {
|
|
||||||
final MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
retriever.setDataSource(context, uri);
|
|
||||||
} catch (final Exception e) {
|
|
||||||
retriever.setDataSource(file.getAbsolutePath());
|
|
||||||
}
|
|
||||||
bitmap = retriever.getFrameAtTime();
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
|
||||||
try {
|
|
||||||
retriever.close();
|
|
||||||
} catch (final Exception e) {
|
|
||||||
// if (logCollector != null)
|
|
||||||
// logCollector.appendException(e, LogCollector.LogFile.ASYNC_DOWNLOADER, "onPostExecute::bitmap_2");
|
|
||||||
}
|
|
||||||
} catch (final Exception e) {
|
|
||||||
if (BuildConfig.DEBUG) Log.e(TAG, "", e);
|
|
||||||
// if (logCollector != null)
|
|
||||||
// logCollector.appendException(e, LogCollector.LogFile.ASYNC_DOWNLOADER, "onPostExecute::bitmap_3");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final String downloadComplete = context.getString(R.string.downloader_complete);
|
final String downloadComplete = context.getString(R.string.downloader_complete);
|
||||||
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
|
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
@ -351,6 +320,40 @@ public class DownloadWorker extends Worker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Bitmap getThumbnail(final Context context,
|
||||||
|
final File file,
|
||||||
|
final Uri uri,
|
||||||
|
final ContentResolver contentResolver) {
|
||||||
|
final String mimeType = Utils.getMimeType(uri, contentResolver);
|
||||||
|
if (TextUtils.isEmpty(mimeType)) return null;
|
||||||
|
Bitmap bitmap = null;
|
||||||
|
if (mimeType.startsWith("image")) {
|
||||||
|
try {
|
||||||
|
final BitmapUtils.BitmapResult bitmapResult = BitmapUtils
|
||||||
|
.getBitmapResult(context.getContentResolver(), uri, THUMBNAIL_SIZE, THUMBNAIL_SIZE, -1, true);
|
||||||
|
if (bitmapResult == null) return null;
|
||||||
|
bitmap = bitmapResult.bitmap;
|
||||||
|
} catch (final Exception e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
|
}
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
if (mimeType.startsWith("video")) {
|
||||||
|
try (MediaMetadataRetriever retriever = new MediaMetadataRetriever()) {
|
||||||
|
try {
|
||||||
|
retriever.setDataSource(context, uri);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
retriever.setDataSource(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
bitmap = retriever.getFrameAtTime();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
public static class DownloadRequest {
|
public static class DownloadRequest {
|
||||||
private final Map<String, String> urlToFilePathMap;
|
private final Map<String, String> urlToFilePathMap;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user