http://blog.csdn.net/u011733020/article/details/46058273
接上一篇 往下写 http://blog.csdn.net/u011733020/article/details/45998861 , 非常感谢在上一篇中给我指出问题的兄弟们。
面试公司:五道口 某公司
面试时间: 5月27日 11:00 AM.
面试过程:
感觉公司还是挺有活力的的,进去填了申请表,人事就跟我聊了下 从上家离职原因(找工作 要准备怎么回答这个问题,最好能找一些客观因素,不要说 感觉以前公司不好。。。)
随后 就是 android 技术 跟我面试。大概面试了 四十分钟吧。惯例 总结了一下 有六七个问题,这个技术水平比较高,问得问题 有几个我开发中都没有遇到过。这次面试感觉 没戏。。。
不过 失败乃成功之父。不气馁
面试官01问 : 解析json。
类似这样的 {
"11:00": "0",
"12:00": "0",
"13:00": "0",
"14:00": "0",
"15:00": "0",
"16:00": "0",
"17:00": "0",
"18:00": "0",
"19:00": "0",
"20:00": "0",
"21:00": "0",
"22:00": "0 "
}
这个平时开发中没碰到这种情况,自己也懒,没有看还有什么解析方法 说以当时只是说,解析json 源码 其实跟解析xml 类似 都是 遍历每一级,存到map集合中。知道应该有方法可以取到,但是 却没有想到 通过iterator。
J哥回答 :这里 当时没能回答上方法,回来 看过解析json 的源码 其实就是 存到一个HashMap<key,value>集合中
其实解析很简单 就是先转成JsonObject 然后拿到迭代器, 遍历集合就可以取到 value。
代码很简单
try { obj = new JSONObject(json); Iterator iterator = obj.keys(); while (iterator.hasNext()){ Object next = iterator.next(); obj.get(next.toString()); } } catch (JSONException e) { e.printStackTrace(); }
平时不在意 ,关键时刻掉链子!!!
面试官01问 :Listview 如果有多种类型的 item ,怎么实现。
J哥回答 :这个问题,被问到的概率还是挺大的,自己以前 开发也没遇到这样的需求,也没有去了解,所以回答的都不是很好。
这里 我回来查找资料,才发现,google 开发者 已经 考虑到这种情况,做了相应的支持,所以listview 本身是支持item 多type的。
通常我们在使用listview 给 listview 适配数据的时候,用到adapter,以及 四个方法 getCount getItem getItemId getView,那么 在我们 多type 的item 时候,我们需要去复写 两个方法 getItemViewType getViewTypeCount, 着两个方法的的意思是
getViewTypeCount:
Returns the number of types of Views that will be created bygetView
. Each type represents a set of views that can be converted ingetView
. If the adapter always returns the same type of View for all items, this method should return 1.
This method will only be called when when the adapter is set on the theAdapterView
.
Returns:
The number of types of Views that will be created by this adapter
意思是 返回 getview 时 产生的 item 的 类型的个数,如果 我们的listview 中所有的item 只有一种类型 ,那么我们不需要复写这个方法,这个方法 当我们给listview setAdapter 的时候 被调用。
因为 可以在baseAdapter 中发现 ,默认值 就是 1.
public int getViewTypeCount() { return 1 ; }
另一个方法
getItemViewType
Get the type of View that will be created by getView
for the specified item.
Parameters:
position The position of the item within the adapter's data set whose view type we want.
Returns:
An integer representing the type of View. Two views should share the same type if one can be converted to the other in
getView
. Note: Integers must be in the range 0 to
getViewTypeCount
- 1.
IGNORE_ITEM_VIEW_TYPE
can also be returned
这个方法 返回 将要被 getview 创建的 item的 类型 。
返回值 范围 0 ~~~~
到 类型type-1。
就是 这两个关键的方法,要想我们实现多type 我们就要实现这两个方法。
效果就是这样子。
代码实现 跟单一 item 唯一的区别 就在上述两个方法 和 getview 方法中增加了判断当前类型。下面Adapter中部分代码
@Override public View getView( int position, View convertView, ViewGroup parent) { int type = list.get(position).type; int itemViewType = getItemViewType(position); System.out.println("type===itemViewType" +(itemViewType==type)); if (getItemViewType(position)== 0 ){ convertView =inflater.inflate( R.layout.item01_layout, parent, false ); return convertView; }else if (getItemViewType(position)== 1 ){ convertView =inflater.inflate( R.layout.item02_layout, parent, false ); return convertView; }else { convertView =inflater.inflate( R.layout.item03_layout, parent, false ); return convertView; } } @Override public int getItemViewType( int position) { System.out.println("getItemViewType-------------------------------" +list.get(position).type); return list.get(position).type; } @Override public int getViewTypeCount() { return maxType; }
上面这里 并没有考虑过 convertview 的复用, 但是如果 有很多条的话,我们就不能这么简单的用了,要复用的话,我们要分别判断 type类型,和 convertview 去实现复用, 这里如果type 很多 复用的话,在getview 方法里面要写很多 判断,假如 type==0 inflate 一个layout01,type==2 inflate 一个layout02....假如有十个 那么 我们的getview方法里要分别判断 十次type 而且还要判断 convetview==null,所以 类型多了的话,这个方法写起来逻辑 可读性都不好,
然而我有没想到什么好办法,网上搜了点资料,这个感觉还是不错的,用这种方式 虽然 要写很多类,但是感觉不用把所有的代码都写在一个getview中。如果 有什么好方法 可以一起分享出来。
面试官01问 :可以手动缩放的图片 怎么去实现。
J哥回答 :由于 自己展示中的项目用到了 开源的
PhotoView , 所以 被问到自己实现。当时自己也没有看 源码,只是知道类似的,touchevent,
知道 两点触摸时间,那是关于图片 拖拽的, 实现的关键 就是 touch 时间的监听,对于 手指按下, 手机移动,手指离开的监听,记录初始的xy ,以及离开时的 xy,进行相应的缩放,在onlayout ondraw. 关于 photoview 的分析,自己找了些资料,这里有一篇分析,感兴趣的可以看一下,个人感觉还不错。地址 。
面试官01问 :ImageLoader 源码 分析
原理 这张图 表达的比较清楚
使用方法 一般是
ImageLoader.getInstance().displayImage(picurl, imageview);
这个ViewAware 对象 里面 有一个 weakReference, 是的。 图片在内存中就是 通过这个 弱引用缓存的。
Implements a weak reference, which is the middle of the three types of references. Once the garbage collector decides that an objectobj
is is weakly-reachable, the following happens:
A set ref
of references is determined. ref
contains the following elements:
All weak references pointing to obj
. All weak references pointing to objects from which obj
is either strongly or softly reachable. All references in ref
are atomically cleared. All objects formerly being referenced by ref
become eligible for finalization. At some future point, all references in ref
will be enqueued with their corresponding reference queues, if any. Weak references are useful for mappings that should have their entries removed automatically once they are not referenced any more (from outside). The difference between a
SoftReference
and a
WeakReference
is the point of time at which the decision is made to clear and enqueue the reference:
A SoftReference
should be cleared and enqueued as late as possible , that is, in case the VM is in danger of running out of memory. A WeakReference
may be cleared and enqueued as soon as is known to be weakly-referenced. 上面 是对于weakreference 的注释
WeakReference实现了一个弱引用,弱引用是三种引用(StrongReference、WeakReference、SoftReference)中的一个。一旦垃圾回收器判定一个对象是是弱获取(对象可获取程度分为五种strongly reachable,softly reachable、weakly reachable、phantomly reachable、unreachable),则下列情况发生:
计算一组引用的ref,ref包括下列元素:
所有指向obj的弱引用
所有指向objects的弱引用,objects是软获取对象或者是强获取对象
在ref中的所有引用被自动删除
所有以前被ref引用的对象都符合终止条件的对象(become eligible for finalization)
在未来的某个时间,所有的在ref中的引用将被放入合适的引用队列中
弱引用对那些映射,这些映射中的实体的引用一旦被不存在这些实体将被自动删除。弱引用和软引用的区别是清空和将加入排队的时间点不同:
一个弱引用应该尽可能晚的被清除和加入队列,那是因为如果内存不足是vm将是危险的
弱引用对象是一旦知道引用的是弱获取对象就会被清除和入队。
就是 在 JVM 内存不足的时候 GC 会优先回收这个 设置了 WeakReference 的对象。
在继续看Display 方法
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) { checkConfiguration(); if (imageAware == null ) { throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS); } if (listener == null ) { listener = defaultListener; } if (options == null ) { options = configuration.defaultDisplayImageOptions; } if (TextUtils.isEmpty(uri)) { engine.cancelDisplayTaskFor(imageAware); listener.onLoadingStarted(uri, imageAware.getWrappedView()); if (options.shouldShowImageForEmptyUri()) { imageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources)); } else { imageAware.setImageDrawable(null ); } listener.onLoadingComplete(uri, imageAware.getWrappedView(), null ); return ; } ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize()); String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize); engine.prepareDisplayTaskFor(imageAware, memoryCacheKey); listener.onLoadingStarted(uri, imageAware.getWrappedView()); Bitmap bmp = configuration.memoryCache.get(memoryCacheKey); if (bmp != null && !bmp.isRecycled()) { L.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey); if (options.shouldPostProcess()) { ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, engine.getLockForUri(uri)); ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo, defineHandler(options)); if (options.isSyncLoading()) { displayTask.run(); } else { engine.submit(displayTask); } } else { options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE); listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp); } } else { if (options.shouldShowImageOnLoading()) { imageAware.setImageDrawable(options.getImageOnLoading(configuration.resources)); } else if (options.isResetViewBeforeLoading()) { imageAware.setImageDrawable(null ); } ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, engine.getLockForUri(uri)); LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo, defineHandler(options)); if (options.isSyncLoading()) { displayTask.run(); } else { engine.submit(displayTask); } } }
代码太多,不一一贴出来了,在下载图片的task 方法中,会 做一些 线程安全的同步,还有就是判断本地 内存 有没有以前下载好了,有的话直接拿过来用,没有 去下载 然后试着保存在磁盘缓存中
private boolean downloadImage() throws IOException { InputStream is = getDownloader().getStream(uri, options.getExtraForDownloader()); if (is == null ) { L.e(ERROR_NO_IMAGE_STREAM, memoryCacheKey); return false ; } else { try { return configuration.diskCache.save(uri, is, this ); } finally { IoUtils.closeSilently(is); } } }
面试官01问 : 大图片 加载 oom 问题
J哥回答 : 对于大图片,直接加载给Imageview 容易出现 OOM 异常,那么我们就要对其进行压缩, 压缩原理,根据手机分辨率 去压缩
首先获取手机分辨率:
WindowManager windowManager= (WindowManager)getSystemService(WINDOW_SERVICE); Display display= windowManager.getDefaultDisplay(); height = display.getHeight(); width = display.getWidth();
然后 计算图片的宽度高度,根据比例压缩 在显示 图片
public void calImageView(){ BitmapFactory.Options options= new BitmapFactory.Options(); options.inJustDecodeBounds=true ; String path="" ; BitmapFactory.decodeFile(path, options); int ImageWidth= options.outWidth; int ImageHeight= options.outHeight; System.out.print("ImageWidth:" + ImageWidth); System.out.print("ImageHeight:" +ImageHeight); int scaleX=ImageWidth/width; int scaleY=ImageHeight/height; int scale= 1 ; if (scaleX>scaleY & scaleY>= 1 ){ scale=scaleX; } if (scaleY>scaleX & scaleX>= 1 ){ scale=scaleY; } options.inJustDecodeBounds=false ; options.inSampleSize=scale; Bitmap bitmap= BitmapFactory.decodeFile("/storage/emulated/a.jpg" , options); iv.setImageBitmap(bitmap); }
接上一篇 往下写 http://blog.csdn.net/u011733020/article/details/45998861 , 非常感谢在上一篇中给我指出问题的兄弟们。
面试公司:五道口 某公司
面试时间: 5月27日 11:00 AM.
面试过程:
感觉公司还是挺有活力的的,进去填了申请表,人事就跟我聊了下 从上家离职原因(找工作 要准备怎么回答这个问题,最好能找一些客观因素,不要说 感觉以前公司不好。。。)
随后 就是 android 技术 跟我面试。大概面试了 四十分钟吧。惯例 总结了一下 有六七个问题,这个技术水平比较高,问得问题 有几个我开发中都没有遇到过。这次面试感觉 没戏。。。
不过 失败乃成功之父。不气馁
面试官01问 : 解析json。
类似这样的 {
"11:00": "0",
"12:00": "0",
"13:00": "0",
"14:00": "0",
"15:00": "0",
"16:00": "0",
"17:00": "0",
"18:00": "0",
"19:00": "0",
"20:00": "0",
"21:00": "0",
"22:00": "0 "
}
这个平时开发中没碰到这种情况,自己也懒,没有看还有什么解析方法 说以当时只是说,解析json 源码 其实跟解析xml 类似 都是 遍历每一级,存到map集合中。知道应该有方法可以取到,但是 却没有想到 通过iterator。
J哥回答 :这里 当时没能回答上方法,回来 看过解析json 的源码 其实就是 存到一个HashMap<key,value>集合中
其实解析很简单 就是先转成JsonObject 然后拿到迭代器, 遍历集合就可以取到 value。
代码很简单
try { obj = new JSONObject(json); Iterator iterator = obj.keys(); while (iterator.hasNext()){ Object next = iterator.next(); obj.get(next.toString()); } } catch (JSONException e) { e.printStackTrace(); }
平时不在意 ,关键时刻掉链子!!!
面试官01问 :Listview 如果有多种类型的 item ,怎么实现。
J哥回答 :这个问题,被问到的概率还是挺大的,自己以前 开发也没遇到这样的需求,也没有去了解,所以回答的都不是很好。
这里 我回来查找资料,才发现,google 开发者 已经 考虑到这种情况,做了相应的支持,所以listview 本身是支持item 多type的。
通常我们在使用listview 给 listview 适配数据的时候,用到adapter,以及 四个方法 getCount getItem getItemId getView,那么 在我们 多type 的item 时候,我们需要去复写 两个方法 getItemViewType getViewTypeCount, 着两个方法的的意思是
getViewTypeCount:
Returns the number of types of Views that will be created bygetView
. Each type represents a set of views that can be converted ingetView
. If the adapter always returns the same type of View for all items, this method should return 1.
This method will only be called when when the adapter is set on the theAdapterView
.
Returns:
The number of types of Views that will be created by this adapter
意思是 返回 getview 时 产生的 item 的 类型的个数,如果 我们的listview 中所有的item 只有一种类型 ,那么我们不需要复写这个方法,这个方法 当我们给listview setAdapter 的时候 被调用。
因为 可以在baseAdapter 中发现 ,默认值 就是 1.
public int getViewTypeCount() { return 1 ; }
另一个方法
getItemViewType
Get the type of View that will be created by getView
for the specified item.
Parameters:
position The position of the item within the adapter's data set whose view type we want.
Returns:
An integer representing the type of View. Two views should share the same type if one can be converted to the other in
getView
. Note: Integers must be in the range 0 to
getViewTypeCount
- 1.
IGNORE_ITEM_VIEW_TYPE
can also be returned
这个方法 返回 将要被 getview 创建的 item的 类型 。
返回值 范围 0 ~~~~
到 类型type-1。
就是 这两个关键的方法,要想我们实现多type 我们就要实现这两个方法。
效果就是这样子。
代码实现 跟单一 item 唯一的区别 就在上述两个方法 和 getview 方法中增加了判断当前类型。下面Adapter中部分代码
@Override public View getView( int position, View convertView, ViewGroup parent) { int type = list.get(position).type; int itemViewType = getItemViewType(position); System.out.println("type===itemViewType" +(itemViewType==type)); if (getItemViewType(position)== 0 ){ convertView =inflater.inflate( R.layout.item01_layout, parent, false ); return convertView; }else if (getItemViewType(position)== 1 ){ convertView =inflater.inflate( R.layout.item02_layout, parent, false ); return convertView; }else { convertView =inflater.inflate( R.layout.item03_layout, parent, false ); return convertView; } } @Override public int getItemViewType( int position) { System.out.println("getItemViewType-------------------------------" +list.get(position).type); return list.get(position).type; } @Override public int getViewTypeCount() { return maxType; }
上面这里 并没有考虑过 convertview 的复用, 但是如果 有很多条的话,我们就不能这么简单的用了,要复用的话,我们要分别判断 type类型,和 convertview 去实现复用, 这里如果type 很多 复用的话,在getview 方法里面要写很多 判断,假如 type==0 inflate 一个layout01,type==2 inflate 一个layout02....假如有十个 那么 我们的getview方法里要分别判断 十次type 而且还要判断 convetview==null,所以 类型多了的话,这个方法写起来逻辑 可读性都不好,
然而我有没想到什么好办法,网上搜了点资料,这个感觉还是不错的,用这种方式 虽然 要写很多类,但是感觉不用把所有的代码都写在一个getview中。如果 有什么好方法 可以一起分享出来。
面试官01问 :可以手动缩放的图片 怎么去实现。
J哥回答 :由于 自己展示中的项目用到了 开源的
PhotoView , 所以 被问到自己实现。当时自己也没有看 源码,只是知道类似的,touchevent,
知道 两点触摸时间,那是关于图片 拖拽的, 实现的关键 就是 touch 时间的监听,对于 手指按下, 手机移动,手指离开的监听,记录初始的xy ,以及离开时的 xy,进行相应的缩放,在onlayout ondraw. 关于 photoview 的分析,自己找了些资料,这里有一篇分析,感兴趣的可以看一下,个人感觉还不错。地址 。
面试官01问 :ImageLoader 源码 分析
原理 这张图 表达的比较清楚
使用方法 一般是
ImageLoader.getInstance().displayImage(picurl, imageview);
这个ViewAware 对象 里面 有一个 weakReference, 是的。 图片在内存中就是 通过这个 弱引用缓存的。
Implements a weak reference, which is the middle of the three types of references. Once the garbage collector decides that an objectobj
is is weakly-reachable, the following happens:
A set ref
of references is determined. ref
contains the following elements:
All weak references pointing to obj
. All weak references pointing to objects from which obj
is either strongly or softly reachable. All references in ref
are atomically cleared. All objects formerly being referenced by ref
become eligible for finalization. At some future point, all references in ref
will be enqueued with their corresponding reference queues, if any. Weak references are useful for mappings that should have their entries removed automatically once they are not referenced any more (from outside). The difference between a
SoftReference
and a
WeakReference
is the point of time at which the decision is made to clear and enqueue the reference:
A SoftReference
should be cleared and enqueued as late as possible , that is, in case the VM is in danger of running out of memory. A WeakReference
may be cleared and enqueued as soon as is known to be weakly-referenced. 上面 是对于weakreference 的注释
WeakReference实现了一个弱引用,弱引用是三种引用(StrongReference、WeakReference、SoftReference)中的一个。一旦垃圾回收器判定一个对象是是弱获取(对象可获取程度分为五种strongly reachable,softly reachable、weakly reachable、phantomly reachable、unreachable),则下列情况发生:
计算一组引用的ref,ref包括下列元素:
所有指向obj的弱引用
所有指向objects的弱引用,objects是软获取对象或者是强获取对象
在ref中的所有引用被自动删除
所有以前被ref引用的对象都符合终止条件的对象(become eligible for finalization)
在未来的某个时间,所有的在ref中的引用将被放入合适的引用队列中
弱引用对那些映射,这些映射中的实体的引用一旦被不存在这些实体将被自动删除。弱引用和软引用的区别是清空和将加入排队的时间点不同:
一个弱引用应该尽可能晚的被清除和加入队列,那是因为如果内存不足是vm将是危险的
弱引用对象是一旦知道引用的是弱获取对象就会被清除和入队。
就是 在 JVM 内存不足的时候 GC 会优先回收这个 设置了 WeakReference 的对象。
在继续看Display 方法
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) { checkConfiguration(); if (imageAware == null ) { throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS); } if (listener == null ) { listener = defaultListener; } if (options == null ) { options = configuration.defaultDisplayImageOptions; } if (TextUtils.isEmpty(uri)) { engine.cancelDisplayTaskFor(imageAware); listener.onLoadingStarted(uri, imageAware.getWrappedView()); if (options.shouldShowImageForEmptyUri()) { imageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources)); } else { imageAware.setImageDrawable(null ); } listener.onLoadingComplete(uri, imageAware.getWrappedView(), null ); return ; } ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize()); String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize); engine.prepareDisplayTaskFor(imageAware, memoryCacheKey); listener.onLoadingStarted(uri, imageAware.getWrappedView()); Bitmap bmp = configuration.memoryCache.get(memoryCacheKey); if (bmp != null && !bmp.isRecycled()) { L.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey); if (options.shouldPostProcess()) { ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, engine.getLockForUri(uri)); ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo, defineHandler(options)); if (options.isSyncLoading()) { displayTask.run(); } else { engine.submit(displayTask); } } else { options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE); listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp); } } else { if (options.shouldShowImageOnLoading()) { imageAware.setImageDrawable(options.getImageOnLoading(configuration.resources)); } else if (options.isResetViewBeforeLoading()) { imageAware.setImageDrawable(null ); } ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, engine.getLockForUri(uri)); LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo, defineHandler(options)); if (options.isSyncLoading()) { displayTask.run(); } else { engine.submit(displayTask); } } }
代码太多,不一一贴出来了,在下载图片的task 方法中,会 做一些 线程安全的同步,还有就是判断本地 内存 有没有以前下载好了,有的话直接拿过来用,没有 去下载 然后试着保存在磁盘缓存中
private boolean downloadImage() throws IOException { InputStream is = getDownloader().getStream(uri, options.getExtraForDownloader()); if (is == null ) { L.e(ERROR_NO_IMAGE_STREAM, memoryCacheKey); return false ; } else { try { return configuration.diskCache.save(uri, is, this ); } finally { IoUtils.closeSilently(is); } } }
面试官01问 : 大图片 加载 oom 问题
J哥回答 : 对于大图片,直接加载给Imageview 容易出现 OOM 异常,那么我们就要对其进行压缩, 压缩原理,根据手机分辨率 去压缩
首先获取手机分辨率:
WindowManager windowManager= (WindowManager)getSystemService(WINDOW_SERVICE); Display display= windowManager.getDefaultDisplay(); height = display.getHeight(); width = display.getWidth();
然后 计算图片的宽度高度,根据比例压缩 在显示 图片
public void calImageView(){ BitmapFactory.Options options= new BitmapFactory.Options(); options.inJustDecodeBounds=true ; String path="" ; BitmapFactory.decodeFile(path, options); int ImageWidth= options.outWidth; int ImageHeight= options.outHeight; System.out.print("ImageWidth:" + ImageWidth); System.out.print("ImageHeight:" +ImageHeight); int scaleX=ImageWidth/width; int scaleY=ImageHeight/height; int scale= 1 ; if (scaleX>scaleY & scaleY>= 1 ){ scale=scaleX; } if (scaleY>scaleX & scaleX>= 1 ){ scale=scaleY; } options.inJustDecodeBounds=false ; options.inSampleSize=scale; Bitmap bitmap= BitmapFactory.decodeFile("/storage/emulated/a.jpg" , options); iv.setImageBitmap(bitmap); }