1. 程式人生 > >Android 面試題總結之Android 基礎(五)

Android 面試題總結之Android 基礎(五)

Android 面試題總結之Android 基礎(ListView)(五)

前幾篇面試總結中,主要講了Android 的四大元件的相關知識點,希望在大家日常工作中有所幫助,那麼在本節中主要是Android 必不可少的ListView 的相關知識點。Listview 類似的控制元件 ,不管是在.Net 中 ,還是在Java 中 都是使用非常廣泛。正因為他的重要性,內容比較多,所以單獨章節的介紹。前兩篇文章傳送門:
Android 面試題總結之Android 基礎(一)
Android 面試題總結之Android 基礎(二)

Listview 基礎問題

  1. 當 ListView 資料集改變後,如何更新 ListView?

    使用該 ListView 的 adapter 的 notifyDataSetChanged()方法。該方法會 使 ListView 重新繪製。

  2. ListView 如何實現分頁載入

    1. 設 置 ListView 的 滾 動 監 聽 器 : setOnScrollListener(new OnScrollListener{….})
      在監聽器中有兩個方法: 滾動狀態發生變化的方法 (onScrollStateChanged)和 listView 被滾動時呼叫的方法(onScroll)
    2. 在滾動狀態發生改變的方法中,有三種狀態:
      手指按下移動的狀態: SCROLL_STATE_TOUCH_SCROLL: // 觸控滑動
      慣性滾動(滑翔(flgin)狀態): SCROLL_STATE_FLING: // 滑翔 靜止狀態:
      SCROLL_STATE_IDLE: // 靜止

    對不同的狀態進行處理:
    分批載入資料,只關心靜止狀態:關心最後一個可見的條目,如果最後一個 可見條目就是資料介面卡(集合)裡的最後一個,此時可載入更多的資料。在每 次載入的時候,計算出滾動的數量,當滾動的數量大於等於總數量的時候,可以 提示使用者無更多資料了。

  3. ListView 如何顯示多種型別的Item

    ListView 顯示的每個條目都是通過 baseAdapter 的 getView(int position, View convertView, ViewGroup parent)來展示的,理 論上我們完全可以讓每個條目都是不同型別的 view。
    比如:從伺服器拿回一個標識為 id=1,那麼當 id=1 的時候,我們就載入類 型一的條目,當 id=2 的時候,載入型別二的條目。常見佈局在資訊類客戶端中 可以經常看到。
    除此之外 adapter 還提供了 getViewTypeCount()

    getItemViewType(int position)兩個方法。在 getView 方法中我們可以根據不 同的 viewtype 載入不同的佈局檔案。

  4. ListView 如何定位到指定位置?
    可以通過 ListView 提供的 lv.setSelection(listView.getPosition());方法。

  5. 在ListView中設定Selector為null會報空指標?
    mListView.setSelector(null);//空指標
    試試下面這個:
    mListView.setSelector(new ColorDrawable(Color.TRANSPARENT));

  6. ListView中主要有2種監聽器:
    OnItemClickListener: 處理檢視中單個條目的點選事件。 (OnItemSelectedListener,引數與其一致,只是監聽使用者手指行為不同)
    OnScrollListener:監聽滾動變化,可以用於檢視滾動中載入資料。

  7. ListView中圖片錯位問題
    每次getView能給物件一個標識,在非同步載入完成時比較標識與當前行item的標識是否一致,一致則顯示,否則不做處理即可

    
    // 給 ImageView 設定一個 tag
    holder.img.setTag(imgUrl);
    // 預設一個圖片
    holder.img.setImageResource(R.drawable.ic_launcher);
    
    // 通過 tag 來防止圖片錯位
    if (imageView.getTag() != null &&imageView.getTag().equals(imageUrl)) {
    imageView.setImageBitmap(result);
    }
    
  8. ListView中多執行緒更新問題
    使用Handler負責統一重新整理,
    ListView帶有進度條的每個Item,多個子執行緒重新整理各自的進度,如果子執行緒很多那麼重新整理就會變得很頻繁,我們可以由一個Handler負責統一重新整理,這樣我們就要以增加一些額外條件限制重新整理的次數和條件

這裡寫圖片描述

Listview 優化問題

