Android ImageView

转自:ImageView


mageView是开发中经常使用到的一个控件,也可以说是必不可少的。对于它的使用,除了注意ScaleType的理解和设置外,还需要注意其他一些问题,比如设置一张大的背景图片内存占用和释放等。还有它的拓展性方面, 像圆角图片、圆形图片、图片边框等等。因此,如果想熟练使用这个控件,就需要对其实现的机制有一个基本的了解。
   ImageView也是直接继承于View类,主要的结构图如下:

 鉴于篇幅大小,就不copy ImageView的整体代码,选择结构图中的部分作为重点。首先是构造方法,代码如下:
[html]  view plain  copy
  1. public ImageView(Context context, AttributeSet attrs, int defStyle) {  
  2.        super(context, attrs, defStyle);  
  3.        initImageView();  
  4.   
  5.        TypedArray a = context.obtainStyledAttributes(attrs,  
  6.                com.android.internal.R.styleable.ImageView, defStyle, 0);  
  7.   
  8.        Drawable d = a.getDrawable(com.android.internal.R.styleable.ImageView_src);  
  9.        if (d != null) {  
  10.            setImageDrawable(d);  
  11.        }  
  12.   
  13.        mBaselineAlignBottom = a.getBoolean(  
  14.                com.android.internal.R.styleable.ImageView_baselineAlignBottom, false);  
  15.   
  16.        mBaseline = a.getDimensionPixelSize(  
  17.                com.android.internal.R.styleable.ImageView_baseline, -1);  
  18.   
  19.        setAdjustViewBounds(  
  20.            a.getBoolean(com.android.internal.R.styleable.ImageView_adjustViewBounds,  
  21.            false));  
  22.   
  23.        setMaxWidth(a.getDimensionPixelSize(  
  24.                com.android.internal.R.styleable.ImageView_maxWidth, Integer.MAX_VALUE));  
  25.         
  26.        setMaxHeight(a.getDimensionPixelSize(  
  27.                com.android.internal.R.styleable.ImageView_maxHeight, Integer.MAX_VALUE));  
  28.         
  29.        int index = a.getInt(com.android.internal.R.styleable.ImageView_scaleType, -1);  
  30.        if (index >= 0) {  
  31.            setScaleType(sScaleTypeArray[index]);  
  32.        }  
  33.   
  34.        int tint = a.getInt(com.android.internal.R.styleable.ImageView_tint, 0);  
  35.        if (tint != 0) {  
  36.            setColorFilter(tint);  
  37.        }  
  38.         
  39.        int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);  
  40.        if (alpha != 255) {  
  41.            setAlpha(alpha);  
  42.        }  
  43.   
  44.        mCropToPadding = a.getBoolean(  
  45.                com.android.internal.R.styleable.ImageView_cropToPadding, false);  
  46.         
  47.        a.recycle();  
  48.   
  49.        //need inflate syntax/reader for matrix  
  50.    }  
  51.   
  52.    private void initImageView() {  
  53.        mMatrix     = new Matrix();  
  54.        mScaleType  = ScaleType.FIT_CENTER;  
  55.        mAdjustViewBoundsCompat = mContext.getApplicationInfo().targetSdkVersion <=  
  56.                Build.VERSION_CODES.JELLY_BEAN_MR1;  
  57.    }  
  在构造方法中也是很常规的从attrs文件中读取属性值,并进行设置。也可以看到ImageView默认使用的ScaleType 是FIT_CENTER。说到ScaleType,它是一个枚举类型,用于设置,平常使用的ScaleType就是在这里定义的。
