当前位置: 代码迷 >> Android >> Android之Adapter小结
  详细解决方案

Android之Adapter小结

热度:61   发布时间:2016-05-01 11:33:49.0
Android之Adapter总结
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://lichen.blog.51cto.com/697816/492200
?
Adapter是用来帮助填充数据的中间桥梁,比如通过它将数据填充到ListView, GridView, Gallery.而android 提供了几种Adapter:ArrayAdapter, BaseAdapter, CursorAdapter, HeaderViewListAdapter, ListAdapter, ResourceCursorAdapter, SimpleAdapter, SimpleCursorAdapter, SpinnerAdapter, WrapperListAdapter.
根据数据来源形式的不同可以选择不同的Adapter,比如数据来源于一个Arraylist 就使用BaseAdapter,SimpleAdapter,而数据来源于通过查询数据库获得Cursor那就使用SimpleCursorAdapter.
使用simpleadapter的例子:
?
主布局文件
<!--main.xml-->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
????????android:orientation="vertical"
????????android:layout_width="fill_parent"
????????android:layout_height="fill_parent"
????????>
????????<RelativeLayout
??????android:layout_width="wrap_content"
??????android:layout_height="wrap_content"
???????? >
???????? <Spinner
???????????????? android:id="@+id/subway_lines"
???????????????? android:layout_width="fill_parent"
???????????????? android:layout_height="wrap_content">
???????? </Spinner>
???????? <TextView
????????????android:layout_width="fill_parent"
????????????android:layout_height="wrap_content"
????????????android:layout_below="@id/subway_lines"
????????????android:layout_alignLeft="@id/subway_lines"
????????????android:id="@+id/select_line"
???????? />
???? </RelativeLayout>
????<ListView
????android:layout_width="fill_parent"
????android:layout_height="fill_parent"
????android:id="@+id/station_listView"
????/>
</LinearLayout>
?
然后是ListView布局
<!--stationitem.xml-->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
????xmlns:android="http://schemas.android.com/apk/res/android"
????android:layout_width="fill_parent"
????android:layout_height="fill_parent">
???? <TextView
????????android:layout_width="200px"
????????android:layout_height="fill_parent"
????????android:textSize="20px"
????????android:gravity="center_horizontal"
????????android:id="@+id/station_name"
???? />
???? <TextView
????????android:layout_width="200px"
????????android:layout_height="fill_parent"
????????android:layout_toRightOf="@id/station_name"
????????android:textSize="20px"
????????android:layout_alignTop="@id/station_name"
????????android:id="@+id/station_info"
???? />
</RelativeLayout>
?
接下来是Activity
import java.util.ArrayList;

public class SubwayActivity extends Activity {

????????private static final String TAG = "SubwayActivity";
????????private SubwayService subwayService;
????????private TextView selectLine;
????????private Spinner subwayLines;
????????private ArrayAdapter<String> linesAdapter;
????????private List<String> linesNames;
????????private ListView stationListView;
????????private SimpleAdapter stationsAdapter;

[email protected]
????????public void onCreate(Bundle savedInstanceState) {
????????????????super.onCreate(savedInstanceState);
????setContentView(R.layout.main);

????stationListView = (ListView) findViewById(R.id.station_listView);
????subwayService = new SubwayService(this);

????//初始化数据
//????subwayService.init();

????List<SubwayLine> listLines = subwayService.getLineScrollData();
????linesNames = new ArrayList<String>();
????for (SubwayLine subwayLine : listLines) {
??????linesNames.add(subwayLine.getLineName());
????}
????// 第一步:添加一个下拉列表项的list,这里添加的项就是下拉列表的菜单项
????selectLine = (TextView) findViewById(R.id.select_line);
????subwayLines = (Spinner) findViewById(R.id.subway_lines);
????// 第二步:为下拉列表定义一个适配器,这里就用到里前面定义的list。
????linesAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,linesNames);
????// 第三步:为适配器设置下拉列表下拉时的菜单样式。
????linesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
????// 第四步:将适配器添加到下拉列表上
????subwayLines.setAdapter(linesAdapter);
????//第五步:为下拉列表设置各种事件的响应,这个事响应菜单被选中
????subwayLines.setOnItemSelectedListener(selectedListener);
????/*下拉菜单弹出的内容选项触屏事件处理*/
????subwayLines.setOnTouchListener(onTouchListener);
????/*下拉菜单弹出的内容选项焦点改变事件处理*/
????subwayLines.setOnFocusChangeListener(onFocusChangeListener);
????????}

