前言:在开发过程中,遇到一些比较旧的项目,请求网络数据时,接口返回一长串的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;
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);
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开始
Demo下载