[html]  view plain  copy
  1. /**  
  2.      * Options for scaling the bounds of an image to the bounds of this view.  
  3.      */  
  4.     public enum ScaleType {  
  5.         /**  
  6.          * Scale using the image matrix when drawing. The image matrix can be set using  
  7.          * {@link ImageView#setImageMatrix(Matrix)}. From XML, use this syntax:  
  8.          * <code>android:scaleType="matrix"</code>.  
  9.          */  
  10.         MATRIX      (0),  
  11.         /**  
  12.          * Scale the image using {@link Matrix.ScaleToFit#FILL}.  
  13.          * From XML, use this syntax: <code>android:scaleType="fitXY"</code>.  
  14.          */  
  15.         FIT_XY      (1),  
  16.         /**  
  17.          * Scale the image using {@link Matrix.ScaleToFit#START}.  
  18.          * From XML, use this syntax: <code>android:scaleType="fitStart"</code>.  
  19.          */  
  20.         FIT_START   (2),  
  21.         /**  
  22.          * Scale the image using {@link Matrix.ScaleToFit#CENTER}.  
  23.          * From XML, use this syntax:  
  24.          * <code>android:scaleType="fitCenter"</code>.  
  25.          */  
  26.         FIT_CENTER  (3),  
  27.         /**  
  28.          * Scale the image using {@link Matrix.ScaleToFit#END}.  
  29.          * From XML, use this syntax: <code>android:scaleType="fitEnd"</code>.  
  30.          */  
  31.         FIT_END     (4),  
  32.         /**  
  33.          * Center the image in the view, but perform no scaling.  
  34.          * From XML, use this syntax: <code>android:scaleType="center"</code>.  
  35.          */  
  36.         CENTER      (5),  
  37.         /**  
  38.          * Scale the image uniformly (maintain the image's aspect ratio) so  
  39.          * that both dimensions (width and height) of the image will be equal  
  40.          * to or larger than the corresponding dimension of the view  
  41.          * (minus padding). The image is then centered in the view.  
  42.          * From XML, use this syntax: <code>android:scaleType="centerCrop"</code>.  
  43.          */  
  44.         CENTER_CROP (6),  
  45.         /**  
  46.          * Scale the image uniformly (maintain the image's aspect ratio) so  
  47.          * that both dimensions (width and height) of the image will be equal  
  48.          * to or less than the corresponding dimension of the view  
  49.          * (minus padding). The image is then centered in the view.  
  50.          * From XML, use this syntax: <code>android:scaleType="centerInside"</code>.  
  51.          */  
  52.         CENTER_INSIDE (7);  
  53.          
  54.         ScaleType(int ni) {  
  55.             nativeInt = ni;  
  56.         }  
  57.         final int nativeInt;  
  58.     }  
 功能是设置图片的显示位置和大小等方面。接着就是onMeasure()方法了,它用于设置ImageView的大小,我们在xml文件中设置ImageView的时候,如果指定了固定的宽高,那么onMeasur()方法中测量的大小就是固定的宽高大小;如果是包裹内容,那么就需要进一步的计算。
