北京Android各招聘公司面試實戰總結2

面試公司:五道口  某公司
面試時間: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。
代碼很簡單
[java] view plaincopy
  1. try {  
  2.             obj = new JSONObject(json);  
  3.   
  4.             Iterator iterator = obj.keys();  
  5.             while(iterator.hasNext()){  
  6.                 Object next = iterator.next();// 獲取到 key  
  7.                  obj.get(next.toString());// 獲取到 value  
  8.             }  
  9.         } catch (JSONException e) {  
  10.             // TODO Auto-generated catch block  
  11.             e.printStackTrace();  
  12.         }  
平時不在意 ,關鍵時刻掉鏈子!!!

面試官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.
[java] view plaincopy
  1. public int getViewTypeCount() {  
  2.        return 1;  
  3.    }  

另一個方法  getItemViewType   

Get the type of View that will be created by getView 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 plaincopy
  1. @Override  
  2. public View getView(int position, View convertView, ViewGroup parent) {  
  3.       
  4.     int type = list.get(position).type;  
  5.     int itemViewType = getItemViewType(position);  
  6.       
  7.     System.out.println("type===itemViewType"+(itemViewType==type));  
  8.     if(getItemViewType(position)==0){  
  9.             convertView =inflater.inflate(  
  10.                     R.layout.item01_layout, parent, false);  
  11.         return convertView;  
  12.           
  13.     }else if(getItemViewType(position)==1){  
  14.         convertView =inflater.inflate(  
  15.                 R.layout.item02_layout, parent, false);  
  16.     return convertView;  
  17.     }else{  
  18.         convertView =inflater.inflate(  
  19.                 R.layout.item03_layout, parent, false);  
  20.     return convertView;  
  21.     }  
  22.   
  23. }  
  24. @Override  
  25. public int getItemViewType(int position) {  
  26.     System.out.println("getItemViewType-------------------------------"+list.get(position).type);  
  27.     return list.get(position).type;  
  28. }  
  29. @Override  
  30. public int getViewTypeCount() {  
  31.     return maxType;  
  32. }  

 上面這裏 並沒有考慮過 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  源碼 分析



J哥回答: 開發中,多多少少都能接觸到異步加載圖片,大家知道 universalImageLoader (github 地址 https://github.com/nostra13/Android-Universal-Image-Loader)加載圖片 可以有效地防止 因爲圖片導致的oom。由於是開源,封裝的不錯,所以 一般項目中 都直接拿過來用,關於imageloader 的使用方法 這裏就不介紹了, 大體思路肯定 是 使用了緩存,在保證效率的前提下 合理節約資源, 一般第一次加載 都是從網絡加載,然後判斷是不是要保存在本地,順便將圖片在內存保存一下。 
原理 這張圖 表達的比較清楚

使用方法 一般是  
[java] view plaincopy
  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 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 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 enqueued as 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 plaincopy
  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.   
  14.     if (TextUtils.isEmpty(uri)) { //<span style="color:#ff0000;"> 判斷傳入的地址是否爲空</span>  
  15.         engine.cancelDisplayTaskFor(imageAware);  
  16.         listener.onLoadingStarted(uri, imageAware.getWrappedView());  
  17.         if (options.shouldShowImageForEmptyUri()) {//  <span style="color:#ff6666;">是否設置了默認的圖片</span>  
  18.             imageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources));  
  19.         } else {  
  20.             imageAware.setImageDrawable(null);  
  21.         }  
  22.         listener.onLoadingComplete(uri, imageAware.getWrappedView(), null);//<span style="color:#ff0000;">加載完成的回調</span>  
  23.         return;  
  24.     }  
  25.   
  26.     ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize());  
  27.     String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize);  
  28.     engine.prepareDisplayTaskFor(imageAware, memoryCacheKey);  
  29.   
  30.     listener.onLoadingStarted(uri, imageAware.getWrappedView());  
  31.   
  32.     Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);  
  33.     if (bmp != null && !bmp.isRecycled()) {  
  34.         L.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey);  
  35.   
  36.         if (options.shouldPostProcess()) {  
  37.             ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,  
  38.                     options, listener, progressListener, engine.getLockForUri(uri));  
  39.             ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo,  
  40.                     defineHandler(options));  
  41.             if (options.isSyncLoading()) {  
  42.                 displayTask.run();  
  43.             } else {  
  44.                 engine.submit(displayTask);  
  45.             }  
  46.         } else {  
  47.             options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);  
  48.             listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);  
  49.         }  
  50.     } else {  
  51.         if (options.shouldShowImageOnLoading()) {  
  52.             imageAware.setImageDrawable(options.getImageOnLoading(configuration.resources));  
  53.         } else if (options.isResetViewBeforeLoading()) {  
  54.             imageAware.setImageDrawable(null);  
  55.         }  
  56.   
  57.         ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,  
  58.                 options, listener, progressListener, engine.getLockForUri(uri));//將信息保存到這個對象中  
  59.         LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo,  
  60.                 defineHandler(options));// 生成下載任務  
  61.         if (options.isSyncLoading()) { //下載  
  62.             displayTask.run();  
  63.         } else {  
  64.             engine.submit(displayTask);  
  65.         }  
  66.     }  
  67. }  

