*Android面试实战总结2

 接上一篇 往下写 http://blog.csdn.net/u011733020/article/details/45998861  ,   非常感谢在上一篇中给我指出问题的兄弟们。

面试公司:五道口 某公司

面试过程:

感觉公司还是挺有活力的的,进去填了申请表,人事就跟我聊了下 从上家离职原因(找工作 要准备怎么回答这个问题,最好能找一些客观因素,不要说 感觉以前公司不好。。。)

随后 就是 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。

代码很简单

[java] view plain copy

print?

  1. try {  
  2.             obj = new JSONObject(json);  
  3.             Iterator iterator = obj.keys();  
  4. while(iterator.hasNext()){  
  5.                 Object next = iterator.next();// 获取到 key
  6.                  obj.get(next.toString());// 获取到 value
  7.             }  
  8.         } catch (JSONException e) {  
  9. // TODO Auto-generated catch block
  10.             e.printStackTrace();  
  11.         }  

平时不在意 ,关键时刻掉链子!!!

面试官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.

Overrides:getViewTypeCount() inBaseAdapter

Returns:The number of types of Views that will be created by this adapter意思是 返回  getview 时 产生的 item 的 类型的个数,如果 我们的listview 中所有的item 只有一种类型 ,那么我们不需要复写这个方法,这个方法 当我们给listview  setAdapter 的时候 被调用。因为 可以在baseAdapter  中发现  ,默认值 就是 1.

[java] view plain copy

print?

  1. public int getViewTypeCount() {  
  2. return 1;  
  3.    }  

另一个方法  getItemViewType   

Get the type of View that will be created bygetView for the specified item.

Specified by:getItemViewType(...) inAdapter

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 ingetView. Note: Integers must be in the range 0 togetViewTypeCount - 1.IGNORE_ITEM_VIEW_TYPE can also be returned 这个方法 返回 将要被 getview 创建的 item的 类型 。返回值  范围 0   ~~~~  到 类型type-1。 就是 这两个关键的方法,要想我们实现多type 我们就要实现这两个方法。

效果就是这样子。

代码实现 跟单一 item 唯一的区别 就在上述两个方法 和 getview 方法中增加了判断当前类型。下面Adapter中部分代码

[java] view plain copy

print?

  1. @Override
  2. public View getView(int position, View convertView, ViewGroup parent) {  
  3. int type = list.get(position).type;  
  4. int itemViewType = getItemViewType(position);  
  5.     System.out.println("type===itemViewType"+(itemViewType==type));  
  6. if(getItemViewType(position)==0){  
  7.             convertView =inflater.inflate(  
  8.                     R.layout.item01_layout, parent, false);  
  9. return convertView;  
  10.     }else if(getItemViewType(position)==1){  
  11.         convertView =inflater.inflate(  
  12.                 R.layout.item02_layout, parent, false);  
  13. return convertView;  
  14.     }else{  
  15.         convertView =inflater.inflate(  
  16.                 R.layout.item03_layout, parent, false);  
  17. return convertView;  
  18.     }  
  19. }  
  20. @Override
  21. public int getItemViewType(int position) {  
  22.     System.out.println("getItemViewType-------------------------------"+list.get(position).type);  
  23. return list.get(position).type;  
  24. }  
  25. @Override
  26. public int getViewTypeCount() {  
  27. return maxType;  
  28. }  

 上面这里 并没有考虑过 convertview 的复用, 但是如果 有很多条的话,我们就不能这么简单的用了,要复用的话,我们要分别判断 type类型,和 convertview 去实现复用,  这里如果type 很多 复用的话,在getview 方法里面要写很多 判断,假如 type==0 inflate 一个layout01,type==2 inflate  一个layout02....假如有十个 那么 我们的getview方法里要分别判断 十次type 而且还要判断 convetview==null,所以 类型多了的话,这个方法写起来逻辑 可读性都不好,然而我有没想到什么好办法,网上搜了点资料,这个感觉还是不错的,用这种方式 虽然 要写很多类,但是感觉不用把所有的代码都写在一个getview中。如果 有什么好方法 可以一起分享出来。

listview 多type 复用 convertview 的解决方法

面试官01问:可以手动缩放的图片 怎么去实现。

