介绍适配器的使用,从浅到深,一共6步,这6步所用到的xml文件相同,就是下面这两个
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${relativePackage}.${activityClass}" >
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
item1中第二个TextView只有在5和6中用到
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<ImageView
android:id="@+id/item1_iv"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="center_vertical"
android:src="@drawable/h2" />
<TextView
android:id="@+id/item1_tv"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="ddddddd"
android:gravity="center" />
<CheckBox
android:id="@+id/item1_cb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
</LinearLayout>
1.简单适配器的使用
package com.example.adapterdemo2;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity2 extends Activity {
ListView lv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv=(ListView) findViewById(R.id.lv);
MyAdapter ma=new MyAdapter();
lv.setAdapter(ma);
}
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
// TODO Auto-generated method stub
return 30;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
LayoutInflater layoutInflater=MainActivity2.this.getLayoutInflater();
View view=layoutInflater.inflate(R.layout.item1, parent,false);
return view;
}
}
}
这篇代码实现的功能比较简单,在activity_main.xml文件中创建一个组件ListView,设置相应的id.在MainActivity中findViewByid实例化这个控件.
创建一个子类继承BaseAdapter,实现抽象方法.在getCount()方法中设置条目数量,之后再getView()方法中实现下面的功能(MainActivity中没有以下注释)
之后的步骤就是创建子类的对象,然后通过setAdapter();方法将这个对象传进去,详情看代码
2.将集合数据传到条目中的适配器的使用
package com.example.adapterdemo2;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity {
private ListView lv;
private List<String>datas=new ArrayList<String>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for(int i=0;i<40;i++){
datas.add("我是数据------>"+i);
}
lv=(ListView) findViewById(R.id.lv);
MyAdapter ma=new MyAdapter();
lv.setAdapter(ma);
}
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
// TODO Auto-generated method stub
return datas.size();
}
@Override
public String getItem(int position) {
// TODO Auto-generated method stub
return datas.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
LayoutInflater layoutInflater=MainActivity.this.getLayoutInflater();
View view=layoutInflater.inflate(R.layout.item1, parent,false);
TextView tv=(TextView)view.findViewById(R.id.item1_tv);
tv.setText(getItem(position));
return view;
}
}
}
和上面的适配器的使用基本一样,有几处需要注意的地方
(1)下面代码红色标注的地方,注意这里并不是activity_main中的组件,而是在上一行view对象中,上一行已经将相应的布局文件转换成View对象,而所加载的TextView就在这个布局中,所以在这里应该特别注意
(2)红线标注的方法,返回一个字符串,position是条目的位置,也可以将第二个横线位置,换成datas.get(position),也就是上面方法的返回值
3.适配器内部的优化使用(针对View对象)
这个适配器的使用效果和上的适配器使用的效果一样,但是内部进行了优化,使内存的使用的到了优化
getView() 方法会被反复调用很多次,加载不同位置的条目
当ListView初次展开时,getView方法调用多少次?
取决于当前界面展现了多少条目,不展现的条目暂时不加载 ——这就是BaseAdapter的内部优化机制
当上下滚动时,界面展现哪个条目,我们就调用getView方法加载哪一个条目
此时因为 重新调用了该位置的getView,所以会重新inflate一个新的view对象,那么之前我们旧的view对象就成为了垃圾对象 ,造成内存必要的消耗
所以,我们要针对此种情况进行优化 :复用view对象 使用参数converView
假如我们界面 可以展现5个条目 那么总共会有多少个view对象?会有7个,最上面的露一半,最下面的露一半.所以可能有7个
在这篇代码getView方法中有如下代码
在标签可以看出converView.hashCode()的值会被反复使用,而上一个适配器的使用converView.hashCode()所打印的完全不同.关于这里的优化问题在另一篇笔记适配器(2)中有介绍
4.适配器内部的优化使用(针对View和TextView对象)
针对View对象造成的内存浪费,在3中已经进行了优化,但是在每次调用getVeiw方法,更新TextView对象tv时,tv都会重新finViewById,而这个方法也会重新创建一个对象,也会造成内存的浪费,(在新版本的手机中这个问题已经在版本中进行了优化,不用开发者考虑,但是我们也需要知道这个原理和方法,主要针对没有进行优化的手机版本),问题和3中所说的问题相似,就不在赘述,只说一下解决方法.
我已开始是这么理解的:
convertView怎么解决,tv就怎么解决,这样的理解是错了,因为converView是缓存对象,是时刻存在的而TextView的对象tv不是,每次执行这个方法时,tv对象都需要重新创建,而converView不为空时,tv为空,所以既然convertView不会消失,那么就将tv存到converView中,于是就有了开始时候的解决办法了,通过setTag进行存储,getTag进行提取
5.多个TextView对象的适配器的使用
我一开始的理解是如果有两个TextView,是不是可以一个一个的使用,就和上面TextView对象tv一样,只是多了一个,事实是错的,因为convertView的setTag方法只能用一次,getTag也是同样的道理
所以应用java面向对象的思想,一个功能一个类,将多个TextView对象封装到一个类里面,对这个类对象进行操作即可,代码不难,理解思想
6.对CheckBox使用优化的适配器
因为convertView对象中没有储存CheckBox的状态,所以就算打上勾条目消失后,勾选状态也就消失了,所以应该想办法,留住相应位置的选中状态,可以用键值对来储存,也就是用Map集合,位置是Key,状态是Value.把CheckBox也封装到类里面(就是5中的 ViewHolder类)
图中红线:将位置存到CheckBox对象cb的Tag里
图中紫线:对cb进行监听(最好不要内名内部类,因为每次都会产生一个新对象)
图中蓝线:根据位置position(Key)取出是否被选中的状态(Value)
图中黄线:取出存储在cb中的位置