【发布时间】:2015-12-19 00:09:36
【问题描述】:
我有以下两种方法可以加载我的Bitmaps。当我尝试加载巨大的图像 2000px x 6000px 时,我得到了 UIfreeze 大约 3 秒。 anubody 可以帮助我提高大图像的加载速度吗?我对屏幕方向的改变很重要,因为这些方法总是被那个库调用并且我的 UI 在旋转之前总是冻结大约 3 秒...
/**
* Async task used to get image details
*/
private static class TilesInitTask implements Runnable {
private final WeakReference<ScaleImageView> viewRef;
private final WeakReference<Context> contextRef;
private final WeakReference<DecoderFactory<? extends ImageRegionDecoder>> decoderFactoryRef;
private final Uri source;
private ImageRegionDecoder decoder;
private Exception exception;
public TilesInitTask(ScaleImageView view, Context context, DecoderFactory<? extends ImageRegionDecoder> decoderFactory, Uri source) {
this.viewRef = new WeakReference<>(view);
this.contextRef = new WeakReference<>(context);
this.decoderFactoryRef = new WeakReference<DecoderFactory<? extends ImageRegionDecoder>>(decoderFactory);
this.source = source;
}
public void run() {
ScaleImageView view = null;
try {
String sourceUri = source.toString();
Context context = contextRef.get();
DecoderFactory<? extends ImageRegionDecoder> decoderFactory = decoderFactoryRef.get();
view = viewRef.get();
if (context != null && decoderFactory != null && view != null) {
decoder = decoderFactory.make();
Point dimensions = decoder.init(context, source);
int sWidth = dimensions.x;
int sHeight = dimensions.y;
int exifOrientation = view.getExifOrientation(sourceUri);
if (view.sRegion != null) {
sWidth = view.sRegion.width();
sHeight = view.sRegion.height();
}
view.onTilesInited(decoder, sWidth, sHeight, exifOrientation);
}
} catch (Exception e) {
Log.e(TAG, "Failed to initialise bitmap decoder", e);
this.exception = e;
if (view != null && view.onImageEventListener != null) {
view.onImageEventListener.onImageLoadError(exception);
}
}
}
}
/**
* Called by worker task when decoder is ready and image size and EXIF orientation is known.
*/
private synchronized void onTilesInited(ImageRegionDecoder decoder, int sWidth, int sHeight, int sOrientation) {
// If actual dimensions don't match the declared size, reset everything.
if (this.sWidth > 0 && this.sHeight > 0 && (this.sWidth != sWidth || this.sHeight != sHeight)) {
reset(false);
if (bitmap != null) {
if (!bitmapIsCached) {
bitmap.recycle();
}
bitmap = null;
bitmapIsPreview = false;
bitmapIsCached = false;
}
}
this.decoder = decoder;
this.sWidth = sWidth;
this.sHeight = sHeight;
this.sOrientation = sOrientation;
checkReady();
checkImageLoaded();
invalidate();
requestLayout();
}
/**
* Async task used to load images
*/
private static class TileLoadTask implements Runnable {
private final WeakReference<ScaleImageView> viewRef;
private final WeakReference<ImageRegionDecoder> decoderRef;
private final WeakReference<Tile> tileRef;
private Exception exception;
public TileLoadTask(ScaleImageView view, ImageRegionDecoder decoder, Tile tile) {
this.viewRef = new WeakReference<>(view);
this.decoderRef = new WeakReference<>(decoder);
this.tileRef = new WeakReference<>(tile);
tile.loading = true;
}
public void run() {
ScaleImageView view = null;
try {
view = viewRef.get();
ImageRegionDecoder decoder = decoderRef.get();
Tile tile = tileRef.get();
if (decoder != null && tile != null && view != null && decoder.isReady()) {
synchronized (view.decoderLock) {
// Update tile's file sRect according to rotation
view.fileSRect(tile.sRect, tile.fileSRect);
if (view.sRegion != null) {
tile.fileSRect.offset(view.sRegion.left, view.sRegion.top);
}
tile.bitmap = decoder.decodeRegion(tile.fileSRect, tile.sampleSize);
tile.loading = false;
view.onTileLoaded();
}
} else if (tile != null) {
tile.loading = false;
}
} catch (Exception e) {
Log.e(TAG, "Failed to decode tile", e);
this.exception = e;
if (view != null && view.onImageEventListener != null) {
view.onImageEventListener.onTileLoadError(exception);
}
}
}
}
/**
* Called by worker task when a tile has loaded. Redraws the view.
*/
private synchronized void onTileLoaded() {
checkReady();
checkImageLoaded();
if (isBaseLayerReady() && bitmap != null) {
if (!bitmapIsCached) {
bitmap.recycle();
}
bitmap = null;
bitmapIsPreview = false;
bitmapIsCached = false;
}
invalidate();
}
【问题讨论】:
-
如果您在单独的线程中加载图像,则不应有任何形式的 UI 冻结。你为什么用我的
AsyncTask?你是如何运行这些Runnables的?在适当的情况下使用WeakReference大受好评,但我目前正在手机中,无法详细研究您的源代码。但是,您的代码中似乎仍然存在一些危险信号。就像在Bitmap上调用recycle()或在主线程之外访问Views。 -
如果您告诉我您要加载什么样的图像,将能够提供解决方案!
-
@XaverKapeller,这些方法在我的视图中显示一些照片。我在 View 类中使用 .run() 方法调用它们
-
@XaverKapeller,我正在尝试根据我的需要重新制作这个库github.com/davemorrissey/subsampling-scale-image-view。当默认代码图像上的旋转屏幕消失一秒钟并再次重新加载 3 秒钟时,我决定冻结 UI 以避免白屏,但现在我正试图提高加载速度)))这些方法来自 SubsamplingScaleImageView(AsynkTasks)
标签: android android-asynctask runnable android-bitmap