[html]  view plain  copy
  1. @Override  
  2.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  3.         resolveUri();//获取图片Drawable  
  4.         int w;  
  5.         int h;  
  6.          
  7.         // Desired aspect ratio of the view's contents (not including padding)  
  8.         float desiredAspect = 0.0f;  
  9.          
  10.         // We are allowed to change the view's width  
  11.         boolean resizeWidth = false;  
  12.          
  13.         // We are allowed to change the view's height  
  14.         boolean resizeHeight = false;  
  15.          
  16.         final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);  
  17.         final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);  
  18.   
  19.         if (mDrawable == null) {  
  20.             // If no drawable, its intrinsic size is 0.  
  21.             mDrawableWidth = -1;  
  22.             mDrawableHeight = -1;  
  23.             w = h = 0;  
  24.         } else {  
  25.             w = mDrawableWidth;在updateDrawable(Drawable d)方法赋值的。  
  26.             h = mDrawableHeight;  
  27.             if (w <= 0) w = 1;  
  28.             if (h <= 0) h = 1;  
  29.   
  30.             // We are supposed to adjust view bounds to match the aspect  
  31.             // ratio of our drawable. See if that is possible.  
  32.             if (mAdjustViewBounds) {  
  33.                 resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;  
  34.                 resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;  
  35.                  
  36.                 desiredAspect = (float) w / (float) h;  
  37.             }  
  38.         }  
  39.          
  40.         int pleft = mPaddingLeft;  
  41.         int pright = mPaddingRight;  
  42.         int ptop = mPaddingTop;  
  43.         int pbottom = mPaddingBottom;  
  44.   
  45.         int widthSize;  
  46.         int heightSize;  
  47.   
  48.         if (resizeWidth || resizeHeight) {  
  49.             /* If we get here, it means we want to resize to match the  
  50.                 drawables aspect ratio, and we have the freedom to change at  
  51.                 least one dimension.  
  52.             */  
  53.   
  54.             // Get the max possible width given our constraints  
  55.             widthSize = resolveAdjustedSize(w + pleft + pright, mMaxWidth, widthMeasureSpec);  
  56.   
  57.             // Get the max possible height given our constraints  
  58.             heightSize = resolveAdjustedSize(h + ptop + pbottom, mMaxHeight, heightMeasureSpec);  
  59.   
  60.             if (desiredAspect != 0.0f) {  
  61.                 // See what our actual aspect ratio is  
  62.                 float actualAspect = (float)(widthSize - pleft - pright) /  
  63.                                         (heightSize - ptop - pbottom);  
  64.                  
  65.                 if (Math.abs(actualAspect - desiredAspect) > 0.0000001) {  
  66.                      
  67.                     boolean done = false;  
  68.                      
  69.                     // Try adjusting width to be proportional to height  
  70.                     if (resizeWidth) {  
  71.                         int newWidth = (int)(desiredAspect * (heightSize - ptop - pbottom)) +  
  72.                                 pleft + pright;  
  73.   
  74.                         // Allow the width to outgrow its original estimate if height is fixed.  
  75.                         if (!resizeHeight && !mAdjustViewBoundsCompat) {  
  76.                             widthSize = resolveAdjustedSize(newWidth, mMaxWidth, widthMeasureSpec);  
  77.                         }  
  78.   
  79.                         if (newWidth <= widthSize) {  
  80.                             widthSize = newWidth;  
  81.                             done = true;  
  82.                         }  
  83.                     }  
  84.                      
  85.                     // Try adjusting height to be proportional to width  
  86.                     if (!done && resizeHeight) {  
  87.                         int newHeight = (int)((widthSize - pleft - pright) / desiredAspect) +  
  88.                                 ptop + pbottom;  
  89.   
  90.                         // Allow the height to outgrow its original estimate if width is fixed.  
  91.                         if (!resizeWidth && !mAdjustViewBoundsCompat) {  
  92.                             heightSize = resolveAdjustedSize(newHeight, mMaxHeight,  
  93.                                     heightMeasureSpec);  
  94.                         }  
  95.   
  96.                         if (newHeight <= heightSize) {  
  97.                             heightSize = newHeight;  
  98.                         }  
  99.                     }  
  100.                 }  
  101.             }  
  102.         } else {  
  103.             /* We are either don't want to preserve the drawables aspect ratio,  
  104.                or we are not allowed to change view dimensions. Just measure in  
  105.                the normal way.  
  106.             */  
  107.             w += pleft + pright;  
  108.             h += ptop + pbottom;  
  109.                  
  110.             w = Math.max(w, getSuggestedMinimumWidth());  
  111.             h = Math.max(h, getSuggestedMinimumHeight());  
  112.   
  113.             widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);  
  114.             heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);  
  115.         }  
  116.   
  117.         setMeasuredDimension(widthSize, heightSize);  
  118.     }  
   在onMeasure方法中,首先调用了resolveUri()这个方法,目的就是为了确定Drawable。如果设置了drawableResource,那么Drawable就是其值;如果没有,那么就从ContentResolver获取一个Drawable。
[html]  view plain  copy
  1. private void resolveUri() {  
  2.        if (mDrawable != null) {  
  3.            return;  
  4.        }  
  5.   
  6.        Resources rsrc = getResources();  
  7.        if (rsrc == null) {  
  8.            return;  
  9.        }  
  10.   
  11.        Drawable d = null;  
  12.   
  13.        if (mResource != 0) {  
  14.            try {  
  15.                d = rsrc.getDrawable(mResource);  
  16.            } catch (Exception e) {  
  17.                Log.w("ImageView", "Unable to find resource: " + mResource, e);  
  18.                // Don't try again.  
  19.                mUri = null;  
  20.            }  
  21.        } else if (mUri != null) {  
  22.            String scheme = mUri.getScheme();  
  23.            if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {  
  24.                try {  
  25.                    // Load drawable through Resources, to get the source density information  
  26.                    ContentResolver.OpenResourceIdResult r =  
  27.                            mContext.getContentResolver().getResourceId(mUri);  
  28.                    d = r.r.getDrawable(r.id);  
  29.                } catch (Exception e) {  
  30.                    Log.w("ImageView", "Unable to open content: " + mUri, e);  
  31.                }  
  32.            } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)  
  33.                    || ContentResolver.SCHEME_FILE.equals(scheme)) {  
  34.                InputStream stream = null;  
  35.                try {  
  36.                    stream = mContext.getContentResolver().openInputStream(mUri);  
  37.                    d = Drawable.createFromStream(stream, null);  
  38.                } catch (Exception e) {  
  39.                    Log.w("ImageView", "Unable to open content: " + mUri, e);  
  40.                } finally {  
  41.                    if (stream != null) {  
  42.                        try {  
  43.                            stream.close();  
  44.                        } catch (IOException e) {  
  45.                            Log.w("ImageView", "Unable to close content: " + mUri, e);  
  46.                        }  
  47.                    }  
  48.                }  
  49.        } else {  
  50.                d = Drawable.createFromPath(mUri.toString());  
  51.            }  
  52.     
  53.            if (d == null) {  
  54.                System.out.println("resolveUri failed on bad bitmap uri: " + mUri);  
  55.                // Don't try again.  
  56.                mUri = null;  
  57.            }  
  58.        } else {  
  59.            return;  
  60.        }  
  61.   
  62.        updateDrawable(d);  
  63.    }  
  之后在resolveUri()这个方法的最后,调用了 updateDrawable(d)方法,这个方法代码如下:
