facebook / fresco

An Android library for managing images and the memory they use.
https://frescolib.org/
MIT License
17.07k stars 3.75k forks source link

Always throw the error “Draw requested for a non-attached controller” #245

Closed duguguiyu closed 7 years ago

duguguiyu commented 9 years ago

When the log "Draw requested for a non-attached controller ..." show, the app can't show any image via fresco (any image view, any images).

Kill app and restart IT IS only temp solution.

The log like:

Draw requested for a non-attached controller 2ccc3dce. DraweeHolder{controllerAttached=false, holderAttached=true, drawableVisible=false, activityStarted=true, events=[ON_DETACH_CONTROLLER, ON_CLEAR_OLD_CONTROLLER, ON_SET_CONTROLLER, ON_ATTACH_CONTROLLER, ON_DRAWABLE_HIDE, ON_DETACH_CONTROLLER, ON_ATTACH_CONTROLLER, ON_DETACH_CONTROLLER, ON_CLEAR_OLD_CONTROLLER, ON_SET_CONTROLLER, ON_ATTACH_CONTROLLER, ON_DRAWABLE_HIDE, ON_DETACH_CONTROLLER, ON_ATTACH_CONTROLLER, ON_DETACH_CONTROLLER, ON_CLEAR_OLD_CONTROLLER, ON_SET_CONTROLLER, ON_ATTACH_CONTROLLER, ON_DRAWABLE_HIDE, ON_DETACH_CONTROLLER]}

tyronen commented 9 years ago

Are you using a SimpleDraweeView or using DraweeHolder directly? If the latter, make sure you are handling attach/detach events correctly.

If you are, please post a code snippet to help debug.

duguguiyu commented 9 years ago

I am not custom the SimpleDraweeView and not using DraweeHolder directly.

Sometime, the app would could not show any images, until I clean all file cache...

duguguiyu commented 9 years ago
final SimpleDraweeView imageView = (SimpleDraweeView) view;
      // Initialize controller, to support callback.
      final PipelineDraweeControllerBuilder controllerBuilder = Fresco.newDraweeControllerBuilder();
      if (imageUrl != null &&
          backupUrl != null &&
          !backupUrl.equals(imageUrl)) {
        // Has backup.
        ImageRequest imageRequest = ImageRequest.fromUri(imageUrl);
        ImageRequest backupRequest = ImageRequest.fromUri(backupUrl);
        controllerBuilder.setFirstAvailableImageRequests(
            new ImageRequest[] {imageRequest, backupRequest});
      } else {
        // No backup, simple set url.
        controllerBuilder.setUri(imageUrl == null ? null : Uri.parse(imageUrl));
      }
      controllerBuilder.setAutoPlayAnimations(true);
      final DraweeController controller =
          controllerBuilder.setControllerListener(
              callback == null ? null : new BaseControllerListener<ImageInfo>() {
                @Override
                public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) {
                  if (callback == null) {
                    return;
                  }
                  if (imageInfo == null) {
                    callback.loadCompleted(imageView, null);
                    return;
                  }
                  callback.loadCompleted(imageView,
                      new Image(imageInfo.getHeight(), imageInfo.getWidth()));
                }

                @Override
                public void onFailure(String id, Throwable throwable) {
                  if (callback == null) {
                    return;
                  }
                  callback.loadCompleted(imageView, null);
                }
              })
              .build();
      // Initialize hierarchy to support default image.
      if (defaultImage != NULL_IMAGE_RESOURCE) {
        GenericDraweeHierarchy hierarchy = imageView.getHierarchy();
        if (hierarchy == null) {
          hierarchy = new GenericDraweeHierarchyBuilder(imageView.getResources())
              .build();
          imageView.setHierarchy(hierarchy);
        }
        hierarchy.setPlaceholderImage(defaultImage);
      }
      // Start to load.
      imageView.setController(controller);
plamenko commented 9 years ago

What are the parent views/layouts of SimpleDraweeView? It is possible that one of them is not sending attach/detach events reliably.

duguguiyu commented 9 years ago

We use it everywhere, maybe a RecyclerView, a ViewPager, a FrameLayout ...

And sometime, the app can not load any image again, until clean cache and kill the app.

tyronen commented 9 years ago

The RecyclerView children should be fine, but FrameLayout and ViewPager may not be sending the attach/detach events.

If you know when your child image is going off-screen, call onStartTemporaryDetach at that point. When the image comes back on screen, call onFinishTemporaryDetach. (RecyclerView will do this automatically).

duguguiyu commented 9 years ago

@tyronen If don't do this, what happen? The app may not load any images?

tyronen commented 9 years ago

Fresco needs to know when your image is off-screen in order to release the images' memory. And it needs to know when your image is on-screen, or you'll get the error above.

duguguiyu commented 9 years ago

@tyronen I know that, it's hard to know when to off-screen and in-screen in my app, any best practice?

And if the error throw, what's happen?

kirwan commented 7 years ago

I'm cleaning up very old issues and this should no longer result in errors anyway.

datnt1987 commented 6 years ago

Hi, I current have the same error. I have an object list that remove or add object when check/uncheck from another list. So when I scroll the recycler view, the avatar image (using SimpleDraweeView) disappear and only appear when I touch/scroll again. Here's my logcat:

W/DraweeEventTracker: ba4b6ca: Draw requested for a non-attached controller f0f903b. DraweeHolder{controllerAttached=false, holderAttached=false, drawableVisible=true, events=[ON_SET_HIERARCHY, ON_SET_CONTROLLER, ON_DRAWABLE_HIDE, ON_DRAWABLE_SHOW]}