https://www.jianshu.com/p/519bb23987caandroid
看完此文章 你就會學到什麼...git
- RecyclerView添加頭部,尾部,或list列表中某位置添加view
- RecyclerView+SwipeRefreshLayout 實現上下拉刷新效果
- 分頁加載數據
- 列表優化方案
- 利用Glide加載圖片,滑動的時候按back鍵,App會crash蹦掉處理。
添加依賴github
//recyclerview compile 'com.android.support:recyclerview-v7:25.1.1' //glide compile 'com.github.bumptech.glide:glide:3.7.0' //butterknife 注意須要在三個第三添加代碼 //1 module gradle裏面底部添加 compile 'com.jakewharton:butterknife:8.5.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' //2 module gradle 裏面頂部添加 apply plugin: 'com.jakewharton.butterknife' //3 在project gradle裏面添加 dependencies { classpath 'com.android.tools.build:gradle:2.2.3' classpath 'com.jakewharton:butterknife-gradle-plugin:8.5.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files }
RecyclerView中有如下三個函數:編程
getItemCount --獲得列表中Item的總個數緩存
getItemViewType(int position)--決定佈局使用哪種類型,返回一個int型標誌position,傳遞給onCreateViewHolder的第二個參數。
通俗說:一個列表有不少個Item,每一個Item均可以是本身的一個自定義的佈局且每一個都會有一個惟一的位置,能夠經過Item中的位置position標誌,規定這個position將會返回的Item的佈局類型。例如:網絡
@Override public int getItemViewType(int position) { if (position == 0) { return TYPE_HEAD; } else if (position + 1 == getItemCount()) { return TYPE_FOOTER; } else { return TYPE_ITEM; } }
3.onCreateViewHolder(ViewGroup parent, int viewType) 依據getItemViewType返回的每一個position位置所返回的佈局類型,去渲染具體的ViewHolder 。例如:app
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == TYPE_HEAD) { View view = LayoutInflater.from(context).inflate(R.layout.recycler_view_discover_head, parent, false); return new HeadViewHolder(view); } else if (viewType == TYPE_ITEM) { View view = LayoutInflater.from(context).inflate(R.layout.recycler_view_discover_base, parent, false); return new ItemViewHolder(view); } else if (viewType == TYPE_FOOTER) { View view = LayoutInflater.from(context).inflate(R.layout.recycler_view_discover_foot, parent, false); return new FootViewHolder(view); } return null; }
xml以下佈局框架
<android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeRefreshLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/discover_recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="vertical" /> </android.support.v4.widget.SwipeRefreshLayout>
用法ide
//進入界面時候顯示動畫 swipeRefreshLayout.post(new Runnable() { @Override public void run() { swipeRefreshLayout.setRefreshing(false); } }); //每次下拉刷新時候加載刷新數據 swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { if (!isLoading) { isLoading = true; data.clear(); getData(); } } });
利用了SwipeRefreshLayout實現了下拉數據刷新功能,而上拉加載數據是利用RecyclerView的函數
public abstract static class OnScrollListener { //newState 參數有: // SCROLL_STATE_TOUCH_SCROLL(1) 正在滾動 // SCROLL_STATE_FLING(2) 手指作了拋的動做(手指離開屏幕前,用力滑了一下) // SCROLL_STATE_IDLE(0) 中止滾動 public void onScrollStateChanged(RecyclerView recyclerView, int newState){} //滾動時一直回調,直到中止滾動時才中止回調。單擊時回調一次 public void onScrolled(RecyclerView recyclerView, int dx, int dy){} }
分頁加載:
實際就是每次上拉,而後將數據加進list集合裏面,而獲取特定數據的控制,就是從頁碼來,每次上拉都將page頁碼加一放到請求參數裏面,而每次下拉,將list集合的數據清除,將page還原成原來的1,請求到的數據放進list裏面。
列表優化方案:
1.佈局方面,儘可能少點組件嵌套,儘可能多用LinearLayout,少用RelativeLayout之類的,由於RelativeLayout渲染時候須要須要資源較多。
2.圖片優化,建議使用現有的圖片框架,例如 Glide,Picasso,Fresco,ImageLoader 等的開源框架,由於裏面很好的封裝了圖片緩存機制,以及沒用時候,或者用頻率少的時候,那圖片緩存會優先被回收。
3.圖片加載. 當列表滑動時候,將圖片用佔位圖片顯示,或則圖片徹底不顯示來處理,等滑動中止後,再加載。本demo用Glide,結合RecyclerView.OnScrollListener 來處理圖片加載的。具體看demo源碼。
4.每次分頁加載數據,數據添加進List的時間(也能夠說是網絡請求數據的時間最好在何時),通過本人研究了bilibili安卓App和其它App列表滑動流暢度的對比,bilibili是滑動最不卡最流暢的,爲何這樣呢?其實是由於分頁時網絡請求數據的開始時間決定的。在RecyclerView.OnScrollListener 的onScrolled滑動事件中處理。
下面代碼中有個 5 ,它就是代碼的滑動流暢的關鍵,也能夠不必定是5,按實際須要寫。
@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition(); if (lastVisibleItemPosition + 5 >= adapter.getItemCount()) { boolean isRefreshing = swipeRefreshLayout.isRefreshing(); if (isRefreshing) { adapter.notifyItemRemoved(adapter.getItemCount()); return; } if (!isLoading) { isLoading = true; getData(); } } }
這樣的優化優勢:滑動特別流暢 缺點:可能由於屏幕的大小不一而加載開始時間不一樣,還有的就是你體驗不到上拉加載數據的動畫感(上拉加載更多.. 這樣的字你就難看到了,不過網絡慢的時候,仍是能夠看到的)~。
剛所說的列表滑動優化處理,而我本身就隨便用了個Glide去加載圖片,能夠看到,在一瞬間滑動,而後我按back鍵退出的時候,App會crash蹦掉,why?why?why?why? due to 「You cannot start a load for a destroyed activity」。
緣由的出處是由於我在滑動那裏作的圖片滑動時中止加載,中止時加載圖片致使的,「You cannot start a load for a destroyed activity」,說白了就是activity在你按back鍵時候已經銷燬了,而那個滾動事件的Glide圖片處理事件還在執行。
mOnScrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); switch (newState) { case SCROLL_STATE_IDLE: Glide.with(MainActivity.this).resumeRequests(); break; case SCROLL_STATE_DRAGGING: case SCROLL_STATE_SETTLING: Glide.with(MainActivity.this).pauseRequests(); break; } }
解決問題:
if(Util.isOnMainThread()) { Glide.with(this).pauseRequest(); }
Glide.with(this).resumeRequests();
@Override protected void onPause() { recyclerView.removeOnScrollListener(mOnScrollListener); super.onPause(); }
僅供學習使用 提供思路,具體實現仍是得按照本身業務邏輯處理
源碼地址
https://github.com/androidHRTZ/SuperRecyclerView.git
轉載請在開頭註明做者詳細信息和本文出處 謝謝
做者:rivc 連接:https://www.jianshu.com/p/519bb23987ca 來源:簡書 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。