[html]  view plain  copy
  1. private void updateDrawable(Drawable d) {  
  2.        if (mDrawable != null) {  
  3.            mDrawable.setCallback(null);  
  4.            unscheduleDrawable(mDrawable);  
  5.        }  
  6.        mDrawable = d;  
  7.        if (d != null) {  
  8.            d.setCallback(this);  
  9.            if (d.isStateful()) {  
  10.                d.setState(getDrawableState());  
  11.            }  
  12.            d.setLevel(mLevel);  
  13.            d.setLayoutDirection(getLayoutDirection());  
  14.            d.setVisible(getVisibility() == VISIBLE, true);  
  15.            mDrawableWidth = d.getIntrinsicWidth();  
  16.            mDrawableHeight = d.getIntrinsicHeight();  
  17.            applyColorMod();  
  18.            configureBounds();  
  19.        } else {  
  20.            mDrawableWidth = mDrawableHeight = -1;  
  21.        }  
  22.    }  
  可以看到就是为了Drawable宽高赋值的。回过头来继续看,如果Drawable的宽高不为空的话就分别赋值给w和h;如果为空的话值为-1。然后是一个if判断,mAdjustViewBounds作为判断的变量,它是在setAdjustViewBounds方法中设置的,默认为false,所以必须设置为true,这个判断才会执行。当然这个变量的值也可以在xml文件中设置(android:adjustViewBounds)。那这个方法是做什么用的呢?设置View的最大高度,单独使用无效,需要与setAdjustViewBounds一起使用。如果想设置图片固定大小,又想保持图片宽高比,需要如下设置:
1) 设置setAdjustViewBounds为true;
2) 设置maxWidth、MaxHeight;
3) 设置设置layout_width和layout_height为wrap_content。
  再看一下这个判断,
[html]  view plain  copy
  1. if (mAdjustViewBounds) {  
  2.                 resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;  
  3.                 resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;  
  4.                  
  5.                 desiredAspect = (float) w / (float) h;  
  6.             }  
  widthSpecMode如果不是指定大小的话,因为如果指定了固定大小就不需要重新设置大小了。然后接下来的判断也是基于 resizeWidth和resizeHeight 的值,如果不为true的情况下,会执行如下代码:
[html]  view plain  copy
  1. w += pleft + pright;  
  2.            h += ptop + pbottom;  
  3.            w = Math.max(w, getSuggestedMinimumWidth());  
  4.            h = Math.max(h, getSuggestedMinimumHeight());  
  5.            widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);  
  6.            heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);  
  7.        }  
  8.        setMeasuredDimension(widthSize, heightSize);  
  考虑了填充,最后设置ImageView的大小。
  最后看一下onDraw()方法,
