1.ListView简介
(1)什么是ListView?
一个列表视图,包含许多行,其每一行的布局都相同。
(2)什么是adapter
适配器是AdapterView视图与数据之间的桥梁,用来处理数据并将数据绑定到AdapterView上。
2.ListView的简单实现
实现目标:在屏幕上加载手机应用列表(图标+文件名)
实现步骤
(1)在布局文件中添加ListView
<ListView
android:id="@+id/app_list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
(2)创建每一行的Layout
<ImageView
android:id="@+id/app_icon"
android:layout_width="wrap_content"
android:layout_height="60dp" />
<TextView
android:id="@+id/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
(3)获取手机的APP数据
获取手机中所有应用的信息
private List<ResolveInfo> getAppInfos(){
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
return getPackageManager().queryIntentActivities(intent, 0);
}
(4)用adapter将数据填充到每一行的视图中
public class AppListAdapter extends BaseAdapter{
List<ResolveInfo> mInfos;
//传入适配的数据
public AppListAdapter (List<ResolveInfo> appInfos){
mInfos=appInfos;
}
public int getCount() {
return mInfos.size();
}
public Object getItem(int position) {
return mInfos.get(position);
}
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
LayoutInflater layoutInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.app_list_item, null);
ImageView appImageView=(ImageView)convertView.findViewById(R.id.app_icon);
TextView appTextView=(TextView)convertView.findViewById(R.id.app_name);
appImageView.setImageDrawable(mInfos.get(position).activityInfo.loadIcon(getPackageManager()));
appTextView.setText(mInfos.get(position).activityInfo.loadLabel(getPackageManager()));
return convertView;
}
}
getView详解:
- 首先通过LayoutInflater解析行对应的Layout文件将其变成View对象
- 获取布局文件里的控件
- 为Item 里面的控件设置相应的数据
- 返回View
(4)待适配器和数据都准备好了,获取ListView对象,获取Adapter对象,传入数据setAdap()。
mListView=(ListView)findViewById(R.id.app_list);
mListView.setAdapter(new AppListAdapter(getAppInfos()));
效果图所示:
3.为ListView上的Item添加点击事件
(1)直接在getView中设置点击事件,最后返回convertView就行了(也可以为各控件设置监听事件)
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String pkg=mInfos.get(position).activityInfo.packageName;
String cls=mInfos.get(position).activityInfo.name;
ComponentName componet = new ComponentName(pkg, cls);
Intent intent = new Intent();
intent.setComponent(componet);
startActivity(intent);
}
});
(2)直接为ListView设置监听Item事件
final List<ResolveInfo> mInfos=getAppInfos();
mListView.setAdapter(new AppListAdapter(mInfos));
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
String pkg=mInfos.get(position).activityInfo.packageName;
String cls=mInfos.get(position).activityInfo.name;
ComponentName componet = new ComponentName(pkg, cls);
Intent intent = new Intent();
intent.setComponent(componet);
startActivity(intent);
}
});
4.优化列表
(1)为什么要优化列表?
根据上面的代码我们可以知道每次调用getView时(滑动屏幕),都将item布局重新加载一遍,控件也是每次要通过findViewById重新获取。
(2)解决办法,布局缓存:通过convertView对布局进行缓存,控件缓存:通过ViewHolder()来缓存控件(ViewHolder是个自定义类,包含控件字段),然后调用View的setTag()方法把ViewHolder对象存储在View中。最后通过getTag()方法取出该对象设置控件。
if(convertView == null){
viewHolder = new ViewHolder();
convertView = layoutInflater.inflate(R.layout.item_demo_list, null);
// 获取控件
viewHolder.nameTextView = (TextView) convertView.findViewById(R.id.title_text_view);
viewHolder.avatarImageView = (ImageView) convertView.findViewById(R.id.icon_image_view);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}