????????/**
???????? * 为下拉列表设置各种事件的响应,这个事响应菜单被选中
???????? */

????????private OnItemSelectedListener selectedListener =????new Spinner.OnItemSelectedListener(){
[email protected]("unchecked")
????????????????public void onItemSelected(AdapterView arg0, View arg1, int arg2, long arg3) {
????????????String lineName = linesAdapter.getItem(arg2);
????????????SubwayLine line = subwayService.findLine(lineName);
????????????/*根据lineId查询出stations*/
????????????List<SubwayStation> stations = subwayService.getStationLineScrollData(line.getLineId());
????????????/*把stations的属性值放到List<HashMap<String, String>>中*/
????????????List<HashMap<String, String>> data = new????ArrayList<HashMap<String, String>>();
????????????????????????for (SubwayStation station : stations) {
??????????????????????????HashMap<String, String> map = new HashMap<String, String>();
??????????????????????????if(station.getIsChange() == 1){
????????????????????????????map.put("stationName", station.getStationName());
????????????????????????????List<SubwayStation> changeStations = subwayService.getChangeStationExceptThis(station.getStationName(), line.getLineId());
????????????????????????????StringBuilder builder = new StringBuilder();
????????????????????????????builder.append("换乘 ");
????????????????????????????if(changeStations != null && changeStations.size() > 0){
??????????????????????????????for (SubwayStation changeStation : changeStations) {
????????????????????????????????SubwayLine changeLine = subwayService.findLine(changeStation.getLineId());
??????????????????????????????????????builder.append(changeLine.getLineName()).append(",");
??????????????????}
??????????????????????????????builder.deleteCharAt(builder.length()-1);
????????????????????????????}
??????????????????????????????????map.put("stationInfo",builder.toString());
??????????????????????????}else{
????????????????????????????map.put("stationName", station.getStationName());
??????????????????????????????????map.put("stationInfo", station.getStationInfo());
??????????????????????????}
????????????????????????????????data.add(map);
????????????}
????????????????????????/*设置stationsAdapter适配器*/
??????stationsAdapter = new SimpleAdapter(
??????????SubwayActivity.this,
??????????data,
??????????R.layout.stationitem,
??????????new String[] { "stationName", "stationInfo" },
??????????new int[] { R.id.station_name, R.id.station_info });
??????stationListView.setAdapter(stationsAdapter);

????????????????????????/* 将所选mySpinner 的值带入myTextView 中*/
??????????????????selectLine.setText("以下是:"+ lineName +" 车站列表...");
????????????????????????/* 将mySpinner 显示*/
????????????????????????arg0.setVisibility(View.VISIBLE);
????????????????}
[email protected]("unchecked")
????????????????public void onNothingSelected(AdapterView arg0) {
??????????????????selectLine.setText("");
????????????????????????arg0.setVisibility(View.VISIBLE);
????????????????}
????????};

????????/**
???????? * 下拉菜单弹出的内容选项触屏事件处理
???????? */

????????private OnTouchListener onTouchListener = new Spinner.OnTouchListener(){
????????????????public boolean onTouch(View v, MotionEvent event) {
????????????????????????/* 将mySpinner 隐藏,不隐藏也可以,看自己爱好*/
//????????????????????????v.setVisibility(View.INVISIBLE);
????????????????????????return false;
????????????????}
????????};

????????/**
???????? * 下拉菜单弹出的内容选项焦点改变事件处理
???????? */

