Closed
Description
I used SimpleDraweeView in adapter, but my app runs slowly, and I saw the log below:
I/Choreographer(1378): Skipped 55 frames! The application may be doing too much work on its main thread.
so I comment the code mSimpleDraw.setImageUri
, the app runs fluently. I think the SimpleDraw blocks the main thread when fetching image from network.
Activity
plamenko commentedon Apr 3, 2015
Are you using OkHttp networking stack?
There is an issue with OkHttp networking stack that it cancels requests on the calling thread (which is going to be the main thread). We have a fix ready for that.
Other than that, SimpleDraweeView should not be doing anything heavy on the main thread. If you give us more context on how you use Fresco, we may be able to isolate the issue more easily.
ultimaters commentedon Apr 4, 2015
@plamenko I just used in a CircleView Adapter and load image, very simple like the tutorial.
in Application:
Fresco.initialize(mContext);
in adapter:
mImageView.setImageURI(Uri.parse(data.getImage()));
that's it.
plamenko commentedon Apr 4, 2015
What's
CircleView Adapter
?mikeknoop commentedon Apr 6, 2015
Hitting the same problem here. Pretty basic usage of
SimpleDraweeView
in aGridView
through an adapter:It seems that any parallel calls to
setImageURI
result in the slowdown.ultimaters commentedon Apr 6, 2015
@plamenko My code just the same as above, in an adapter
plamenko commentedon Apr 6, 2015
I'll investigate
mikeknoop commentedon Apr 9, 2015
Replacing
with
in my code above fixes the performance problem. If I comment out the
setResizeOptions
line the performance problem comes back. Perhaps something to do with rescaling on the main thread?mikeknoop commentedon Apr 9, 2015
FWIW I can also hack the Fresco Sample app to
Skipped 129 frames!
by taking the opposite approach to my last comment:Replace these lines with
I've found it only hits performance problems dealing with local
content://
URIs.http://
do just fine.plamenko commentedon Apr 9, 2015
That's really helpful information, thanks!
plamenko commentedon Apr 10, 2015
@fuwaneko , yeah OkHttp cancellation is a known issue and we have a fix for that. However, local content uri is something we yet need to figure.
mikeknoop commentedon Apr 12, 2015
One other potential/related clue. Even when using my workaround above (which fixed the performance problem), I still see one error line for every
content://...
image that is loaded:The image still successfully loads but an error is generated for each.
The fix from this Picasso thread is to include
file://
in front, presumably something that Fresco needs to do internally or an upstream lib needs to be doing.plamenko commentedon Apr 17, 2015
I deleted the two comments related to OkHttp cancellation as they are not related to this issue and has already been fixed.
plamenko commentedon Apr 17, 2015
@mikeknoop , I missed part of your commend earlier, where you said "If I comment out the setResizeOptions line the performance problem comes back."
Can you please check what are the dimensions of those local images? If the image is much bigger than the view than there is going to be a noticeable overhead unless we resize the image first. Resize has to be explicitly specified as calling
setImageURI
won't do that.2 remaining items
mikeknoop commentedon Apr 18, 2015
Thanks for the info. I imagine Camera images are the 80% use case for
content://
URIs, maybe it'd make sense to do resizing insetImageURI
.I feel like I'm really hacking things to get Fresco to work:
Resizing to 1x1 seems to pick some minimum size that is suitable. I should add that I haven't been able to beat Picasso w.r.t. loading performance for
content://
images yet (and Picasso is pretty slow itself which is why I was checking out Fresco).plamenko commentedon Apr 18, 2015
You should definitely specify resizing, but
ResizeOptions(1, 1)
doesn't seem right, why don't you pass the view's dimensions?Btw, if you do
.setLocalThumbnailPreviewsEnabled(true)
with.setResizeOptions(new ResizeOptions(1, 1))
, and also dosetControllerListener
with the following listener, what do you get in the adb logcat?avenwu commentedon Jul 14, 2015
Same issue, after using SimpleDraweeView:
In my case I have init the Fresco in Application, in the adapter use setImageUrl, then the app is closing to ANR with few response;
The issue can be fixed setting ResizeOptions to SimpleDraweeView mentioned by @mikeknoop
ohshi000 commentedon Jul 23, 2015
I just get the width and height when setImageUri()
public void setImageURI(Uri uri, @nullable Object callerContext) {
if (!hasHierarchy()) {
inflateHierarchy(getContext());
}
DraweeController controller;
int width = getLayoutWidth() , height = getLayoutHeight();
if (this.mSimpleDraweeControllerBuilder instanceof PipelineDraweeControllerBuilder
&& width>0 && height >0) {
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setResizeOptions(new ResizeOptions(width, height))
.setAutoRotateEnabled(true)
.build();
PipelineDraweeControllerBuilder builder =
(PipelineDraweeControllerBuilder) mSimpleDraweeControllerBuilder;
controller = builder
.setAutoPlayAnimations(true)
.setCallerContext(callerContext)
.setOldController(this.getController())
.setImageRequest(request)
.build();
/**
* {@inheritdoc}
*
* Width is defined by target {@link android.view.View view} parameters, configuration
* parameters or device display dimensions.
* Size computing algorithm (go by steps until get non-zero value):
* 1) Get the actual drawn getWidth() of the View
* 2) Get layout_width
*/
public int getLayoutWidth() {
final ViewGroup.LayoutParams params = getLayoutParams();
int width = 0;
if (params != null && params.width != ViewGroup.LayoutParams.WRAP_CONTENT) {
width = getWidth(); // Get actual image width
}
if (width <= 0 && params != null) width = params.width; // Get layout width parameter
if (width <= 0) {
width = getImageViewFieldValue(this, "mMaxWidth"); // Check maxWidth parameter
}
return width;
}
tyronen commentedon Oct 14, 2015
Setting ResizeOptions is indeed the correct solution. The reason frames were skipped is that Android was struggling to scale such a large image in a small view.
At most we could make this automatic some of the time - when the view is specified with an explicit size - but that won't work for match_parent type layouts.
SarthakM9 commentedon Oct 27, 2015
Hello,
I got entangled in a similar problem where i was using SimpleDraweeView as a GridView row, to parse some http uri's. All images were > 5mb and were being loaded in memory without getting resized automatically (which was causing Out of Memory Error).
@mikeknoop 's solution works but writing such code in getView() seems an inefficient approach.
So, i created my version of SimpleDraweeView, following are the steps i used:
Copy/Paste SimpleDraweeView in your package and rename it to something else (I renamed it to TweakedDraweeView)
Change the following method as follows:
The solution for this problem is to add an extra line where you initialized Fresco(probably in Application class)
that's all!
saantiaguilera commentedon Aug 2, 2016
Hi ! I had the same problem and what fixed it was to
setLocalThumbnailPreview(FALSE).
Regarding this issue, can someone from fresco answer me these questions:
OlukaDenis commentedon Aug 30, 2018
I also thave the same issue, my app has images and uses fragments and adapters but it is too slow.
Then shows "The application may be doing too much work on its main thread."
This is how my adpater looks like;
`public class UniversityAdapter extends ArrayAdapter {
}`
An the fragment looks like this;
`public class UniversityFragment extends android.support.v4.app.Fragment {
}`
Please what could be wrong?
vinit-poojary commentedon Sep 11, 2018
need help
vinit-poojary/ViewWallpaper#1
adkhamjonDev commentedon Jun 13, 2021
need help
<< The application may be doing too much work on its main thread >>
And here is my code
ViewModel->
class YoutubeViewModel(apiService: ApiService):ViewModel() {
val youtubeLiveData=MutableLiveData<Resource>()
private val youtubeRepository=YoutubeRepository(apiService)
init {
getVideos()
}
private fun getVideos() {
viewModelScope.launch {
youtubeLiveData.postValue(Resource.loading(null))
youtubeRepository.getYoutubeData()
.catch {e->
youtubeLiveData.postValue(Resource.error(e.message?:"Error",null))
}.collect {
youtubeLiveData.postValue(Resource.success(it))
}
}
}
@JvmName("getYoutubeLiveData1")
fun getYoutubeLiveData():MutableLiveData<Resource>{
return youtubeLiveData
}
}
And in MainFragment
youtubeViewModel=ViewModelProviders.of(this,ViewModelFactory(ApiClient.apiService))[YoutubeViewModel::class.java]