Browse Source

Memory efficient bitmap decoding in DownloadWorker. Fixes austinhuang0131/barinsta#930.

renovate/org.robolectric-robolectric-4.x
Ammar Githam 4 years ago
parent
commit
d819928eb3
  1. 48
      app/src/main/java/awais/instagrabber/utils/BitmapUtils.java
  2. 77
      app/src/main/java/awais/instagrabber/workers/DownloadWorker.java

48
app/src/main/java/awais/instagrabber/utils/BitmapUtils.java

@ -127,7 +127,33 @@ 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
.tasksThread()
.submit(() -> getBitmapResult(contentResolver, uri, reqWidth, reqHeight, maxDimenSize, addToCache));
Futures.addCallback(future, new FutureCallback<BitmapResult>() {
@Override
public void onSuccess(@Nullable final BitmapResult result) {
if (result == null) {
callback.onLoad(null, -1, -1);
return;
}
callback.onLoad(result.bitmap, result.width, result.height);
}
@Override
public void onFailure(@NonNull final Throwable t) {
callback.onFailure(t);
}
}, callbackHandlers);
}
@Nullable
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; BitmapFactory.Options bitmapOptions;
float actualReqWidth = reqWidth; float actualReqWidth = reqWidth;
float actualReqHeight = reqHeight; float actualReqHeight = reqHeight;
@ -167,26 +193,10 @@ public final class BitmapUtils {
Log.e(TAG, "loadBitmap: ", e); Log.e(TAG, "loadBitmap: ", e);
} }
return null; return null;
});
Futures.addCallback(future, new FutureCallback<BitmapResult>() {
@Override
public void onSuccess(@Nullable final BitmapResult result) {
if (result == null) {
callback.onLoad(null, -1, -1);
return;
}
callback.onLoad(result.bitmap, result.width, result.height);
}
@Override
public void onFailure(@NonNull final Throwable t) {
callback.onFailure(t);
}
}, callbackHandlers);
} }
private static class BitmapResult {
Bitmap bitmap;
public static class BitmapResult {
public Bitmap bitmap;
int width; int width;
int height; int height;

77
app/src/main/java/awais/instagrabber/workers/DownloadWorker.java

@ -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 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 Bitmap bitmap = getThumbnail(context, file, uri, contentResolver);
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…
Cancel
Save