代碼太多,不一一貼出來了,在下載圖片的task 方法中,會 做一些 線程安全的同步,還有就是判斷本地 內存 有沒有以前下載好了,有的話直接拿過來用,沒有 去下載 然後試着保存在磁盤緩存中
[java] view plaincopy
  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 plaincopy
  1. WindowManager windowManager= (WindowManager)getSystemService(WINDOW_SERVICE);  
  2.       Display display= windowManager.getDefaultDisplay();  
  3.       height = display.getHeight();  
  4.       width = display.getWidth();  
然後 計算圖片的寬度高度,根據比例壓縮 在顯示 圖片
轉自:http://blog.csdn.net/u011733020/article/details/46058273
[java] view plaincopy
  1. public void  calImageView(){  
  2.   
  3. //        Log.i("file","ImageWidth:"+ImageWidth);  
  4. //        Log.i("file","ImageHeight:"+ImageHeight);  
  5.   
  6.         BitmapFactory.Options options=  new  BitmapFactory.Options();  
  7.         options.inJustDecodeBounds=true;  
  8. //        bitmap=null  
  9.   
  10.         String path="";// 對應圖片的 地址  
  11.         BitmapFactory.decodeFile(path, options);  
  12.         int ImageWidth= options.outWidth;  
  13.         int ImageHeight= options.outHeight;  
  14.         System.out.print("ImageWidth:" + ImageWidth);  
  15.         System.out.print("ImageHeight:"+ImageHeight);  
  16.         int scaleX=ImageWidth/width;  
  17.         int scaleY=ImageHeight/height;  
  18.         int scale=1;  
  19.   
  20.         if(scaleX>scaleY & scaleY>=1){  
  21.             scale=scaleX;  
  22.         }  
  23.   
  24.         if(scaleY>scaleX & scaleX>=1){  
  25.             scale=scaleY;  
  26.         }  
  27.         //解析圖片  
  28.         options.inJustDecodeBounds=false;  
  29.         options.inSampleSize=scale;  
  30.   
  31.        Bitmap bitmap= BitmapFactory.decodeFile("/storage/emulated/a.jpg", options);  
  32.   
  33.         iv.setImageBitmap(bitmap);  
  34.   
  35. //        ByteArrayOutputStream baos = null ; 另一種壓縮方式  
  36. //        baos = new ByteArrayOutputStream();  
  37. //        bitmap.compress(Bitmap.CompressFormat.JPEG, 30, baos);  
  38.         } 
發佈了4 篇原創文章 · 獲贊 13 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章