Android 面試題總結之Android 基礎(五)
Android 面試題總結之Android 基礎(ListView)(五)
前幾篇面試總結中,主要講了Android 的四大元件的相關知識點,希望在大家日常工作中有所幫助,那麼在本節中主要是Android 必不可少的ListView 的相關知識點。Listview 類似的控制元件 ,不管是在.Net 中 ,還是在Java 中 都是使用非常廣泛。正因為他的重要性,內容比較多,所以單獨章節的介紹。前兩篇文章傳送門:
Android 面試題總結之Android 基礎(一)
Android 面試題總結之Android 基礎(二)
Listview 基礎問題
當 ListView 資料集改變後,如何更新 ListView?
使用該 ListView 的 adapter 的 notifyDataSetChanged()方法。該方法會 使 ListView 重新繪製。
ListView 如何實現分頁載入
- 設 置 ListView 的 滾 動 監 聽 器 : setOnScrollListener(new OnScrollListener{….})
在監聽器中有兩個方法: 滾動狀態發生變化的方法 (onScrollStateChanged)和 listView 被滾動時呼叫的方法(onScroll) - 在滾動狀態發生改變的方法中,有三種狀態:
手指按下移動的狀態: SCROLL_STATE_TOUCH_SCROLL: // 觸控滑動
慣性滾動(滑翔(flgin)狀態): SCROLL_STATE_FLING: // 滑翔 靜止狀態:
SCROLL_STATE_IDLE: // 靜止
對不同的狀態進行處理:
分批載入資料,只關心靜止狀態:關心最後一個可見的條目,如果最後一個 可見條目就是資料介面卡(集合)裡的最後一個,此時可載入更多的資料。在每 次載入的時候,計算出滾動的數量,當滾動的數量大於等於總數量的時候,可以 提示使用者無更多資料了。- 設 置 ListView 的 滾 動 監 聽 器 : setOnScrollListener(new OnScrollListener{….})
ListView 如何顯示多種型別的Item
ListView 顯示的每個條目都是通過 baseAdapter 的 getView(int position, View convertView, ViewGroup parent)來展示的,理 論上我們完全可以讓每個條目都是不同型別的 view。
比如:從伺服器拿回一個標識為 id=1,那麼當 id=1 的時候,我們就載入類 型一的條目,當 id=2 的時候,載入型別二的條目。常見佈局在資訊類客戶端中 可以經常看到。
除此之外 adapter 還提供了 getViewTypeCount()ListView 如何定位到指定位置?
可以通過 ListView 提供的 lv.setSelection(listView.getPosition());方法。在ListView中設定Selector為null會報空指標?
mListView.setSelector(null);//空指標
試試下面這個:
mListView.setSelector(new ColorDrawable(Color.TRANSPARENT));ListView中主要有2種監聽器:
OnItemClickListener: 處理檢視中單個條目的點選事件。 (OnItemSelectedListener,引數與其一致,只是監聽使用者手指行為不同)
OnScrollListener:監聽滾動變化,可以用於檢視滾動中載入資料。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); }
ListView中多執行緒更新問題
使用Handler負責統一重新整理,
ListView帶有進度條的每個Item,多個子執行緒重新整理各自的進度,如果子執行緒很多那麼重新整理就會變得很頻繁,我們可以由一個Handler負責統一重新整理,這樣我們就要以增加一些額外條件限制重新整理的次數和條件
Listview 優化問題
1.ListView 如何提高其效率?
當 convertView 為空時,用 setTag()方法為每個 View 繫結一個存放控制元件的 ViewHolder 物件。當 convertView 不為空,重複利用已經建立的 view 的時候, 使用 getTag()方法獲取繫結的 ViewHolder 物件,這樣就避免了 findViewById
對控制元件的層層查詢,而是快速定位到控制元件。
- 複用 ConvertView,使用歷史的 view,提升效率 200%
- 自定義靜態類 ViewHolder,減少 findViewById 的次數。提 升效率 50%
- 非同步載入資料,分頁載入資料。
使用 WeakRefrence 引用 ImageView 物件
- ListView 中載入優化圖片
圖片的優化策略比較多。
處理圖片的方式:
如果 ListView 中自定義的 Item 中有涉及到大量圖片的,一定要對圖片進行
細心的處理,因為圖片佔的記憶體是 ListView 項中最頭疼的,處理圖片的方法大 致有以下幾種:- 不要直接拿路徑就去迴圈 BitmapFactory.decodeFile;使用 Options 保 存圖片大小、不要載入圖片到記憶體去。
- 對圖片一定要經過邊界壓縮尤其是比較大的圖片,如果你的圖片是後臺 伺服器處理好的那就不需要了
- 在 ListView 中取圖片時也不要直接拿個路徑去取圖片,而是以 WeakReference(使用 WeakReference 代替強引用。比如可以使用 WeakReference mContextRef)、SoftReference、WeakHashMap 等的來存 儲圖片資訊。
- 在 getView 中做圖片轉換時,產生的中間變數一定及時釋放
非同步載入圖片基本思想:
1). 先從記憶體快取中獲取圖片顯示(記憶體緩衝)
2). 獲取不到的話從 SD 卡里獲取(SD 卡緩衝)
3). 都獲取不到的話從網路下載圖片並儲存到 SD 卡同時加入記憶體並顯示(視情況看是否要顯示)
優化基本原理:
優化一: 先從記憶體中載入,沒有則開啟執行緒從 SD 卡或網路中獲取,這裡注 意從 SD 卡獲取圖片是放在子執行緒裡執行的,否則快速滑屏的話會不夠流暢。
優化二: 於此同時,在 adapter 裡有個 busy 變數,表示 listview 是否處於 滑動狀態,如果是滑動狀態則僅從記憶體中獲取圖片,沒有的話無需再開啟執行緒去 外存或網路獲取圖片。
優化三:ImageLoader 裡的執行緒使用了執行緒池,從而避免了過多執行緒頻繁 建立和銷燬,如果每次總是 new 一個執行緒去執行這是非常不可取的,好一點的 用的 AsyncTask 類,其實內部也是用到了執行緒池。在從網路獲取圖片時,先是 將其儲存到 sd 卡,然後再載入到記憶體,這麼做的好處是在載入到記憶體時可以做 個壓縮處理,以減少圖片所佔記憶體。
- 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-PullToRefreshAndroid-PullToRefreshRecyclerView
支援下拉重新整理的RecyclerView,同時支援滑動到底部自動載入資料、給RecyclerView新增Header。並且不更改原有RecyclerView的邏輯。
Github:https://github.com/HomHomLin/Android-PullToRefreshRecyclerViewpinned-section-listview
GroupName 滑動到頂端時會固定不動直到另外一個 GroupName 到達頂端的 ExpandListView
Github:https://github.com/beworker/pinned-section-listview
等等,比較多,瞭解幾個就行了,看看實現。。。。
到目前為止Listview 相關知識點,就先總結到這。基本可以滿足面試要求了。
更多Android 面試題總結,請點選下方圖片哦。