Android ImageView设置图片原理(上)
本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处!
首先关于图片加载到ImageView上,我们来讨论几个问题:
如下:
imageView.setImageResource(resId);获得图片资源运行在主线程
- This does Bitmap reading and decoding on the UI
- * thread, which can cause a latency hiccup. If that's a concern,
- * consider using {@link #setImageDrawable(android.graphics.drawable.Drawable)} or
- * {@link #setImageBitmap(android.graphics.Bitmap)} and
- * {@link android.graphics.BitmapFactory} instead.</p>
- *
- * @param resId the resource identifier of the the drawable
- *
- * @attr ref android.R.styleable#ImageView_src
- */
- @android.view.RemotableViewMethod
- public void setImageResource(int resId) {
- if (mUri != null || mResource != resId) {
- updateDrawable(null);
- mResource = resId;
- mUri = null;
- resolveUri();
- requestLayout();
- invalidate();
- }
- }
- private void resolveUri() {
- if (mDrawable != null) {
- return;
- }
- Resources rsrc = getResources();
- if (rsrc == null) {
- return;
- }
- Drawable d = null;
- if (mResource != 0) {
- try {
- d = rsrc.getDrawable(mResource);
- } catch (Exception e) {
- Log.w("ImageView", "Unable to find resource: " + mResource, e);
- // Don't try again.
- mUri = null;
- }
- } else if (mUri != null) {
从源码上看,mResource不为空,而mUri不为空,所以下面的方法咱们只贴出来一部分,可以看到,图片drawable值是通过Resource对象在UI线程中完成。方法上面的解释也可佐证,同时引出下面两个问题,由于SetImageResource会使UI线程延迟,所以可以考虑下面两种做法
imageView.setImageDrawable(drawable);获得图片资源运行在子线程
- /**
- * Sets a drawable as the content of this ImageView.
- *
- * @param drawable The drawable to set
- */
- public void setImageDrawable(Drawable drawable) {
- if (mDrawable != drawable) {
- mResource = 0;
- mUri = null;
- int oldWidth = mDrawableWidth;
- int oldHeight = mDrawableHeight;
- updateDrawable(drawable);
- if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
- requestLayout();
- }
- invalidate();
- }
- }
- private void updateDrawable(Drawable d) {
- if (mDrawable != null) {
- mDrawable.setCallback(null);
- unscheduleDrawable(mDrawable);
- }
- mDrawable = d;
- if (d != null) {
- d.setCallback(this);
- if (d.isStateful()) {
- d.setState(getDrawableState());
- }
- d.setLevel(mLevel);
- mDrawableWidth = d.getIntrinsicWidth();
- mDrawableHeight = d.getIntrinsicHeight();
- applyColorMod();
- configureBounds();
- } else {
- mDrawableWidth = mDrawableHeight = -1;
- }
- }
从源码上看,只需要把获得的值,解析一下,刷新到UI线程即可,所以Drawable对象可以在子线程中获取。
imageView.setImageBitmap(bm);获得图片资源可以运行在子线程,且可以改变图片大小
- /**
- * Sets a Bitmap as the content of this ImageView.
- *
- * @param bm The bitmap to set
- */
- @android.view.RemotableViewMethod
- public void setImageBitmap(Bitmap bm) {
- // if this is used frequently, may handle bitmaps explicitly
- // to reduce the intermediate drawable object
- setImageDrawable(new BitmapDrawable(mContext.getResources(), bm));
- }
- /**
- * Create drawable from a bitmap, setting initial target density based on
- * the display metrics of the resources.
- */
- public BitmapDrawable(Resources res, Bitmap bitmap) {
- this(new BitmapState(bitmap), res);
- mBitmapState.mTargetDensity = mTargetDensity;
- }
- private BitmapDrawable(BitmapState state, Resources res) {
- mBitmapState = state;
- if (res != null) {
- mTargetDensity = res.getDisplayMetrics().densityDpi;
- } else {
- mTargetDensity = state.mTargetDensity;
- }
- setBitmap(state != null ? state.mBitmap : null);
- }
- private void setBitmap(Bitmap bitmap) {
- if (bitmap != mBitmap) {
- mBitmap = bitmap;
- if (bitmap != null) {
- computeBitmapSize();
- } else {
- mBitmapWidth = mBitmapHeight = -1;
- }
- invalidateSelf();
- }
- }
SetImageBitmap同理,其实是通过BitmapDrawable获得一个Drawable对象,同setImageDrawable。值可以在子线程获得,在主界面刷新。
与此同时,有两个方法出现频率比较高,requestLayout和invalidate方法。
requestLayout:
- /**
- * Call this when something has changed which has invalidated the
- * layout of this view. This will schedule a layout pass of the view
- * tree.
- */
- public void requestLayout() {
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.REQUEST_LAYOUT);
- }
- mPrivateFlags |= FORCE_LAYOUT;
- mPrivateFlags |= INVALIDATED;
- if (mParent != null) {
- if (mLayoutParams != null) {
- mLayoutParams.resolveWithDirection(getResolvedLayoutDirection());
- }
- if (!mParent.isLayoutRequested()) {
- mParent.requestLayout();
- }
- }
- }
- * To intiate a layout, call {@link #requestLayout}. This method is typically
- * called by a view on itself when it believes that is can no longer fit within
- * its current bounds.
最主要的是这句,主要是当前View已经放不用所存放的值时,需要重新计算宽高
Invalidate():
- /**
- * Invalidate the whole view. If the view is visible,
- * {@link #onDraw(android.graphics.Canvas)} will be called at some point in
- * the future. This must be called from a UI thread. To call from a non-UI thread,
- * call {@link #postInvalidate()}.
- */
- public void invalidate() {
- invalidate(true);
- }
- /**
- * This is where the invalidate() work actually happens. A full invalidate()
- * causes the drawing cache to be invalidated, but this function can be called with
- * invalidateCache set to false to skip that invalidation step for cases that do not
- * need it (for example, a component that remains at the same dimensions with the same
- * content).
- *
- * @param invalidateCache Whether the drawing cache for this view should be invalidated as
- * well. This is usually true for a full invalidate, but may be set to false if the
- * View's contents or dimensions have not changed.
- */
- void invalidate(boolean invalidateCache) {
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
- }
- if (skipInvalidate()) {
- return;
- }
- if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
- (invalidateCache && (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) ||
- (mPrivateFlags & INVALIDATED) != INVALIDATED || isOpaque() != mLastIsOpaque) {
- mLastIsOpaque = isOpaque();
- mPrivateFlags &= ~DRAWN;
- mPrivateFlags |= DIRTY;
- if (invalidateCache) {
- mPrivateFlags |= INVALIDATED;
- mPrivateFlags &= ~DRAWING_CACHE_VALID;
- }
- final AttachInfo ai = mAttachInfo;
- final ViewParent p = mParent;
- //noinspection PointlessBooleanExpression,ConstantConditions
- if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
- if (p != null && ai != null && ai.mHardwareAccelerated) {
- // fast-track for GL-enabled applications; just invalidate the whole hierarchy
- // with a null dirty rect, which tells the ViewAncestor to redraw everything
- p.invalidateChild(this, null);
- return;
- }
- }
- if (p != null && ai != null) {
- final Rect r = ai.mTmpInvalRect;
- r.set(0, 0, mRight - mLeft, mBottom - mTop);
- // Don't call invalidate -- we don't want to internally scroll
- // our own bounds
- p.invalidateChild(this, r);
- }
- }
- }
把计算宽高、实际宽高、布局等刷新进来
- If either {@link #requestLayout()} or {@link #invalidate()} were called,
- * the framework will take care of measuring, laying out, and drawing the tree
- * as appropriate.
与此同时,我们还可以看到一个知识点postInvalidate
- /**
- * <p>Cause an invalidate to happen on a subsequent cycle through the event loop.
- * Use this to invalidate the View from a non-UI thread.</p>
- *
- * <p>This method can be invoked from outside of the UI thread
- * only when this View is attached to a window.</p>
- *
- * @see #invalidate()
- */
- public void postInvalidate() {
- postInvalidateDelayed(0);
- }
- /**
- * <p>Cause an invalidate to happen on a subsequent cycle through the event
- * loop. Waits for the specified amount of time.</p>
- *
- * <p>This method can be invoked from outside of the UI thread
- * only when this View is attached to a window.</p>
- *
- * @param delayMilliseconds the duration in milliseconds to delay the
- * invalidation by
- */
- public void postInvalidateDelayed(long delayMilliseconds) {
- // We try only with the AttachInfo because there's no point in invalidating
- // if we are not attached to our window
- AttachInfo attachInfo = mAttachInfo;
- if (attachInfo != null) {
- Message msg = Message.obtain();
- msg.what = AttachInfo.INVALIDATE_MSG;
- msg.obj = this;
- attachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
- }
- }
这个刷新会排到消息队列去刷新,也就是在空闲时刷新,相对来说可以减少阻塞,此任务优先级稍低,当然我们可以加入延迟时间来相对自定义优先级。
在开发过程中,大概会遇到这样的情况,在布局的时候,需要图片的宽度或长度;或者图片太大,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值。
Android ImageView设置图片原理(上)的更多相关文章
- Android ImageView设置图片原理(下)
本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 写完上一篇后,总认为介绍的知识点不多,仅仅是一种在UI线程解析载入图片.两种在子线程解析,在UI线程 ...
- Android开发模板代码(二)——为ImageView设置图片,退出后能保存ImageView的状态
接着之前的那个从图库选择图片,设置到ImageView中去,但是,我发现了一个问题,就是再次进入的时候ImageView是恢复到了默认状态,搜索了资料许久之后,终于是发现了解决方法,使用SharePr ...
- Java开发桌面程序学习(七)——ImageView设置图片以及jar包读取fxml文件
ImageView设置图片 JavaFx的ImageView,设置图片不能直接通过属性设置,只能通过代码来设置 ImageView设置图片 首先,我们让fxml对应的那个controller的java ...
- Android -- ImageView(控制图片的大小以及旋转的角度)
1.
- iOS按钮设置图片在上文字在下
UIButton同时设置Title和Image后,默认是图片在左文字在右,如下图1,很多情况下我们希望图片在上图片在下,如下图2,只需要简单的几行代码,即可实现. (1)因为需要处理多个按钮,所以将实 ...
- Android Studio设置图片背景及主题设置
因为Android Studio是基于IDEA的,所以IDEA里面能用的插件Android Studio也能用,这次图片背景是依赖IDEA下的一个插件,名为BackgroundImage的插件,用户可 ...
- Android教程:ImageView 设置图片
Android doc中是这样描述的: public void setImageResource (int resId) 这是其中的一个方法,参数resld是这样: ImageView.setImag ...
- PHP设置图片文件上传大小的具体实现方法
PHP默认的上传限定是最大2M,想上传超过此设定的文件,需要调整PHP.apache等的一些参数 我们简要介绍一下PHP文件上传涉及到的一些参数: •file_uploads :是否允许通过HTTP上 ...
- ImageView 设置图片
android doc中是这样描述的: public void setImageResource (int resId) 这是其中的一个方法,参数resld是这样: ImageView.setIm ...
随机推荐
- Hadoop集群配置搭建
环境:Centos 6.9,Hadoop 2.7.1,JDK 1.8.0_161,Maven 3.3.9 前言: 1.配置一台master服务器,两台或多台slave服务器. 2.master可 ...
- 杯子 (glass)
题目 试题1:杯子 (glass) 源代码:glass.cpp 输入文件:glass.in 输出文件:glass.out 时间限制:1s 空间限制:256MB 题目描述 小明买了N个容积可以 ...
- Java基础学习总结(29)——浅谈Java中的Set、List、Map的区别
就学习经验,浅谈Java中的Set,List,Map的区别,对JAVA的集合的理解是想对于数组: 数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型),JAVA集合可以存储和操 ...
- Myeclipse学习总结(4)——Eclipse常用开发插件
(1) AmaterasUML 介绍:Eclipse的UML插件,支持UML活动图,class图,sequence图,usecase图等:支持与Java class/interf ...
- gpdb删除segment上残余的session和sql
转载请注明出处:gpdb删除segment上残余的session和sql 最近公司的gpdb的变卡,导致线上系统查询队列阻塞,用户一点数据都查不出来. 每天早上我和同事都得用我们自家做的gpdb运维平 ...
- 通过C语言程序改动控制台的背景和前景颜色
本文主要解说怎样通过C语言来改动dos背景和前景颜色.我们首先来看一下dos的背景颜色的属性. 打开開始菜单,点击执行,弹出执行对话框.输入cmd,回车. (打开dos控制台) 在命令提示符界面下,输 ...
- Android资源之图像资源(状态图像资源)
在上一篇博文中.我主要解说了XML图像资源中的图层资源,在此图像资源博文中我会给大家陆续解说XMl图像资源的图像状态资源.图像级别资源.淡入淡出资源.嵌入图像资源.剪切图像资源和外形资源. 1.图像状 ...
- 手把手教你如何在Ubuntu系统中安装Pycharm
前几天带大家一起安装了Ubuntu14.04系统,没来得及上车的伙伴可以戳这篇文章:手把手教你在VMware虚拟机中安装Ubuntu14.04系统.今天小编带大家一起在Ubuntu14.04中安装Py ...
- vuex 快速入门( 基于vue2.0,vue1.0未知可否)
1.原理概述 2.用户登录例子解析: 由上图可以看到: 1.组件的数据是username,我们把它以name放在state中: 2.更改name发生在mutations的回调里,事件名字是showUs ...
- 现实人脸识别性别之路----弄清楚train_test_split函数
'''train_test_split(trian_data,trian_target,test_size,random_state)各个参数表示的意义:trian_data表示被划分的样本特征集tr ...