????????private OnFocusChangeListener onFocusChangeListener = new Spinner.OnFocusChangeListener(){
????public void onFocusChange(View v, boolean hasFocus) {
??????v.setVisibility(View.VISIBLE);
????}
??};
}
?
其中,核心的是
/*设置stationsAdapter适配器*/
????????????stationsAdapter = new SimpleAdapter(
????????????????????SubwayActivity.this,
????????????????????data,
????????????????????R.layout.stationitem,
????????????????????new String[] { "stationName", "stationInfo" },
????????????????????new int[] { R.id.station_name, R.id.station_info });
????????????stationListView.setAdapter(stationsAdapter);
?
===========================================================
以上是简单的使用adapter的方法,一般情况下这样就够用了.接下来是自定义adapter.
?
继承BaseAdapter,重写四个方法.
public class WeatherAdapter extends BaseAdapter {

????????private Context context;
????????private List<Weather> weatherList;????????//这就是adapter关联的List,用来存储数据.还记的ArrayList

????????public WeatherAdapter(Context context, List<Weather> weatherList ) {
????????????????this.context = context;
????????????????this.weatherList = weatherList;
????????}

????????public int getCount() {
????????????????return weatherList.size();
????????}

????????public Object getItem(int position) {
????????????????return weatherList.get(position);
????????}

????????public long getItemId(int position) {
????????????????return position;
????????}

????????public View getView(int position, View convertView, ViewGroup parent) {
????????????????Weather weather = weatherList.get(position);
????????????????return new WeatherAdapterView(this.context, weather );
????????}

}

自定义的View
class WeatherAdapterView extends LinearLayout {
????????????????public static final String LOG_TAG = "WeatherAdapterView";

????????????????public WeatherAdapterView(Context context,
????????????????????????????????????????????????????????????????Weather weather ) {
????????????????????????super( context );

????????????????????????this.setOrientation(HORIZONTAL);
????????????????????????LinearLayout.LayoutParams cityParams =
????????????????????????????????new LinearLayout.LayoutParams(100, LayoutParams.WRAP_CONTENT);
????????????????????????cityParams.setMargins(1, 1, 1, 1);

????????????????????????TextView cityControl = new TextView( context );
????????????????????????cityControl.setText( weather.getCity() );
????????????????????????addView( cityControl, cityParams);

????????????????????????LinearLayout.LayoutParams temperatureParams =
????????????????????????????????new LinearLayout.LayoutParams(20, LayoutParams.WRAP_CONTENT);
????????????????????????temperatureParams.setMargins(1, 1, 1, 1);

????????????????????????TextView temperatureControl = new TextView(context);
????????????????????????temperatureControl.setText( Integer.toString( weather.temperature ) );
????????????????????????addView( temperatureControl, temperatureParams);

????????????????????????LinearLayout.LayoutParams skyParams =
????????????????????????????????new LinearLayout.LayoutParams(25, LayoutParams.WRAP_CONTENT);

????????????????????????ImageView skyControl = new ImageView( context );
????????????????????????Log.d( LOG_TAG, weather.getCity()+" -> "+weather.sky );
????????????????????????skyControl.setImageResource( weather.getSkyResource() );
????????????????????????addView( skyControl, skyParams );
????????????????}
}

最后在Activity中使用
public class CustomAdapterActivity extends ListActivity
{
[email protected]
????????public void onCreate(Bundle savedInstanceState)
????????{
????????????????super.onCreate(savedInstanceState);
????????????????setContentView(R.layout.main);
????????????????ArrayList<Weather> weatherList = new ArrayList<Weather>();
????????????????Weather w = new Weather( "London", 17, Weather.OVERCAST );
????????????????weatherList.add( w );
????????????????w = new Weather( "Paris", 22, Weather.OVERCAST );
????????????????weatherList.add( w );
????????????????w = new Weather( "Athens", 29, Weather.SUNNY );
????????????????weatherList.add( w );
????????????????w = new Weather( "Stockholm", 12, Weather.RAIN );
????????????????weatherList.add( w );
????????????????WeatherAdapter weatherAdapter = new WeatherAdapter(
????????????????????????????????this,
????????????????????????????????weatherList );
????????????????setListAdapter( weatherAdapter );
????????}
}

?
===========================================================
再就是Adapter的优化,一个广为流传的 ViewHolder、ViewCache办法:
?
public View getView(int position, View convertView, ViewGroup parent) {

??ViewHolder holder;
??if (convertView == null) {
????holder = new ViewHolder();
????convertView = inflater.inflate(R.layout.topic_list, null);
????holder.title = (TextView) convertView.findViewById(R.id.title);
????convertView.setTag(holder);
??} else {
????holder = (ViewHolder) convertView.getTag();
??}
}

public class ViewHolder {
??public TextView getTitle() {
????if (title == null) {
??????title = (TextView) baseView.findViewById(R.id.title);
????}
????return title;
??}
}

?
或者使用HashMap做缓存的方法:
?
HashMap<Integer, View> m = new HashMap<Integer, View>();