J哥回答:由于 自己展示中的项目用到了 开源的  PhotoView, 所以 被问到自己实现。当时自己也没有看 源码,只是知道类似的,touchevent,

知道 两点触摸时间,那是关于图片 拖拽的, 实现的关键 就是 touch 时间的监听,对于 手指按下, 手机移动,手指离开的监听,记录初始的xy ,以及离开时的 xy,进行相应的缩放,在onlayout  ondraw.  关于 photoview 的分析,自己找了些资料,这里有一篇分析,感兴趣的可以看一下,个人感觉还不错。地址

面试官01问:ImageLoader 源码 分析

J哥回答: 开发中,多多少少都能接触到异步加载图片,大家知道 universalImageLoader (github 地址 https://github.com/nostra13/Android-Universal-Image-Loader)加载图片 可以有效地防止 因为图片导致的oom。由于是开源,封装的不错,所以 一般项目中 都直接拿过来用,关于imageloader 的使用方法 这里就不介绍了, 大体思路肯定 是 使用了缓存,在保证效率的前提下 合理节约资源, 一般第一次加载 都是从网络加载,然后判断是不是要保存在本地,顺便将图片在内存保存一下。 

原理 这张图 表达的比较清楚

使用方法 一般是  

[java] view plain copy

print?

  1. ImageLoader.getInstance().displayImage(picurl, imageview);//传入 图片url 和 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 toobj.
    • All weak references pointing to objects from whichobj is either strongly or softly reachable.
  • All references in ref are atomically cleared.
  • All objects formerly being referenced byref become eligible for finalization.
  • At some future point, all references inref 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 aSoftReference and aWeakReference is the point of time at which the decision is made to clear and enqueue the reference:

  • SoftReference should be cleared and enqueuedas late as possible, that is, in case the VM is in danger of running out of memory.
  • 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 的对象。

对于weakreference 的理解 还可以看下这篇文章 http://wiseideal.iteye.com/blog/1469295

在继续看Display 方法 

[java] view plain copy

print?

  1. public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,  
  2.         ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {  
  3.     checkConfiguration();  
  4. if (imageAware == null) {  
  5. throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS);  
  6.     }  
  7. if (listener == null) {  
  8.         listener = defaultListener;  
  9.     }  
  10. if (options == null) {  
  11.         options = configuration.defaultDisplayImageOptions;  
  12.     }  
  13. if (TextUtils.isEmpty(uri)) { // 判断传入的地址是否为空
  14.         engine.cancelDisplayTaskFor(imageAware);  
  15.         listener.onLoadingStarted(uri, imageAware.getWrappedView());  
  16. if (options.shouldShowImageForEmptyUri()) {//  是否设置了默认的图片
  17.             imageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources));  
  18.         } else {  
  19.             imageAware.setImageDrawable(null);  
  20.         }  
  21.         listener.onLoadingComplete(uri, imageAware.getWrappedView(), null);//加载完成的回调
  22. return;  
  23.     }  
  24.     ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize());  
  25.     String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize);  
  26.     engine.prepareDisplayTaskFor(imageAware, memoryCacheKey);  
  27.     listener.onLoadingStarted(uri, imageAware.getWrappedView());  
  28.     Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);  
  29. if (bmp != null && !bmp.isRecycled()) {  
  30.         L.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey);  
  31. if (options.shouldPostProcess()) {  
  32.             ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,  
  33.                     options, listener, progressListener, engine.getLockForUri(uri));  
  34.             ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo,  
  35.                     defineHandler(options));  
  36. if (options.isSyncLoading()) {  
  37.                 displayTask.run();  
  38.             } else {  
  39.                 engine.submit(displayTask);  
  40.             }  
  41.         } else {  
  42.             options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);  
  43.             listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);  
  44.         }  
  45.     } else {  
  46. if (options.shouldShowImageOnLoading()) {  
  47.             imageAware.setImageDrawable(options.getImageOnLoading(configuration.resources));  
  48.         } else if (options.isResetViewBeforeLoading()) {  
  49.             imageAware.setImageDrawable(null);  
  50.         }  
  51.         ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,  
  52.                 options, listener, progressListener, engine.getLockForUri(uri));//将信息保存到这个对象中
  53.         LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo,  
  54.                 defineHandler(options));// 生成下载任务
  55. if (options.isSyncLoading()) { //下载
  56.             displayTask.run();  
  57.         } else {  
  58.             engine.submit(displayTask);  
  59.         }  
  60.     }  
  61. }  

