1

I have a class that extends from ImageView (well actually are three classes that extends one from the other, but that's not relevant) to perform some custom drawing around the drawable drawn by the ImageView. Now, my code is fine (or at least I think is fine, after having profiled it it takes just a bunch of ms to run) but when setting the image (image loaded as a Bitmap) everything hangs for about 500 ms, not a lot but enough to be noticeable.

Sadly this class has to be used inside a GridView (or ListView) and everything is fine until, after the images have been load (through Picasso, so obviously my problem is not the loading of the image on the main thread), the images are set in the imageviews. Now, since each ImageView takes some hundreds ms to display the image it makes the GridView lag while scrolling if images are being set.

Now as you can see from the image below (results of method profiling provided by DDMS) what takes so much time is the method GLES20Canvas.nDrawDisplayList

Note: The images are down scaled to a size a little lower respect the ImageView, so this solution has already been tried.

Now to the question: How can I display in an efficient and fast manner this Bitmap?

Thank you all in advance!

drawing profile

EDIT: Time for some code, as asked by JakeWharton

@Override
public boolean onPreDraw() {
    if (mNeedRedraw)
        updateAttrs();
    return true;
}

@Override
protected void onDraw(Canvas canvas) {
    canvas.save();
    if (mClippingPath != null) {
        canvas.clipPath(mClippingPath);
    }
    super.onDraw(canvas);
    canvas.restore();
    if (mBorderPath != null && mBorderPaint != null) {
        canvas.drawPath(mBorderPath, mBorderPaint);
    }
}

Now the other three subclass have a really similar code, obviously the mNeedRedraw flag is set only when really needed since it recalculate all the things needed for a correct drawing (but always reusing objects, no object allocation is done in the updateAttrs() method.

Just for completeness sake:

The draw of the first subclass:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mBackgroundPaint != null && mBackgroundPath != null) {
        canvas.drawPath(mBackgroundPath, mBackgroundPaint);
        canvas.drawTextOnPath(mText, mBackgroundPath, mHorizontalOffset, mMidTextHeight, mTextPaint);
        if (mIcon != null && mIconTransformationMatrix != null) {
            canvas.drawBitmap(mIcon, mIconTransformationMatrix, mTextPaint);
        }
    }
}

@Override
public boolean onPreDraw() {
    boolean result = super.onPreDraw();
    if (mFooNeedRedraw)
        updateAttrs();
    return result;
}

The draw of the second subclass:

@Override
public boolean onPreDraw() {
    boolean result = super.onPreDraw();
    if (mBarNeedRedraw)
        updateAttrs();
    return result;
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mArc != null && !isInEditMode()) { 
        canvas.drawPath(mArc, mArcPaint);
    }
}

And finally the code of the last subclass:

@Override
public boolean onPreDraw() {
    boolean result = super.onPreDraw();
    if (mBazNeedRedraw || mTrackNeedRedraw)
        updateAttrs();
    return result;
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if(mTrackVisible)
        canvas.drawBitmap(mThumbTrackIcon, mThumbIconTransformationMatrix, mThumbPaint);
}

This is all. Now, the updateAttrs() is a private method, there are no relations between them in the subclasses, I have checked how many times it is called, and for my test seems to be called only two times at the first creation / activity recreation.

Any Idea?

Community
  • 1
  • 1
Antonio E.
  • 4,381
  • 2
  • 25
  • 35
  • the question is why are you extending an ImageView? – pskink Mar 27 '14 at 18:23
  • Why I shouldn't? ImageView is conveniente for the various transformation it does automatically to the image (fitCenter, centerCrop etc) this is why it was my first choice of class to be extended – Antonio E. Mar 27 '14 at 20:14
  • if you want "custom drawing around Drawable drawn" then subclass not ImageView but rather Drawable – pskink Mar 27 '14 at 20:22
  • and if you want to make it easier you can use one of existing Drawable subclasses – pskink Mar 27 '14 at 20:25
  • Show code. What are you doing in your custom drawing code? Sounds like your allocating a Bitmap and drawing to it on the main thread. – Jake Wharton Mar 27 '14 at 20:36
  • I'll show the code tomorrow (here it's night and I'm off work :P) anyway the Bitmap allocation is done by Picasso not by me. The custom drawing code is substantially a clipping path and a border in the first subclass, another fixed border + another border animated via ObjectAnimator and in the last subclass the drawing of a small bitmap that can be moved along a path. You can think at it as a slider, just a little more complicated. Obviously invalidate() calls are reduced to the minimum, I reuse all object used and every ondraw I use is no longer than 3 lines of code (are all simple methods) – Antonio E. Mar 27 '14 at 22:00
  • i would suggest extending a BitmapDrawable or StateListDrawable if you need stateful look, but the first candidate would be BitmapDrawable – pskink Mar 28 '14 at 16:54
  • btw what you are doing in the last subclass (a small Bitmap moved via an Animation) can be easly done by https://github.com/pskink/PatchworkDrawable – pskink Mar 28 '14 at 20:00

0 Answers0