public View getView(int position, View view, ViewGroup parent) {

??View convertView = m.get(position);
??if (convertView != null) {
????return convertView;
??} else {
????convertView = inflater.inflate(R.layout.topic_list, null);
????TextView title = (TextView) convertView.findViewById(R.id.title);
????m.put(position, convertView);
??}
}
来自:http://www.eoeandroid.com/thread-56717-1-1.html
???????Adapter是用来帮助填充数据的中间桥梁,比如通过它将数据填充到ListView, GridView, Gallery.而android 提供了几种Adapter:ArrayAdapter<T>, BaseAdapter, CursorAdapter, HeaderViewListAdapter, ListAdapter, ResourceCursorAdapter, SimpleAdapter, SimpleCursorAdapter, SpinnerAdapter, WrapperListAdapter.我猜想这些Adapter的区别在于你的数据来源不一样:比如若你的数据来源于一个Arraylist 就使用BaseAdapter,SimpleAdapter,而数据来源于通过查询数据库获得Cursor那就使用SimpleCursorAdapter等。就目前我经常使用的BaseAdapter和SimpleCursorAdapter。


? ???1,BaseAdapter:---数据来源于Arraylist-->MyArraylist
当你继承BaseAdapter客制化你的Adapter时,你必须OverWrite以下函数:
Java代码
@Override? ?
? ?? ???public int getCount() {? ?
? ?? ?? ?? ?// TODO Auto-generated method stub? ?
? ?? ?? ?? ?System.out.println("the size is\t" +? ?? ?? ?? ?MyArraylist.size());? ?
? ?? ?? ?? ?return MyArraylist.size();? ?
? ?? ???}? ?
@Override
public int getCount() {
// TODO Auto-generated method stub
System.out.println("the size is\t" +? ?? ?? ?? ?MyArraylist.size());
return MyArraylist.size();
}
? ?? ? getCount返回的就是你的有多少条数据需要绑定的,也就是需要多少个View.比如这里返回的就是MyArraylist的Size.

Java代码
public View getView(int position, View v, ViewGroup parent) {? ?
? ?? ?? ?? ?// TODO Auto-generated method stub? ?
? ?? ?? ?? ?? ?
? ?? ?? ?? ?View view;? ?
? ?? ?? ?? ?if (v == null) {? ?
? ?? ?? ?? ?? ? view = mInflater.inflate(R.layout.track_list_item, null);? ?
? ?? ?? ?? ?} else {? ?
? ?? ?? ?? ?? ? view = v;? ?
? ?? ?? ?? ?}}? ?
public View getView(int position, View v, ViewGroup parent) {
// TODO Auto-generated method stub
View view;
if (v == null) {
view = mInflater.inflate(R.layout.track_list_item, null);
} else {
view = v;
}}

? ?? ? 通过getView就获得了view来显示数据了。在这里你就可以自定义你的View了,但你通过XML定义可以通过LayoutInflater来inflater你的XML。getView里面就可以将MyArraylist的数据通过position 这个来将数据一条绑定一个View了。


? ???2,SimpleCursorAdapter:---数据来源于数据库--->MyCursor
? ?? ? 要实现bindView()和newView()这两个抽象方法需要实现的内容。

? ?? ? public void bindView(View view, Context context, Cursor cursor),重用一个已有的view,使其显示当前cursor所指向的数据。

? ?? ?public View newView(Context context, Cursor cursor, ViewGroup parent),为cursor所指向的数据新建一个View对象,并显示其数据。

? ?? ?通俗的说:比如你一个listview在一个屏幕里一次只能显示8条数据,那么第一次显示的时候就会newView 8次生成8个View,调用bindView绑定8条数据,而你有16条数据,但你拖动滚动条看9-16条时,此时不会再调用newView了,而只能调用了bindView去绑定新的数据而了。这样就省了空间了。


? ?? ? 注意:传入到CursorAdapter中的Cursor结果集必须包含有列名为_id的列,否则SimpleCursorAdapter将不会起作用。

对于SimpleCursorAdapter中的newView与bindView的作用在BaseAdapter中的getView中也有这样的意义:getView里面我们必须做判断才能达到这种效果,就是要判断第二个参数View的是否为空:当空时就Infalte新的View,但不为空时就要就用它,这样就第一屏幕Infate 8个View,后面就直接使用这个8个view了。

注意:getView中是返回一个view,必须返回的是你infalte之后不为空的View,不然会报空指针异常
  相关解决方案