代码太多,不一一贴出来了,在下载图片的task 方法中,会 做一些 线程安全的同步,还有就是判断本地 内存 有没有以前下载好了,有的话直接拿过来用,没有 去下载 然后试着保存在磁盘缓存中

[java] view plain copy

print?

  1. private boolean downloadImage() throws IOException {  
  2.     InputStream is = getDownloader().getStream(uri, options.getExtraForDownloader());  
  3. if (is == null) {  
  4.         L.e(ERROR_NO_IMAGE_STREAM, memoryCacheKey);  
  5. return false;  
  6.     } else {  
  7. try {  
  8. return configuration.diskCache.save(uri, is, this);  
  9.         } finally {  
  10.             IoUtils.closeSilently(is);  
  11.         }  
  12.     }  
  13. }  

面试官01问: 大图片 加载 oom 问题

J哥回答: 对于大图片,直接加载给Imageview  容易出现 OOM 异常,那么我们就要对其进行压缩, 压缩原理,根据手机分辨率 去压缩

首先获取手机分辨率:

[java] view plain copy

print?

  1. WindowManager windowManager= (WindowManager)getSystemService(WINDOW_SERVICE);  
  2.       Display display= windowManager.getDefaultDisplay();  
  3.       height = display.getHeight();  
  4.       width = display.getWidth();  

然后 计算图片的宽度高度,根据比例压缩 在显示 图片

[java] view plain copy

print?

  1. public void  calImageView(){  
  2. //        Log.i("file","ImageWidth:"+ImageWidth);
  3. //        Log.i("file","ImageHeight:"+ImageHeight);
  4.         BitmapFactory.Options options=  new  BitmapFactory.Options();  
  5.         options.inJustDecodeBounds=true;  
  6. //        bitmap=null
  7.         String path="";// 对应图片的 地址
  8.         BitmapFactory.decodeFile(path, options);  
  9. int ImageWidth= options.outWidth;  
  10. int ImageHeight= options.outHeight;  
  11.         System.out.print("ImageWidth:" + ImageWidth);  
  12.         System.out.print("ImageHeight:"+ImageHeight);  
  13. int scaleX=ImageWidth/width;  
  14. int scaleY=ImageHeight/height;  
  15. int scale=1;  
  16. if(scaleX>scaleY & scaleY>=1){  
  17.             scale=scaleX;  
  18.         }  
  19. if(scaleY>scaleX & scaleX>=1){  
  20.             scale=scaleY;  
  21.         }  
  22. //解析图片
  23.         options.inJustDecodeBounds=false;  
  24.         options.inSampleSize=scale;  
  25.        Bitmap bitmap= BitmapFactory.decodeFile("/storage/emulated/a.jpg", options);  
  26.         iv.setImageBitmap(bitmap);  
  27. //        ByteArrayOutputStream baos = null ; 另一种压缩方式
  28. //        baos = new ByteArrayOutputStream();
  29. //        bitmap.compress(Bitmap.CompressFormat.JPEG, 30, baos);
  30.         }  

 接上一篇 往下写 http://blog.csdn.net/u011733020/article/details/45998861  ,   非常感谢在上一篇中给我指出问题的兄弟们。

面试公司:五道口 某公司

面试过程:

感觉公司还是挺有活力的的,进去填了申请表,人事就跟我聊了下 从上家离职原因(找工作 要准备怎么回答这个问题,最好能找一些客观因素,不要说 感觉以前公司不好。。。)

随后 就是 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。

代码很简单

[java] view plain copy

print?

  1. try {  
  2.             obj = new JSONObject(json);  
  3.             Iterator iterator = obj.keys();  
  4. while(iterator.hasNext()){  
  5.                 Object next = iterator.next();// 获取到 key
  6.                  obj.get(next.toString());// 获取到 value
  7.             }  
  8.         } catch (JSONException e) {  
  9. // TODO Auto-generated catch block
  10.             e.printStackTrace();  
  11.         }  

平时不在意 ,关键时刻掉链子!!!

面试官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.

Overrides:getViewTypeCount() inBaseAdapter