1.ListView 如何提高其效率?
當 convertView 為空時,用 setTag()方法為每個 View 繫結一個存放控制元件的 ViewHolder 物件。當 convertView 不為空,重複利用已經建立的 view 的時候, 使用 getTag()方法獲取繫結的 ViewHolder 物件,這樣就避免了 findViewById
對控制元件的層層查詢,而是快速定位到控制元件。

  1. 複用 ConvertView,使用歷史的 view,提升效率 200%
  2. 自定義靜態類 ViewHolder,減少 findViewById 的次數。提 升效率 50%
  3. 非同步載入資料,分頁載入資料。
  4. 使用 WeakRefrence 引用 ImageView 物件

    1. ListView 中載入優化圖片

    圖片的優化策略比較多。

    1. 處理圖片的方式:
      如果 ListView 中自定義的 Item 中有涉及到大量圖片的,一定要對圖片進行
      細心的處理,因為圖片佔的記憶體是 ListView 項中最頭疼的,處理圖片的方法大 致有以下幾種:

      1. 不要直接拿路徑就去迴圈 BitmapFactory.decodeFile;使用 Options 保 存圖片大小、不要載入圖片到記憶體去。
      2. 對圖片一定要經過邊界壓縮尤其是比較大的圖片,如果你的圖片是後臺 伺服器處理好的那就不需要了
      3. 在 ListView 中取圖片時也不要直接拿個路徑去取圖片,而是以 WeakReference(使用 WeakReference 代替強引用。比如可以使用 WeakReference mContextRef)、SoftReference、WeakHashMap 等的來存 儲圖片資訊。
      4. 在 getView 中做圖片轉換時,產生的中間變數一定及時釋放
    2. 非同步載入圖片基本思想:
      1). 先從記憶體快取中獲取圖片顯示(記憶體緩衝)
      2). 獲取不到的話從 SD 卡里獲取(SD 卡緩衝)
      3). 都獲取不到的話從網路下載圖片並儲存到 SD 卡同時加入記憶體並顯示(視情況看是否要顯示)

    優化基本原理:

    優化一: 先從記憶體中載入,沒有則開啟執行緒從 SD 卡或網路中獲取,這裡注 意從 SD 卡獲取圖片是放在子執行緒裡執行的,否則快速滑屏的話會不夠流暢。

    優化二: 於此同時,在 adapter 裡有個 busy 變數,表示 listview 是否處於 滑動狀態,如果是滑動狀態則僅從記憶體中獲取圖片,沒有的話無需再開啟執行緒去 外存或網路獲取圖片。

    優化三:ImageLoader 裡的執行緒使用了執行緒池,從而避免了過多執行緒頻繁 建立和銷燬,如果每次總是 new 一個執行緒去執行這是非常不可取的,好一點的 用的 AsyncTask 類,其實內部也是用到了執行緒池。在從網路獲取圖片時,先是 將其儲存到 sd 卡,然後再載入到記憶體,這麼做的好處是在載入到記憶體時可以做 個壓縮處理,以減少圖片所佔記憶體。

    1. ListView實現Item區域性重新整理?
private void updateView(int itemIndex) {
          //得到第一個可顯示控制元件的位置,
          int visiblePosition = mListView.getFirstVisiblePosition();
          //只有當要更新的view在可見的位置時才更新,不可見時,跳過不更新
          if (itemIndex - visiblePosition >= 0) {
              //得到要更新的item的view
            View view = mListView.getChildAt(itemIndex - visiblePosition);
              //呼叫adapter更新介面
             mAdapter.updateView(view, itemIndex);
        }
     }

Listview 的替代方案

RecyclerView

RecyclerView是一個比ListView更靈活的一個控制元件,以後可以直接拋棄ListView了,也可以替代Gridview。
RecyclerView改善了ListView的程式設計介面,他其實是一個ViewGroup ,能配合任何基於adapter的view實現多種佈局

更好的實現區域性重新整理 ,呼叫notifyItemChanged(position)即可

Listview 原理

首先要理解Listview 三個重要的成員,用MVC思路來理解:
* ListVeiw: 用來展示列表的View (V)
* Adapter : 用來把資料對映到ListView上,(C)
* 資料:item顯示的資料(M)

ListView 針對每個item,要求 adapter “返回一個檢視” (getView),也就是說ListView在開始繪製的時候,系統首先呼叫getCount()函式,根據他的返回值得到ListView的長度,然後根據這個長度,呼叫getView()一行一行的繪製ListView的每一項。如果你的getCount()返回值是0的話,列表一行都不會顯示,如果返回1,就只顯示一行.如果我們有幾千幾萬甚至更多的item要顯示怎麼辦?為每個Item建立一個新的View?不可能!!!實際上Android早已經快取了這些檢視.

可以通過下圖來理解

這裡寫圖片描述

當要顯示一個View就呼叫一次這個方法。這個方法是ListView效能好壞的關鍵。方法中有個convertView,這個是Android在 為我們而做的快取機制。
ListView中每個item都是通過getView返回並顯示的,假如item有很多個,那麼重複建立這麼多物件來顯示顯然是不合理。因此,Android提供了Recycler,將沒有正在顯示的item放進RecycleBin,然後在顯示新檢視時從RecycleBin中複用這個 View。

Recycler可以理解為一個回收池,存放著不同ViewType的convertView。
Recycler的工作原理大致如下

假設螢幕最多能看到11個item,那麼當第1個item滾出螢幕,這個item的View進入RecycleBin中,第12個要出現前,通過 getView從回收站(RecycleBin)中重用這個View,然後設定資料,而不必重新建立一個View。

有哪些開源的ListView控制元件?

這裡主要列出幾個比較常見的:

  • android-pulltorefresh
    一個強大的拉動重新整理開源專案,支援各種控制元件下拉重新整理,ListView、ViewPager、WebView、ExpandableListView、GridView、ScrollView、Horizontal ScrollView、Fragment 上下左右拉動重新整理,比下面 johannilsson 那個只支援 ListView 的強大的多。並且它實現的下拉重新整理 ListView 在 item 不足一屏情況下也不會顯示重新整理提示,體驗更好。
    Github:https://github.com/chrisbanes/Android-PullToRefresh

  • Android-PullToRefreshRecyclerView
    支援下拉重新整理的RecyclerView,同時支援滑動到底部自動載入資料、給RecyclerView新增Header。並且不更改原有RecyclerView的邏輯。
    Github:https://github.com/HomHomLin/Android-PullToRefreshRecyclerView

  • pinned-section-listview
    GroupName 滑動到頂端時會固定不動直到另外一個 GroupName 到達頂端的 ExpandListView
    Github:https://github.com/beworker/pinned-section-listview

等等,比較多,瞭解幾個就行了,看看實現。。。。

到目前為止Listview 相關知識點,就先總結到這。基本可以滿足面試要求了。

更多Android 面試題總結,請點選下方圖片哦。

這裡寫圖片描述