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;


@Override


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(){

@SuppressWarnings(
"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);

}

@SuppressWarnings(
"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

{

@Override


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做缓存的方法:



 


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);

}

}


​​
        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,不然会报空指针异常



举报

相关推荐

0 条评论