Returns:The number of types of Views that will be created by this adapter意思是 返回  getview 时 产生的 item 的 类型的个数,如果 我们的listview 中所有的item 只有一种类型 ,那么我们不需要复写这个方法,这个方法 当我们给listview  setAdapter 的时候 被调用。因为 可以在baseAdapter  中发现  ,默认值 就是 1.

[java] view plain copy

print?

  1. public int getViewTypeCount() {  
  2. return 1;  
  3.    }  

另一个方法  getItemViewType   

Get the type of View that will be created bygetView for the specified item.

Specified by:getItemViewType(...) inAdapter

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 ingetView. Note: Integers must be in the range 0 togetViewTypeCount - 1.IGNORE_ITEM_VIEW_TYPE can also be returned 这个方法 返回 将要被 getview 创建的 item的 类型 。返回值  范围 0   ~~~~  到 类型type-1。 就是 这两个关键的方法,要想我们实现多type 我们就要实现这两个方法。

效果就是这样子。

代码实现 跟单一 item 唯一的区别 就在上述两个方法 和 getview 方法中增加了判断当前类型。下面Adapter中部分代码

[java] view plain copy

print?

  1. @Override
  2. public View getView(int position, View convertView, ViewGroup parent) {  
  3. int type = list.get(position).type;  
  4. int itemViewType = getItemViewType(position);  
  5.     System.out.println("type===itemViewType"+(itemViewType==type));  
  6. if(getItemViewType(position)==0){  
  7.             convertView =inflater.inflate(  
  8.                     R.layout.item01_layout, parent, false);  
  9. return convertView;  
  10.     }else if(getItemViewType(position)==1){  
  11.         convertView =inflater.inflate(  
  12.                 R.layout.item02_layout, parent, false);  
  13. return convertView;  
  14.     }else{  
  15.         convertView =inflater.inflate(  
  16.                 R.layout.item03_layout, parent, false);  
  17. return convertView;  
  18.     }  
  19. }  
  20. @Override
  21. public int getItemViewType(int position) {  
  22.     System.out.println("getItemViewType-------------------------------"+list.get(position).type);  
  23. return list.get(position).type;  
  24. }  
  25. @Override
  26. public int getViewTypeCount() {  
  27. return maxType;  
  28. }  

 上面这里 并没有考虑过 convertview 的复用, 但是如果 有很多条的话,我们就不能这么简单的用了,要复用的话,我们要分别判断 type类型,和 convertview 去实现复用,  这里如果type 很多 复用的话,在getview 方法里面要写很多 判断,假如 type==0 inflate 一个layout01,type==2 inflate  一个layout02....假如有十个 那么 我们的getview方法里要分别判断 十次type 而且还要判断 convetview==null,所以 类型多了的话,这个方法写起来逻辑 可读性都不好,然而我有没想到什么好办法,网上搜了点资料,这个感觉还是不错的,用这种方式 虽然 要写很多类,但是感觉不用把所有的代码都写在一个getview中。如果 有什么好方法 可以一起分享出来。

listview 多type 复用 convertview 的解决方法

面试官01问:可以手动缩放的图片 怎么去实现。

J哥回答:由于 自己展示中的项目用到了 开源的  PhotoView, 所以 被问到自己实现。当时自己也没有看 源码,只是知道类似的,touchevent,

知道 两点触摸时间,那是关于图片 拖拽的, 实现的关键 就是 touch 时间的监听,对于 手指按下, 手机移动,手指离开的监听,记录初始的xy ,以及离开时的 xy,进行相应的缩放,在onlayout  ondraw.  关于 photoview 的分析,自己找了些资料,这里有一篇分析,感兴趣的可以看一下,个人感觉还不错。地址

面试官01问:ImageLoader 源码 分析

