Android ListView載入多item佈局及效能優化
阿新 • • 發佈:2019-02-06
前言:在開發過程中,遇到一些比較舊的專案,請求網路資料時,介面返回一長串的JSON字串,其中包括各種不相關的資料。而我們又需要把這些資料一一對應寫在同一個介面上,又需要分別展示在不同的佈局上,這時候就需要用到ListView。
而當listview有大量的資料需要載入的時候,會佔據大量記憶體,影響效能,這時候就需要按需填充並重新使用view來減少物件的建立。所以這裡我們在展示多佈局的同時,也對ListView載入效能優化。
廢話講了這麼多,下面我們直接開始做個類似獲取課程大綱的demo,先看一眼需要做的效果圖介面:
需求是,B資料量會根據請求的資料而發生變化,A,B,C分別對應不同的佈局。
下面直接上程式碼:
package com.donkor.demo;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
import java.util.Map;
/**
* @author donkor
*/
public class DetailListAdapter extends BaseAdapter {
private Activity mContext; //執行上下文
private List<Map<String, Object>> listItems; //列表資訊集合
private LayoutInflater inflater; //檢視容器
final int TYPE_1 = 0;
final int TYPE_2 = 1;
final int TYPE_3 = 2;
public DetailListAdapter(Activity context, List<Map<String, Object>> listItems) {
this.mContext = context;
//建立檢視容器並設定上下文
inflater = LayoutInflater.from(context);
this.listItems = listItems;
}
@Override
public int getCount() {
return listItems.size();
}
@Override
public Object getItem(int position) {
return listItems.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
/**
* 根據資料列表的position返回需要展示的layout的對應的type
* type的值必須從0開始
*/
@Override
public int getItemViewType(int position) {
int p = position;
//這裡我們修改的是對應頭item和底部item
if (p == 0)
return TYPE_1;
else if (p == (listItems.size()-1))
return TYPE_3;
else
return TYPE_2;
}
/**
* 該方法返回多少個不同的佈局
*/
@Override
public int getViewTypeCount() {
return 3;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder1 holder1 = null;
ViewHolder2 holder2 = null;
ViewHolder3 holder3 = null;
int type = getItemViewType(position);
if (convertView == null) {
inflater = LayoutInflater.from(mContext);
// 按當前所需的樣式,確定new的佈局
switch (type) {
case TYPE_1:
convertView = inflater.inflate(R.layout.couese_detail_top,
parent, false);
holder1 = new ViewHolder1();
holder1.tvCourseTime = (TextView) convertView
.findViewById(R.id.tvCourseTime);
holder1.tvTeacherName = (TextView) convertView
.findViewById(R.id.tvTeacherName);
holder1.tvCourseObject = (TextView) convertView
.findViewById(R.id.tvCourseObject);
convertView.setTag(holder1);
break;
case TYPE_2:
convertView = inflater.inflate(R.layout.course_list_item,
parent, false);
holder2 = new ViewHolder2();
holder2.tvCoursedescwap = (TextView) convertView
.findViewById(R.id.tvCoursedescwap);
convertView.setTag(holder2);
break;
case TYPE_3:
convertView = inflater.inflate(R.layout.course_detail_bottom,
parent, false);
holder3 = new ViewHolder3();
holder3.ivCoursePic = (ImageView) convertView
.findViewById(R.id.ivCoursePic);
convertView.setTag(holder3);
break;
default:
break;
}
} else {
switch (type) {
case TYPE_1:
holder1 = (ViewHolder1) convertView.getTag();
break;
case TYPE_2:
holder2 = (ViewHolder2) convertView.getTag();
break;
case TYPE_3:
holder3 = (ViewHolder3) convertView.getTag();
break;
}
}
// 設定資源
switch (type) {
case TYPE_1:
String courseTime = (String) listItems.get(position).get("courseTime");
String teacherName = (String) listItems.get(position).get("teacherName");
String courseObject = (String) listItems.get(position).get("courseObject");
holder1.tvCourseTime.setText(courseTime);
holder1.tvTeacherName.setText(teacherName);
holder1.tvCourseObject.setText(courseObject);
break;
case TYPE_2:
String author = (String) listItems.get(position).get("author");
holder2.tvCoursedescwap.setText(author);
break;
case TYPE_3:
holder3.ivCoursePic.setImageResource(R.mipmap.background2);
break;
}
return convertView;
}
public class ViewHolder1 {
TextView tvCourseTime, tvTeacherName, tvCourseObject;
}
public class ViewHolder2 {
TextView tvCoursedescwap;
}
public class ViewHolder3 {
ImageView ivCoursePic;
}
}
※當處理一些耗時的資源載入的時候需要做到以下幾點,以使你的載入更快更平滑:
- 介面卡在介面主執行緒中進行修改
- 可以在任何地方獲取資料但應該在另外一個地方請求資料
- 在主介面的執行緒中提交介面卡的變化並呼叫adapter的notifyDataSetChanged()方法修改UI
▲其他需要注意的地方:
- adapter中的getViewTypeCount():該方法返回多少個不同的佈局
- adapter中的getItemViewType(int
position):根據資料列表的position返回需要展示的layout的對應的type。 type的值必須從0開始