本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处!

首先关于图片加载到ImageView上,我们来讨论几个问题:

如下:

imageView.setImageResource(resId);获得图片资源运行在主线程

  1. This does Bitmap reading and decoding on the UI
  2. * thread, which can cause a latency hiccup.  If that's a concern,
  3. * consider using {@link #setImageDrawable(android.graphics.drawable.Drawable)} or
  4. * {@link #setImageBitmap(android.graphics.Bitmap)} and
  5. * {@link android.graphics.BitmapFactory} instead.</p>
  6. *
  7. * @param resId the resource identifier of the the drawable
  8. *
  9. * @attr ref android.R.styleable#ImageView_src
  10. */
  11. @android.view.RemotableViewMethod
  12. public void setImageResource(int resId) {
  13. if (mUri != null || mResource != resId) {
  14. updateDrawable(null);
  15. mResource = resId;
  16. mUri = null;
  17. resolveUri();
  18. requestLayout();
  19. invalidate();
  20. }
  21. }
  1. private void resolveUri() {
  2. if (mDrawable != null) {
  3. return;
  4. }
  5. Resources rsrc = getResources();
  6. if (rsrc == null) {
  7. return;
  8. }
  9. Drawable d = null;
  10. if (mResource != 0) {
  11. try {
  12. d = rsrc.getDrawable(mResource);
  13. } catch (Exception e) {
  14. Log.w("ImageView", "Unable to find resource: " + mResource, e);
  15. // Don't try again.
  16. mUri = null;
  17. }
  18. } else if (mUri != null) {

从源码上看,mResource不为空,而mUri不为空,所以下面的方法咱们只贴出来一部分,可以看到,图片drawable值是通过Resource对象在UI线程中完成。方法上面的解释也可佐证,同时引出下面两个问题,由于SetImageResource会使UI线程延迟,所以可以考虑下面两种做法

imageView.setImageDrawable(drawable);获得图片资源运行在子线程

  1. /**
  2. * Sets a drawable as the content of this ImageView.
  3. *
  4. * @param drawable The drawable to set
  5. */
  6. public void setImageDrawable(Drawable drawable) {
  7. if (mDrawable != drawable) {
  8. mResource = 0;
  9. mUri = null;
  10. int oldWidth = mDrawableWidth;
  11. int oldHeight = mDrawableHeight;
  12. updateDrawable(drawable);
  13. if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
  14. requestLayout();
  15. }
  16. invalidate();
  17. }
  18. }
  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. mDrawableWidth = d.getIntrinsicWidth();
  14. mDrawableHeight = d.getIntrinsicHeight();
  15. applyColorMod();
  16. configureBounds();
  17. } else {
  18. mDrawableWidth = mDrawableHeight = -1;
  19. }
  20. }

从源码上看,只需要把获得的值,解析一下,刷新到UI线程即可,所以Drawable对象可以在子线程中获取。

imageView.setImageBitmap(bm);获得图片资源可以运行在子线程,且可以改变图片大小

  1. /**
  2. * Sets a Bitmap as the content of this ImageView.
  3. *
  4. * @param bm The bitmap to set
  5. */
  6. @android.view.RemotableViewMethod
  7. public void setImageBitmap(Bitmap bm) {
  8. // if this is used frequently, may handle bitmaps explicitly
  9. // to reduce the intermediate drawable object
  10. setImageDrawable(new BitmapDrawable(mContext.getResources(), bm));
  11. }
  1. /**
  2. * Create drawable from a bitmap, setting initial target density based on
  3. * the display metrics of the resources.
  4. */
  5. public BitmapDrawable(Resources res, Bitmap bitmap) {
  6. this(new BitmapState(bitmap), res);
  7. mBitmapState.mTargetDensity = mTargetDensity;
  8. }
  1. private BitmapDrawable(BitmapState state, Resources res) {
  2. mBitmapState = state;
  3. if (res != null) {
  4. mTargetDensity = res.getDisplayMetrics().densityDpi;
  5. } else {
  6. mTargetDensity = state.mTargetDensity;
  7. }
  8. setBitmap(state != null ? state.mBitmap : null);
  9. }
  1. private void setBitmap(Bitmap bitmap) {
  2. if (bitmap != mBitmap) {
  3. mBitmap = bitmap;
  4. if (bitmap != null) {
  5. computeBitmapSize();
  6. } else {
  7. mBitmapWidth = mBitmapHeight = -1;
  8. }
  9. invalidateSelf();
  10. }
  11. }

SetImageBitmap同理,其实是通过BitmapDrawable获得一个Drawable对象,同setImageDrawable。值可以在子线程获得,在主界面刷新。

与此同时,有两个方法出现频率比较高,requestLayout和invalidate方法。

requestLayout:

  1. /**
  2. * Call this when something has changed which has invalidated the
  3. * layout of this view. This will schedule a layout pass of the view
  4. * tree.
  5. */
  6. public void requestLayout() {
  7. if (ViewDebug.TRACE_HIERARCHY) {
  8. ViewDebug.trace(this, ViewDebug.HierarchyTraceType.REQUEST_LAYOUT);
  9. }
  10. mPrivateFlags |= FORCE_LAYOUT;
  11. mPrivateFlags |= INVALIDATED;
  12. if (mParent != null) {
  13. if (mLayoutParams != null) {
  14. mLayoutParams.resolveWithDirection(getResolvedLayoutDirection());
  15. }
  16. if (!mParent.isLayoutRequested()) {
  17. mParent.requestLayout();
  18. }
  19. }
  20. }
  1. * To intiate a layout, call {@link #requestLayout}. This method is typically
  2. * called by a view on itself when it believes that is can no longer fit within
  3. * its current bounds.

最主要的是这句,主要是当前View已经放不用所存放的值时,需要重新计算宽高

Invalidate():

  1. /**
  2. * Invalidate the whole view. If the view is visible,
  3. * {@link #onDraw(android.graphics.Canvas)} will be called at some point in
  4. * the future. This must be called from a UI thread. To call from a non-UI thread,
  5. * call {@link #postInvalidate()}.
  6. */
  7. public void invalidate() {
  8. invalidate(true);
  9. }
  1. /**
  2. * This is where the invalidate() work actually happens. A full invalidate()
  3. * causes the drawing cache to be invalidated, but this function can be called with
  4. * invalidateCache set to false to skip that invalidation step for cases that do not
  5. * need it (for example, a component that remains at the same dimensions with the same
  6. * content).
  7. *
  8. * @param invalidateCache Whether the drawing cache for this view should be invalidated as
  9. * well. This is usually true for a full invalidate, but may be set to false if the
  10. * View's contents or dimensions have not changed.
  11. */
  12. void invalidate(boolean invalidateCache) {
  13. if (ViewDebug.TRACE_HIERARCHY) {
  14. ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
  15. }
  16. if (skipInvalidate()) {
  17. return;
  18. }
  19. if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
  20. (invalidateCache && (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) ||
  21. (mPrivateFlags & INVALIDATED) != INVALIDATED || isOpaque() != mLastIsOpaque) {
  22. mLastIsOpaque = isOpaque();
  23. mPrivateFlags &= ~DRAWN;
  24. mPrivateFlags |= DIRTY;
  25. if (invalidateCache) {
  26. mPrivateFlags |= INVALIDATED;
  27. mPrivateFlags &= ~DRAWING_CACHE_VALID;
  28. }
  29. final AttachInfo ai = mAttachInfo;
  30. final ViewParent p = mParent;
  31. //noinspection PointlessBooleanExpression,ConstantConditions
  32. if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
  33. if (p != null && ai != null && ai.mHardwareAccelerated) {
  34. // fast-track for GL-enabled applications; just invalidate the whole hierarchy
  35. // with a null dirty rect, which tells the ViewAncestor to redraw everything
  36. p.invalidateChild(this, null);
  37. return;
  38. }
  39. }
  40. if (p != null && ai != null) {
  41. final Rect r = ai.mTmpInvalRect;
  42. r.set(0, 0, mRight - mLeft, mBottom - mTop);
  43. // Don't call invalidate -- we don't want to internally scroll
  44. // our own bounds
  45. p.invalidateChild(this, r);
  46. }
  47. }
  48. }

把计算宽高、实际宽高、布局等刷新进来

  1. If either {@link #requestLayout()} or {@link #invalidate()} were called,
  2. * the framework will take care of measuring, laying out, and drawing the tree
  3. * as appropriate.

与此同时,我们还可以看到一个知识点postInvalidate

  1. /**
  2. * <p>Cause an invalidate to happen on a subsequent cycle through the event loop.
  3. * Use this to invalidate the View from a non-UI thread.</p>
  4. *
  5. * <p>This method can be invoked from outside of the UI thread
  6. * only when this View is attached to a window.</p>
  7. *
  8. * @see #invalidate()
  9. */
  10. public void postInvalidate() {
  11. postInvalidateDelayed(0);
  12. }
  1. /**
  2. * <p>Cause an invalidate to happen on a subsequent cycle through the event
  3. * loop. Waits for the specified amount of time.</p>
  4. *
  5. * <p>This method can be invoked from outside of the UI thread
  6. * only when this View is attached to a window.</p>
  7. *
  8. * @param delayMilliseconds the duration in milliseconds to delay the
  9. *         invalidation by
  10. */
  11. public void postInvalidateDelayed(long delayMilliseconds) {
  12. // We try only with the AttachInfo because there's no point in invalidating
  13. // if we are not attached to our window
  14. AttachInfo attachInfo = mAttachInfo;
  15. if (attachInfo != null) {
  16. Message msg = Message.obtain();
  17. msg.what = AttachInfo.INVALIDATE_MSG;
  18. msg.obj = this;
  19. attachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
  20. }
  21. }

这个刷新会排到消息队列去刷新,也就是在空闲时刷新,相对来说可以减少阻塞,此任务优先级稍低,当然我们可以加入延迟时间来相对自定义优先级。

在开发过程中,大概会遇到这样的情况,在布局的时候,需要图片的宽度或长度;或者图片太大,ImageView太小,要做图片压缩;这时就要用到接下来讲到的知识点。

BitmapFactory.Options options = new BitmapFactory.Options();

options.inJustDecodeBounds = true;//API中有说明,此时返回bitmap值为null

bitmap = BitmapFactory.decodeFile(pathName,options);

int height=options.outHeight;//获得图片的高

int width=options.outWidth;//获得图片的宽

options.inJustDecodeBounds=false;//之后设置

bitmap=BitmapFactory.decodeFile(pathName, options);

可获得正确的bitmap值。


 本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处!

Android ImageView设置图片原理(上)的更多相关文章

  1. Android ImageView设置图片原理(下)

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 写完上一篇后,总认为介绍的知识点不多,仅仅是一种在UI线程解析载入图片.两种在子线程解析,在UI线程 ...

  2. Android开发模板代码(二)——为ImageView设置图片,退出后能保存ImageView的状态

    接着之前的那个从图库选择图片,设置到ImageView中去,但是,我发现了一个问题,就是再次进入的时候ImageView是恢复到了默认状态,搜索了资料许久之后,终于是发现了解决方法,使用SharePr ...

  3. Java开发桌面程序学习(七)——ImageView设置图片以及jar包读取fxml文件

    ImageView设置图片 JavaFx的ImageView,设置图片不能直接通过属性设置,只能通过代码来设置 ImageView设置图片 首先,我们让fxml对应的那个controller的java ...

  4. Android -- ImageView(控制图片的大小以及旋转的角度)

    1. 

  5. iOS按钮设置图片在上文字在下

    UIButton同时设置Title和Image后,默认是图片在左文字在右,如下图1,很多情况下我们希望图片在上图片在下,如下图2,只需要简单的几行代码,即可实现. (1)因为需要处理多个按钮,所以将实 ...

  6. Android Studio设置图片背景及主题设置

    因为Android Studio是基于IDEA的,所以IDEA里面能用的插件Android Studio也能用,这次图片背景是依赖IDEA下的一个插件,名为BackgroundImage的插件,用户可 ...

  7. Android教程:ImageView 设置图片

    Android doc中是这样描述的: public void setImageResource (int resId) 这是其中的一个方法,参数resld是这样: ImageView.setImag ...

  8. PHP设置图片文件上传大小的具体实现方法

    PHP默认的上传限定是最大2M,想上传超过此设定的文件,需要调整PHP.apache等的一些参数 我们简要介绍一下PHP文件上传涉及到的一些参数: •file_uploads :是否允许通过HTTP上 ...

  9. ImageView 设置图片

      android doc中是这样描述的: public void setImageResource (int resId) 这是其中的一个方法,参数resld是这样: ImageView.setIm ...

随机推荐

  1. ajax+h5实现文件上传,成功即显示缩略图。

    官方参考文档: http://fex.baidu.com/webuploader/ 文件下载地址: https://github.com/fex-team/webuploader/releases/d ...

  2. 记intel杯比赛中各种bug与debug【其一】:安装intel caffe

    因为intel杯创新软件比赛过程中,并没有任何记录.现在用一点时间把全过程重演一次用作记录. 学习 pytorch 一段时间后,intel比赛突然不让用 pytoch 了,于是打算转战intel ca ...

  3. 洛谷 P3467 [POI2008]PLA-Postering

    P3467 [POI2008]PLA-Postering 题目描述 All the buildings in the east district of Byteburg were built in a ...

  4. 国庆 day 3 下午

    a[问题描述] 你是能看到第一题的 friends 呢. ——hja 给你一个只有小括号和中括号和大括号的括号序列,问该序列是否合法.[输入格式] 一行一个括号序列.[输出格式] 如果合法,输出 OK ...

  5. [Recompose] Compose Streams of React Props with Recompose’s compose and RxJS

    Functions created with mapPropsStream canned be composed together to build up powerful streams. Brin ...

  6. Design Pattern Adaptor 适配器设计模式

    适配器设计模式是为了要使用一个旧的接口,或许这个接口非常难用,或许是和新的更新的接口不兼容,所以须要设计一个适配器类,然后就能够让新旧的接口都统一. 就是这种一个图: watermark/2/text ...

  7. 【HDU 5402】Travelling Salesman Problem(构造)

    被某题卡SB了,结果这题也没读好...以为每一个格子能够有负数就当搜索做了.怎么想也搜只是去,后来发现每一个格子是非负数,那么肯定就是构造题. 题解例如以下: 首先假设nn为奇数或者mm为奇数,那么显 ...

  8. php 读取windows 的系统版本,硬盘,内存,网卡,数据流量等

    php 读取windows 的系统版本,硬盘,内存,网卡,数据流量等 <?php header("Content-type: text/html; charset=utf-8" ...

  9. @Transactional 事务注解

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE, rollbackFor = ...

  10. Aizu - 2555 Everlasting Zero 模拟

    Aizu - 2555 Everlasting Zero 题意:学习技能,每个技能有不同的要求,问能否学习全部特殊技能 思路:枚举每两个技能,得到他们的先后学习关系,如果两个都不能先学的话就是No了, ...