J哥回答: 开发中,多多少少都能接触到异步加载图片,大家知道 universalImageLoader (github 地址 https://github.com/nostra13/Android-Universal-Image-Loader)加载图片 可以有效地防止 因为图片导致的oom。由于是开源,封装的不错,所以 一般项目中 都直接拿过来用,关于imageloader 的使用方法 这里就不介绍了, 大体思路肯定 是 使用了缓存,在保证效率的前提下 合理节约资源, 一般第一次加载 都是从网络加载,然后判断是不是要保存在本地,顺便将图片在内存保存一下。 

原理 这张图 表达的比较清楚

使用方法 一般是  

[java] view plain copy

print?

  1. ImageLoader.getInstance().displayImage(picurl, imageview);//传入 图片url 和 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 toobj.
    • All weak references pointing to objects from whichobj is either strongly or softly reachable.
  • All references in ref are atomically cleared.
  • All objects formerly being referenced byref become eligible for finalization.
  • At some future point, all references inref 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 aSoftReference and aWeakReference is the point of time at which the decision is made to clear and enqueue the reference:

  • SoftReference should be cleared and enqueuedas late as possible, that is, in case the VM is in danger of running out of memory.
  • 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 的对象。

对于weakreference 的理解 还可以看下这篇文章 http://wiseideal.iteye.com/blog/1469295

在继续看Display 方法 

[java] view plain copy

print?

  1. public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,  
  2.         ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {  
  3.     checkConfiguration();  
  4. if (imageAware == null) {  
  5. throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS);  
  6.     }  
  7. if (listener == null) {  
  8.         listener = defaultListener;  
  9.     }  
  10. if (options == null) {  
  11.         options = configuration.defaultDisplayImageOptions;  
  12.     }  
  13. if (TextUtils.isEmpty(uri)) { // 判断传入的地址是否为空
  14.         engine.cancelDisplayTaskFor(imageAware);  
  15.         listener.onLoadingStarted(uri, imageAware.getWrappedView());  
  16. if (options.shouldShowImageForEmptyUri()) {//  是否设置了默认的图片
  17.             imageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources));  
  18.         } else {  
  19.             imageAware.setImageDrawable(null);  
  20.         }  
  21.         listener.onLoadingComplete(uri, imageAware.getWrappedView(), null);//加载完成的回调
  22. return;  
  23.     }  
  24.     ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize());  
  25.     String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize);  
  26.     engine.prepareDisplayTaskFor(imageAware, memoryCacheKey);  
  27.     listener.onLoadingStarted(uri, imageAware.getWrappedView());  
  28.     Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);  
  29. if (bmp != null && !bmp.isRecycled()) {  
  30.         L.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey);  
  31. if (options.shouldPostProcess()) {  
  32.             ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,  
  33.                     options, listener, progressListener, engine.getLockForUri(uri));  
  34.             ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo,  
  35.                     defineHandler(options));  
  36. if (options.isSyncLoading()) {  
  37.                 displayTask.run();  
  38.             } else {  
  39.                 engine.submit(displayTask);  
  40.             }  
  41.         } else {  
  42.             options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);  
  43.             listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);  
  44.         }  
  45.     } else {  
  46. if (options.shouldShowImageOnLoading()) {  
  47.             imageAware.setImageDrawable(options.getImageOnLoading(configuration.resources));  
  48.         } else if (options.isResetViewBeforeLoading()) {  
  49.             imageAware.setImageDrawable(null);  
  50.         }  
  51.         ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,  
  52.                 options, listener, progressListener, engine.getLockForUri(uri));//将信息保存到这个对象中
  53.         LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo,  
  54.                 defineHandler(options));// 生成下载任务
  55. if (options.isSyncLoading()) { //下载
  56.             displayTask.run();  
  57.         } else {  
  58.             engine.submit(displayTask);  
  59.         }  
  60.     }  
  61. }  

代码太多,不一一贴出来了,在下载图片的task 方法中,会 做一些 线程安全的同步,还有就是判断本地 内存 有没有以前下载好了,有的话直接拿过来用,没有 去下载 然后试着保存在磁盘缓存中

[java] view plain copy

print?

  1. private boolean downloadImage() throws IOException {  
  2.     InputStream is = getDownloader().getStream(uri, options.getExtraForDownloader());  
  3. if (is == null) {  
  4.         L.e(ERROR_NO_IMAGE_STREAM, memoryCacheKey);  
  5. return false;  
  6.     } else {  
  7. try {  
  8. return configuration.diskCache.save(uri, is, this);  
  9.         } finally {  
  10.             IoUtils.closeSilently(is);  
  11.         }  
  12.     }  
  13. }  

面试官01问: 大图片 加载 oom 问题

J哥回答: 对于大图片,直接加载给Imageview  容易出现 OOM 异常,那么我们就要对其进行压缩, 压缩原理,根据手机分辨率 去压缩

首先获取手机分辨率:

