RecyclerView複用ViewHolder導致控制元件有時顯示有時消失問題
阿新 • • 發佈:2019-01-27
本篇內容僅用來記錄開發過程,提醒自己。本人目前實習,剛結束安卓三個月,能力有限,如有錯誤,歡迎指出。
在開發專案過程中,使用Recycler有需求需要在不同情況下顯示不同的控制元件。當時並不知道ViewHolder會被複用,並且只針對不同情況進行控制元件隱藏,但是並未顯示,導致複用該ViewHolder的item的某些控制元件不顯示。在空閒時間自己寫了一個Demo進行了驗證。
以下是Demo內容
首先寫一個最簡單的RecycleView例子
MainActivity.java
public class MainActivity extends AppCompatActivity {
@BindView(R.id.rv_demo)
RecyclerView rvDemo;
@BindView(R.id.btn_demo)
Button btnDemo;
private AdapterDemo adapterDemo;
private Set<AdapterDemo.MyViewHoder> viewHoderSet = new HashSet<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
List <String> list = new ArrayList<>();
list.add("0");
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
list.add("6");
list.add("7");
list.add("8");
list.add("9");
list.add("10");
list .add("11");
list.add("12");
list.add("13");
list.add("14");
list.add("15");
list.add("16");
list.add("17");
list.add("18");
list.add("19");
list.add("20");
list.add("21");
list.add("22");
adapterDemo = new AdapterDemo(list, this);
rvDemo.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
rvDemo.setAdapter(adapterDemo);
}
@OnClick(R.id.btn_demo)
public void showViewHolder(){
Iterator<AdapterDemo.MyViewHoder> iterator = viewHoderSet.iterator();
Log.i("個數", "viewHolder " + viewHoderSet.size());
while (iterator.hasNext()){
Log.i("viewHolder", iterator.next().toString());
}
}
public class AdapterDemo extends RecyclerView.Adapter<AdapterDemo.MyViewHoder> {
private List<String> demoList;
private Context mContext;
public AdapterDemo(List<String> demoList, Context mContext) {
this.demoList = demoList;
this.mContext = mContext;
}
@Override
public MyViewHoder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(mContext).inflate(R.layout.adapter_item, parent, false);
return new MyViewHoder(v);
}
@Override
public void onBindViewHolder(MyViewHoder holder, int position) {
Log.e("測試", holder.toString() + " -- " + position);
viewHoderSet.add(holder);
if (position % 5 == 0)
holder.tv_demo.setVisibility(View.GONE);
else
holder.tv_demo.setText(demoList.get(position));
}
@Override
public int getItemCount() {
return demoList.size();
}
class MyViewHoder extends RecyclerView.ViewHolder {
ImageView iv_demo;
TextView tv_demo;
public MyViewHoder(View itemView) {
super(itemView);
iv_demo = itemView.findViewById(R.id.iv_demo);
tv_demo = itemView.findViewById(R.id.tv_demo);
}
}
}
}
MainActivity佈局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.qxb_810.myapplication.MainActivity"
android:orientation="vertical">
<Button
android:text="列印viewHolder"
android:id="@+id/btn_demo"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginBottom="20dp"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_demo"
android:layout_width="match_parent"
android:layout_height="wrap_content"></android.support.v7.widget.RecyclerView>
</LinearLayout>
RecycleView item 佈局
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
>
<ImageView
android:id="@+id/iv_demo"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@color/colorAccent"/>
<TextView
android:id="@+id/tv_demo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="60sp"
android:text="555555"/>
</LinearLayout>
實現的功能很簡單,就是在頁面上顯示如下圖的頁面,其中把position是5的倍數的ViewHolder的tv_Demo 控制元件隱藏掉。按鈕的功能是為了能清除的看到生成了幾個ViewHolder。效果如圖
列印的Log:
目前為止一切正常,可以看到確實position為5的倍數的ViewHolder的TextView確實被隱藏掉了。然後向下滑動到最底層。
效果如圖:
這裡發現了postion為17和22的TextView也不見了,檢視一下Log
發現第17和第22的ViewHolder是複用第0個和第5個的ViewHolder,而在程式碼處理中,第0個和第5個的ViewHolder中的TextView我們給隱藏掉了。
關鍵程式碼如下:
當執行到postion = 17 的時候,判斷一下postion不是5的倍數,執行賦值操作,但是這個ViewHolder在postion等於5的時候TextView被隱藏了,而且這裡並沒有在賦值操作時設定TextView可見,導致雖然賦值了,但是不可見也沒用。想要改正也很簡單,加一句可見語句就行。
另外在列印ViewHolder生成個數的時候發現總共生成了12個ViewHolder,然而我們又23個item。(不同裝置生成的可能不一樣,我這裡用PAD生成12個,用手機生成10個,另外如果加上可見語句則PAD生成11個)
因為這個問題導致在專案開發時利用RecycleView展示的時候資料時有時無,頭疼了好幾天,特地記錄一下。RecyclerView為了效能考慮複用無可厚非,所以打算並且抽時間深度研究一下RecyclerView的複用機制。