分离adapter的getView
2016-02-13 20:55
405 查看
一、前言
习惯很多时候决定了我们的做法,而做法一定程度上又在巩固我们的习惯。细想,这是一件很恐怖的事。所以很多时候要学会用一些新的方式去改变我们的习惯。做技术,亦如此。很多时候,我们写一个listview的adapter,总是会按照我们自己习惯的方式去写,布局简单的还好,布局一复杂起来,你就会看到你的类里面代码几百甚至上千行,这样维护起来是很可怕的。而我个人的编程风格是宁愿类多而不愿一个类里面的代码多。所以很多东西都喜欢抽离出去,尽量让代码之间具有的耦合性降到最低。今天这里要介绍的一种方式是将adapter里面的getview代码分离出一个类去,不要放在getview里面。让你的adapter变得更加清爽,维护起来更加清晰有效,这种方法开始是看到一个github上面的国外大神写的,经过理解,自己也写了一下,放在这里大家学习下。
二、实现
首先讲一下思想,看一下getView这个方法先,这里其实是通过inflate返回了一个view,对了,这里的view是在我们写的一个XML的文件解析出来的。所以我们能不能这样做,自定义一个view,而这个自定义的view就是我们那个listview的一个item的布局,然后这个view就单独作为一个类存在着,只要getView用到了,我们就new出这个自定义的view,让它return。确实,完全可以这样做的。而关于这种方式的好处,后面还会介绍到。
现在思想有了,具体怎样实现比较合理,就可以小思考下咯。尽量设计得通用,方便最好。
上代码解释:
1、首先定义一个接口,用来绑定控件,这里用泛型是为了通用性。
[java] view
plain copy
package com.kroc.adapter;
/**
* 绑定控件接口
* @author 林楷鹏
* @date 2014-12-9 下午9:45:25
*/
public interface IAdapterView<T> {
public void bind(int position, T item);
}
2、listview的一个item布局,简简单单
[html] view
plain copy
<?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" >
<TextView
android:id="@+id/item_food_name_txtv"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_weight="1" />
<TextView
android:id="@+id/item_food_num_txtv"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_weight="1" />
<Button
android:id="@+id/item_food_get_btn"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="获取"
android:layout_weight="1" />
</LinearLayout>
3、根据上面布局定义一个view,这个view就是我们一个listview的item布局,这里实现IAdapterView接口,关于这点好处,后面还会介绍
[java] view
plain copy
package com.kroc.adapter;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.kroc.adapterdemo.R;
import com.kroc.main.FoodBO;
import com.kroc.main.TestActivity;
/**
* item布局对应的view
* @author 林楷鹏
* @date 2014-12-9 下午9:49:01
*/
public class FoodListItemView extends LinearLayout implements IAdapterView<FoodBO>{
private Context mContext;
private TextView nameTxtv;
private TextView numTxtv;
private Button getBtn;
private FoodBO mFoodBO;
public FoodListItemView(Context context) {
super(context);
this.mContext = context;
init();
}
private void init(){
View.inflate(getContext(), R.layout.lv_item_food, this);
nameTxtv = (TextView)findViewById(R.id.item_food_name_txtv);
numTxtv = (TextView)findViewById(R.id.item_food_num_txtv);
getBtn = (Button)findViewById(R.id.item_food_get_btn);
getBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent = new Intent(mContext, TestActivity.class);
intent.putExtra("food", mFoodBO);
mContext.startActivity(intent);
}
});
}
@Override
public void bind(int position, FoodBO foodBO) {
mFoodBO = foodBO;
nameTxtv.setText(foodBO.getFoodName());
numTxtv.setText(foodBO.getFoodNum() + "份");
}
}
4、然后这里就是适配器,注意一下,这里是为了显示这种做法的简洁性,我特意写了两个布局,就是说一个listview的item可以有不同的布局,往往用传统方式写的话,代码会更多,但是在这里可以看到,我的getView里面就是短短几行代码,如此简洁。(其他代码点击下面下载代码去看)。这里可以回想一下,我们平时做这种有多种布局的item是如何做的,是不是把所有的view加载绑定都写到getView里面了,那样是不是让你的代码变得格外臃肿不堪呢?而通过这种方式,你就可以将不同的布局写到不同的类中去,需要用到的时候再new出来就行。
[java] view
plain copy
package com.kroc.adapter;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import com.kroc.main.FoodBO;
/**
* @author 林楷鹏
* @description 食物列表适配
* @create 2014-11-24下午2:37:25
*
*/
public class MyAdapter extends CommonBaseAdapter<FoodBO> {
private static final int ITEM_VIEW_TYPE_NUM = 2;
private static final int ITEM_VIEW_TYPE_FOOD = 0;
private static final int ITEM_VIEW_TYPE_IMAGE = 1;
public MyAdapter(Context context) {
super(context);
}
@Override
public int getViewTypeCount() {
return ITEM_VIEW_TYPE_NUM;
}
@Override
public int getItemViewType(int position) {
if(position % 3 == 0){//为了显示不同item布局
return ITEM_VIEW_TYPE_FOOD;
}else{
return ITEM_VIEW_TYPE_IMAGE;
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
IAdapterView<FoodBO> orderDetail = null;
if(position % 3 == 0){
orderDetail = new FoodListItemView(mContext);
}else{
orderDetail = new ImageListItemView(mContext);
}
orderDetail.bind(position, mList.get(position));
return (View) orderDetail;
}
}
关于定义接口的好处:泛型是一个好处,可以适配不同的数据类型,另外,可以将要显示的item布局都实现接口,这样的话就可以实现多态了。下面看看效果图,从下面的图片可以看到确实也实现了我们要的效果。
另外这样做还有一个好处,就是代码的复用性,假如你有两个地方都用到同一个布局,那么通过这种方式,你就可以在两个地方new两个view就行,不用在两个地方将代码码两遍,那样很烦的。
其他代码不做多解释,还是老规矩。要了解的点击代码下载
习惯很多时候决定了我们的做法,而做法一定程度上又在巩固我们的习惯。细想,这是一件很恐怖的事。所以很多时候要学会用一些新的方式去改变我们的习惯。做技术,亦如此。很多时候,我们写一个listview的adapter,总是会按照我们自己习惯的方式去写,布局简单的还好,布局一复杂起来,你就会看到你的类里面代码几百甚至上千行,这样维护起来是很可怕的。而我个人的编程风格是宁愿类多而不愿一个类里面的代码多。所以很多东西都喜欢抽离出去,尽量让代码之间具有的耦合性降到最低。今天这里要介绍的一种方式是将adapter里面的getview代码分离出一个类去,不要放在getview里面。让你的adapter变得更加清爽,维护起来更加清晰有效,这种方法开始是看到一个github上面的国外大神写的,经过理解,自己也写了一下,放在这里大家学习下。
二、实现
首先讲一下思想,看一下getView这个方法先,这里其实是通过inflate返回了一个view,对了,这里的view是在我们写的一个XML的文件解析出来的。所以我们能不能这样做,自定义一个view,而这个自定义的view就是我们那个listview的一个item的布局,然后这个view就单独作为一个类存在着,只要getView用到了,我们就new出这个自定义的view,让它return。确实,完全可以这样做的。而关于这种方式的好处,后面还会介绍到。
现在思想有了,具体怎样实现比较合理,就可以小思考下咯。尽量设计得通用,方便最好。
上代码解释:
1、首先定义一个接口,用来绑定控件,这里用泛型是为了通用性。
[java] view
plain copy
package com.kroc.adapter;
/**
* 绑定控件接口
* @author 林楷鹏
* @date 2014-12-9 下午9:45:25
*/
public interface IAdapterView<T> {
public void bind(int position, T item);
}
2、listview的一个item布局,简简单单
[html] view
plain copy
<?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" >
<TextView
android:id="@+id/item_food_name_txtv"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_weight="1" />
<TextView
android:id="@+id/item_food_num_txtv"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_weight="1" />
<Button
android:id="@+id/item_food_get_btn"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="获取"
android:layout_weight="1" />
</LinearLayout>
3、根据上面布局定义一个view,这个view就是我们一个listview的item布局,这里实现IAdapterView接口,关于这点好处,后面还会介绍
[java] view
plain copy
package com.kroc.adapter;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.kroc.adapterdemo.R;
import com.kroc.main.FoodBO;
import com.kroc.main.TestActivity;
/**
* item布局对应的view
* @author 林楷鹏
* @date 2014-12-9 下午9:49:01
*/
public class FoodListItemView extends LinearLayout implements IAdapterView<FoodBO>{
private Context mContext;
private TextView nameTxtv;
private TextView numTxtv;
private Button getBtn;
private FoodBO mFoodBO;
public FoodListItemView(Context context) {
super(context);
this.mContext = context;
init();
}
private void init(){
View.inflate(getContext(), R.layout.lv_item_food, this);
nameTxtv = (TextView)findViewById(R.id.item_food_name_txtv);
numTxtv = (TextView)findViewById(R.id.item_food_num_txtv);
getBtn = (Button)findViewById(R.id.item_food_get_btn);
getBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent = new Intent(mContext, TestActivity.class);
intent.putExtra("food", mFoodBO);
mContext.startActivity(intent);
}
});
}
@Override
public void bind(int position, FoodBO foodBO) {
mFoodBO = foodBO;
nameTxtv.setText(foodBO.getFoodName());
numTxtv.setText(foodBO.getFoodNum() + "份");
}
}
4、然后这里就是适配器,注意一下,这里是为了显示这种做法的简洁性,我特意写了两个布局,就是说一个listview的item可以有不同的布局,往往用传统方式写的话,代码会更多,但是在这里可以看到,我的getView里面就是短短几行代码,如此简洁。(其他代码点击下面下载代码去看)。这里可以回想一下,我们平时做这种有多种布局的item是如何做的,是不是把所有的view加载绑定都写到getView里面了,那样是不是让你的代码变得格外臃肿不堪呢?而通过这种方式,你就可以将不同的布局写到不同的类中去,需要用到的时候再new出来就行。
[java] view
plain copy
package com.kroc.adapter;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import com.kroc.main.FoodBO;
/**
* @author 林楷鹏
* @description 食物列表适配
* @create 2014-11-24下午2:37:25
*
*/
public class MyAdapter extends CommonBaseAdapter<FoodBO> {
private static final int ITEM_VIEW_TYPE_NUM = 2;
private static final int ITEM_VIEW_TYPE_FOOD = 0;
private static final int ITEM_VIEW_TYPE_IMAGE = 1;
public MyAdapter(Context context) {
super(context);
}
@Override
public int getViewTypeCount() {
return ITEM_VIEW_TYPE_NUM;
}
@Override
public int getItemViewType(int position) {
if(position % 3 == 0){//为了显示不同item布局
return ITEM_VIEW_TYPE_FOOD;
}else{
return ITEM_VIEW_TYPE_IMAGE;
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
IAdapterView<FoodBO> orderDetail = null;
if(position % 3 == 0){
orderDetail = new FoodListItemView(mContext);
}else{
orderDetail = new ImageListItemView(mContext);
}
orderDetail.bind(position, mList.get(position));
return (View) orderDetail;
}
}
关于定义接口的好处:泛型是一个好处,可以适配不同的数据类型,另外,可以将要显示的item布局都实现接口,这样的话就可以实现多态了。下面看看效果图,从下面的图片可以看到确实也实现了我们要的效果。
另外这样做还有一个好处,就是代码的复用性,假如你有两个地方都用到同一个布局,那么通过这种方式,你就可以在两个地方new两个view就行,不用在两个地方将代码码两遍,那样很烦的。
其他代码不做多解释,还是老规矩。要了解的点击代码下载
相关文章推荐
- android必备技能-shape
- uva11134 -Fabled Rooks
- Android_SDK_Windows免费下载链接
- Java Gis 拓扑图(Google 地图)
- VB.NET视频总结(1-7集)
- 电商后台制作遇到的问题
- C++类模板
- Arduino代码机制-引脚读写
- Python算24点
- 成功人士追踪
- 快速初始化 NSArray *viewControllers = @[viewController1, viewController2];
- poj 1088 滑雪
- 书籍名单
- 学习笔记------数据结构(C语言版)串的堆分配存储表示
- 在Sublime Text里开发go
- ASPNET开源项目
- iOS 去掉UITextField前后空格
- iOS开发中对文件目录的访问及管理的基本方法小结
- 简单工厂、工厂方法和抽象工厂的区别
- 【bzoj1596】[Usaco2008 Jan]电话网络 树形dp