[html]  view plain  copy
  1. @Override  
  2. rotected void onDraw(Canvas canvas) {  
  3.       super.onDraw(canvas);  
  4.   
  5.       if (mDrawable == null) {  
  6.           return; // couldn't resolve the URI  
  7.       }  
  8.   
  9.       if (mDrawableWidth == 0 || mDrawableHeight == 0) {  
  10.           return;     // nothing to draw (empty bounds)  
  11.       }  
  12.   
  13.       if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {  
  14.           mDrawable.draw(canvas);  
  15.       } else {  
  16.           int saveCount = canvas.getSaveCount();  
  17.           canvas.save();  
  18.            
  19.           if (mCropToPadding) {  
  20.               final int scrollX = mScrollX;  
  21.               final int scrollY = mScrollY;  
  22.               canvas.clipRect(scrollX + mPaddingLeft, scrollY + mPaddingTop,  
  23.                       scrollX + mRight - mLeft - mPaddingRight,  
  24.                       scrollY + mBottom - mTop - mPaddingBottom);  
  25.           }  
  26.            
  27.           canvas.translate(mPaddingLeft, mPaddingTop);  
  28.   
  29.           if (mDrawMatrix != null) {  
  30.               canvas.concat(mDrawMatrix);  
  31.           }  
  32.           mDrawable.draw(canvas);  
  33.           canvas.restoreToCount(saveCount);  
  34.       }  
  35.   }  
  在onDraw()方法中,实现方式比较简单,如果mDrawMatrix为空,那么就直接绘制出图片;如果不为空,那么还需要绘制矩阵。这就涉及到mDrawMatrix矩阵了,它是在哪赋值的呢,就是ScaleType。这个是在configureBounds()方法中设置的,
[html]  view plain  copy
  1. private void configureBounds() {  
  2.         if (mDrawable == null || !mHaveFrame) {  
  3.             return;  
  4.         }  
  5.   
  6.         int dwidth = mDrawableWidth;  
  7.         int dheight = mDrawableHeight;  
  8.   
  9.         int vwidth = getWidth() - mPaddingLeft - mPaddingRight;  
  10.         int vheight = getHeight() - mPaddingTop - mPaddingBottom;  
  11.   
  12.         boolean fits = (dwidth < 0 || vwidth == dwidth) &&  
  13.                        (dheight < 0 || vheight == dheight);  
  14.   
  15.         if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {  
  16.             /* If the drawable has no intrinsic size, or we're told to  
  17.                 scaletofit, then we just fill our entire view.  
  18.             */  
  19.             mDrawable.setBounds(0, 0, vwidth, vheight);  
  20.             mDrawMatrix = null;  
  21.         } else {  
  22.             // We need to do the scaling ourself, so have the drawable  
  23.             // use its native size.  
  24.             mDrawable.setBounds(0, 0, dwidth, dheight);  
  25.   
  26.             if (ScaleType.MATRIX == mScaleType) {  
  27.                 // Use the specified matrix as-is.  
  28.                 if (mMatrix.isIdentity()) {  
  29.                     mDrawMatrix = null;  
  30.                 } else {  
  31.                     mDrawMatrix = mMatrix;  
  32.                 }  
  33.             } else if (fits) {  
  34.                 // The bitmap fits exactly, no transform needed.  
  35.                 mDrawMatrix = null;  
  36.             } else if (ScaleType.CENTER == mScaleType) {  
  37.                 // Center bitmap in view, no scaling.  
  38.                 mDrawMatrix = mMatrix;  
  39.                 mDrawMatrix.setTranslate((int) ((vwidth - dwidth) * 0.5f + 0.5f),  
  40.                                          (int) ((vheight - dheight) * 0.5f + 0.5f));  
  41.             } else if (ScaleType.CENTER_CROP == mScaleType) {  
  42.                 mDrawMatrix = mMatrix;  
  43.   
  44.                 float scale;  
  45.                 float dx = 0dy = 0;  
  46.   
  47.                 if (dwidth * vheight > vwidth * dheight) {  
  48.                     scale = (float) vheight / (float) dheight;  
  49.                     dx = (vwidth - dwidth * scale) * 0.5f;  
  50.                 } else {  
  51.                     scale = (float) vwidth / (float) dwidth;  
  52.                     dy = (vheight - dheight * scale) * 0.5f;  
  53.                 }  
  54.   
  55.                 mDrawMatrix.setScale(scale, scale);  
  56.                 mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));  
  57.             } else if (ScaleType.CENTER_INSIDE == mScaleType) {  
  58.                 mDrawMatrix = mMatrix;  
  59.                 float scale;  
  60.                 float dx;  
  61.                 float dy;  
  62.                  
  63.                 if (dwidth <= vwidth && dheight <= vheight) {  
  64.                     scale = 1.0f;  
  65.                 } else {  
  66.                     scale = Math.min((float) vwidth / (float) dwidth,  
  67.                             (float) vheight / (float) dheight);  
  68.                 }  
  69.                  
  70.                 dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f);  
  71.                 dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f);  
  72.   
  73.                 mDrawMatrix.setScale(scale, scale);  
  74.                 mDrawMatrix.postTranslate(dx, dy);  
  75.             } else {  
  76.                 // Generate the required transform.  
  77.                 mTempSrc.set(0, 0, dwidth, dheight);  
  78.                 mTempDst.set(0, 0, vwidth, vheight);  
  79.                  
  80.                 mDrawMatrix = mMatrix;  
  81.                 mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));  
  82.             }  
  83.         }  
  84.     }  
  可以看到在if判断中,对各个ScaleType的类型都进行了判断,根据不同的ScaleType设置不同的矩阵mDrawMatrix。然后通过矩阵对图像进行变换,从而显示出不同的效果。
  除了这一点经常使用到之外,还有就是如何设置图片资源了,有以下几个方法:setImageResource(int resId)、setImageURI(Uri uri)、setImageDrawable(Drawable drawable)、setImageBitmap(Bitmap bm)等,或者也可以在xml文件中设置。但是这样直接使用会有一个隐形的弊端,如果显示的图片过多或者单张显示的图片像素过大,就容易出现OOM问题。因此就应该根据需求对图片进行预处理,常用方法有以下几种:
