本文来自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. MYSQL8.0的安装方法

    1.下载zip安装包: MySQL8.0 For Windows zip包下载地址:https://dev.mysql.com/downloads/file/?id=476233,进入页面后可以不登录 ...

  2. 紫书 例题 10-18 UVa 11346(连续概率)

    就是面积计算,没什么好说的. #include<cstdio> #include<cmath> #define REP(i, a, b) for(int i = (a); i ...

  3. 紫书 例题 10-15 UVa 1638(递推)

    从大到小安排杆子 分三种情况 (1)插到最左边,那么左边看到了杆子会多一个 (2)插到最右边,那么右边看到了杆子会多一个 (3)插到中间边,那么不影响左边和右边看到的杆子数 具体看代码 #includ ...

  4. C语言移位

    先说左移,左移就是把一个数的所有位都向左移动若干位,在C中用<<运算符.例如: int i = 1;i = i << 2;  //把i里的值左移2位 也就是说,1的2进制是00 ...

  5. Spring Cloud分布式Session共享实践

    通常情况下,Tomcat.Jetty等Servlet容器,会默认将Session保存在内存中.如果是单个服务器实例的应用,将Session保存在服务器内存中是一个非常好的方案.但是这种方案有一个缺点, ...

  6. gpdb删除segment上残余的session和sql

    转载请注明出处:gpdb删除segment上残余的session和sql 最近公司的gpdb的变卡,导致线上系统查询队列阻塞,用户一点数据都查不出来. 每天早上我和同事都得用我们自家做的gpdb运维平 ...

  7. 计数排序、桶排序python实现

    计数排序在输入n个0到k之间的整数时,时间复杂度最好情况下为O(n+k),最坏情况下为O(n+k),平均情况为O(n+k),空间复杂度为O(n+k),计数排序是稳定的排序. 桶排序在输入N个数据有M个 ...

  8. .Net 跳转

    Action正常跳转 <a href="@Url.Action("AppDownload")">点击下载APP</a> public A ...

  9. thinkphp5项目--企业单车网站(三)

    thinkphp5项目--企业单车网站(三) 项目地址 fry404006308/BicycleEnterpriseWebsite: Bicycle Enterprise Websitehttps:/ ...

  10. Day2代码

    #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #defi ...