[java] view plain copy

print?

  1. WindowManager windowManager= (WindowManager)getSystemService(WINDOW_SERVICE);  
  2.       Display display= windowManager.getDefaultDisplay();  
  3.       height = display.getHeight();  
  4.       width = display.getWidth();  

然后 计算图片的宽度高度,根据比例压缩 在显示 图片

[java] view plain copy

print?

  1. public void  calImageView(){  
  2. //        Log.i("file","ImageWidth:"+ImageWidth);
  3. //        Log.i("file","ImageHeight:"+ImageHeight);
  4.         BitmapFactory.Options options=  new  BitmapFactory.Options();  
  5.         options.inJustDecodeBounds=true;  
  6. //        bitmap=null
  7.         String path="";// 对应图片的 地址
  8.         BitmapFactory.decodeFile(path, options);  
  9. int ImageWidth= options.outWidth;  
  10. int ImageHeight= options.outHeight;  
  11.         System.out.print("ImageWidth:" + ImageWidth);  
  12.         System.out.print("ImageHeight:"+ImageHeight);  
  13. int scaleX=ImageWidth/width;  
  14. int scaleY=ImageHeight/height;  
  15. int scale=1;  
  16. if(scaleX>scaleY & scaleY>=1){  
  17.             scale=scaleX;  
  18.         }  
  19. if(scaleY>scaleX & scaleX>=1){  
  20.             scale=scaleY;  
  21.         }  
  22. //解析图片
  23.         options.inJustDecodeBounds=false;  
  24.         options.inSampleSize=scale;  
  25.        Bitmap bitmap= BitmapFactory.decodeFile("/storage/emulated/a.jpg", options);  
  26.         iv.setImageBitmap(bitmap);  
  27. //        ByteArrayOutputStream baos = null ; 另一种压缩方式
  28. //        baos = new ByteArrayOutputStream();
  29. //        bitmap.compress(Bitmap.CompressFormat.JPEG, 30, baos);
  30.         }  

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android机动车

轻松又酷炫地实现弹幕效果——手把手教学

CSDN: http://blog.csdn.net/jiashuai94

15720
来自专栏天天P图攻城狮

深入Android Runtime: inline优化与字符串

作者简介:dc, 天天P图AND工程师 ---- 奇怪的现象? 先看下面一段apk的代码: public class MainActivity extends...

23930
来自专栏Phoenix的Android之旅

设计模式之工厂模式

工厂模式作为设计模式的一种在开发中被普遍使用, 其实应该可以说是最经常使用的一种的了。 它的设计思想也是面向接口,如果细分下来,可以分成两种工厂模式 · 工厂方...

7910
来自专栏用户画像

3.2 组帧

数据链路层之所以要把比特组合成帧为单位传输,是为了在出错时只重发出错的帧,而不必重发全部数据,从而提高了效率。为了使接收方能正确地接受并检查所传输的帧,发送方必...

7710
来自专栏数据结构与算法

HDU 1848 Fibonacci again and again(SG函数)

Problem Description 任何一个大学生对菲波那契数列(Fibonacci numbers)应该都不会陌生,它是这样定义的: F(1)=1; ...

35460
来自专栏Java呓语

生成器模式(分离部件构造)

生成器模式的主要功能是构建复杂的产品,而且是细化的,分步骤的构建产品,也就是生成器模式重在解决一步一步构造复杂对象的问题。如果光是这么认识生成器模式的功能是不够...

9420
来自专栏木木玲

设计模式 ——— 适配器模式

17770
来自专栏偏前端工程师的驿站

Design Pattern: Not Just Mixin Pattern

Brief                                 从Mix-In模式到Mixin模式,中文常用翻译为“混入/织入模式”。单纯从名字上看...

20760
来自专栏菩提树下的杨过

rpc框架之gRPC 学习 - hello world

grpc是google在github于2015年开源的一款RPC框架,虽然protobuf很早google就开源了,但是google一直没推出正式的开源框架,导...

81570
来自专栏KK的小酒馆

Android设计模式二

在组件构建过程中,某些接口之间直接的依赖常常会带来很多问题,甚至根本无法实现。采用添加一层间接(稳定)接口,来隔离本来互相紧密关联的接口是一种常见的解决方案。

11320

扫码关注云+社区

领取腾讯云代金券