SimpleDraweeView black filckering on replacement image
Closed this issue · 13 comments
I am trying to replace mutiples images (from local storage) using the same SimpleDraweeView. How avoid the black flickering?
After a while the black flickering disappear and works well.
See the video: http://sendvid.com/q92ry52l
I am only doing: mSimpleDraweeView.setImageURI("file://" + imagesList.get(index));
I am using 'com.facebook.fresco:fresco:0.13.0'
Thanks
Yeah, unfortunately this is a known issue. If you set a new URI, you'll see the placeholder image until the new image is ready. This is especially noticeable when you have large images and you switch them a lot (like in your example).
There is a PR that solves this, #1328, but we did not yet include it in Fresco. You could try and see if this would solve the issue.
Thanks, I need to fork de repo and apply the pull request locally to test right?
You don't need to fork. The DraweeController already supports setting a DataSourceSupplier , so you should be able to just copy paste the code from RetainingDataSourceSupplier
in your project that uses Fresco and then use it like shown in MainActivity.java
of the pull request.
Which also means that if this works for you, you can just use it until we've officially included it in Fresco :)
Yes, I tried that, but when I write this
mSimpleDraweeView.setController(
Fresco.newDraweeControllerBuilder()
.setDataSourceSupplier(retainingSupplier)
.build());
The method .build() does not exists
Yes, if you take a look at the PR, setDataSourceSupplier
does not return the builder.
You have to do
PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder()...
builder.setDataSourceSupplier();
setController(builder.build());
Perfect, good to know that it works! Let us know if you experience some issues with this. We'll also work on including this directly into Fresco.
Anyone can share some sample code based on setDataSourceSupplier...
import com.facebook.common.executors.CallerThreadExecutor;
import com.facebook.common.internal.Supplier;
import com.facebook.datasource.AbstractDataSource;
import com.facebook.datasource.DataSource;
import com.facebook.datasource.DataSubscriber;
import java.util.Collections;
import java.util.Set;
import java.util.WeakHashMap;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.NotThreadSafe;
import javax.annotation.concurrent.ThreadSafe;
@NotThreadSafe
public class RetainingDataSourceSupplier<T> implements Supplier<DataSource<T>> {
private final Set<RetainingDataSource> mDataSources =
Collections.newSetFromMap(new WeakHashMap<RetainingDataSource, Boolean>());
private Supplier<DataSource<T>> mCurrentDataSourceSupplier = null;
@Override
public DataSource<T> get() {
RetainingDataSource dataSource = new RetainingDataSource();
dataSource.setSupplier(mCurrentDataSourceSupplier);
mDataSources.add(dataSource);
return dataSource;
}
public void setSupplier(Supplier<DataSource<T>> supplier) {
mCurrentDataSourceSupplier = supplier;
for (RetainingDataSource dataSource: mDataSources) {
dataSource.setSupplier(supplier);
}
}
@ThreadSafe
private class RetainingDataSource extends AbstractDataSource<T> {
@GuardedBy("RetainingDataSource.this")
@Nullable
private DataSource<T> mDataSource = null;
public void setSupplier(@Nullable Supplier<DataSource<T>> supplier) {
// early return without calling {@code supplier.get()} in case we are closed
if (isClosed()) {
return;
}
DataSource<T> oldDataSource;
DataSource<T> newDataSource = (supplier != null) ? supplier.get() : null;
synchronized (RetainingDataSource.this) {
if (isClosed()) {
oldDataSource = newDataSource;
newDataSource = null;
} else {
oldDataSource = mDataSource;
mDataSource = newDataSource;
}
}
if (newDataSource != null) {
newDataSource.subscribe(new InternalDataSubscriber(), CallerThreadExecutor.getInstance());
}
closeSafely(oldDataSource);
}
@Override
@Nullable
public synchronized T getResult() {
return (mDataSource != null) ? mDataSource.getResult() : null;
}
@Override
public synchronized boolean hasResult() {
return (mDataSource != null) && mDataSource.hasResult();
}
@Override
public boolean close() {
DataSource<T> dataSource;
synchronized (RetainingDataSource.this) {
// it's fine to call {@code super.close()} within a synchronized block because we don't
// implement {@link #closeResult()}, but perform result closing ourselves.
if (!super.close()) {
return false;
}
dataSource = mDataSource;
mDataSource = null;
}
closeSafely(dataSource);
return true;
}
private void onDataSourceNewResult(DataSource<T> dataSource) {
if (dataSource == mDataSource) {
setResult(null, false);
}
}
private void onDataSourceFailed(DataSource<T> dataSource) {
// do not propagate failure
}
private void onDatasourceProgress(DataSource<T> dataSource) {
if (dataSource == mDataSource) {
setProgress(dataSource.getProgress());
}
}
private void closeSafely(DataSource<T> dataSource) {
if (dataSource != null) {
dataSource.close();
}
}
private class InternalDataSubscriber implements DataSubscriber<T> {
@Override
public void onNewResult(DataSource<T> dataSource) {
if (dataSource.hasResult()) {
RetainingDataSource.this.onDataSourceNewResult(dataSource);
} else if (dataSource.isFinished()) {
RetainingDataSource.this.onDataSourceFailed(dataSource);
}
}
@Override
public void onFailure(DataSource<T> dataSource) {
RetainingDataSource.this.onDataSourceFailed(dataSource);
}
@Override
public void onCancellation(DataSource<T> dataSource) {
}
@Override
public void onProgressUpdate(DataSource<T> dataSource) {
RetainingDataSource.this.onDatasourceProgress(dataSource);
}
}
}
}
Use:
SimpleDraweeView mImageView = //findById;
RetainingDataSourceSupplier<CloseableReference<CloseableImage>> retainingSupplier = new RetainingDataSourceSupplier<>();
PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder();
builder.setDataSourceSupplier(retainingSupplier);
mImageView.setController(builder.build());
retainingSupplier.setSupplier(Fresco.getImagePipeline().getDataSourceSupplier(ImageRequest.fromUri("your cool uri"), null, false));
hi, @oprisnik i used @agustinsivoplas's code,unfortunately,it's not working,when i replace url,it still shows in the following order:first image-->placeholder-->second image,It really is not a good experience