1、缩放、边界压缩
     在内存中加载图片时直接在内存中做处理。关于图片压缩有很多方法,这里只是列举一个简单的例子,实际使用价值不大,如有需求可以自行参考其他资料。
[html]  view plain  copy
  1. InputStream is = this.getResources().openRawResource(R.drawable.xx);   
  2.    BitmapFactory.Options options=new BitmapFactory.Options();   
  3.    options.inJustDecodeBounds = false;   
  4.    options.inSampleSize = 10;   //width,hight设为原来的十分一   
  5.    Bitmap btp =BitmapFactory.decodeStream(is,null,options);   
2、直接调用JNI
     当使用像 imageView.setBackgroundResource,imageView.setImageResource, 或者 BitmapFactory.decodeResource 这样的方法来设置一张大图片的时候,这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。
  因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常。
  另外,需要特别注意:decodeStream是直接读取图片资料的字节码了, 不会根据机器的各种分辨率来自动适应,使用了decodeStream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源,否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。
[html]  view plain  copy
  1. public static Bitmap readBitMap(Context context, int resId){    
  2.    BitmapFactory.Options opt = new BitmapFactory.Options();    
  3.        opt.inPreferredConfig = Bitmap.Config.RGB_565;     
  4.      opt.inPurgeable = true;    
  5.      opt.inInputShareable = true;     
  6.     InputStream is = context.getResources().openRawResource(resId);    
  7.       return BitmapFactory.decodeStream(is,null,opt);    
  8.     }  
3、手动收回占用资源
     虽然虚拟机会自动回收垃圾资源,但是有时候不是那么及时,这时候可以手动回收。
[html]  view plain  copy
  1. if(!bmp.isRecycle() ){   
  2.       bmp.recycle()   //回收图片所占的内存   
  3.       system.gc()  //提醒系统及时回收   
  4.   }   
4、优化Dalvik虚拟机的堆内存分配
     使用 dalvik.system.VMRuntime类提供的setTargetHeapUtilization方法可以增强程序堆内存的处理效率。
[html]  view plain  copy
  1. private final static float TARGET_HEAP_UTILIZATION = 0.75f;   
     在程序onCreate时就可以调用
[html]  view plain  copy
  1. VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);  
 即可。
     除了 优化Dalvik虚拟机的堆内存分配 外,还可以强制定义自己软件的对内存大小,使用Dalvik提供的 dalvik.system.VMRuntime类来设置最小堆内存为例:Dalvik.VMRuntime类,提供对虚拟机全局,Dalvik的特定功能的接口。Android为每个程序分配的内存可以通过Runtime类的 totalMemory() 、freeMemory() 两个方法获取VM的一些内存信息。
[html]  view plain  copy
  1. private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;  
  2. VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); //设置最小heap内存为6MB大小。  
  
  下面讲解一下如何自定义一个类继承于ImageView。首先以 CircleButton为例,这是github上一个项目,实现一个圆形有点击效果的按钮。如下:
   实现思路是这样的,先画两个圆形图案,一个是实心的圆,一个是圆环。圆环半径小于实心圆半径,这样默认就看不到圆环,然后再画出设置的图片,覆盖在二者之上。最后在按下的时候启动一个属性动画,将圆环放大显示,关于详细的分析可以看 android-circlebutton介绍 这篇文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值