Android基础类之BaseAdapter

BaseAdapter就Android应用程序中经常用到的基础数据适配器,它的主要用途是将一组数据传到像ListView、Spinner、Gallery及GridView等UI显示组件,它是继承自接口类Adapter,
1、Adapter类简介
1)、Adapter相关类结构如下图所示:
Adapter
自定义Adapter子类,就需要实现上面几个方法,其中最重要的是getView()方法,它是将获取数据后的View组件返回,如ListView中每一行里的TextView、Gallery中的每个ImageView。
     2)、Adapter在Android应用程序中起着非常重要的作用,应用也非常广泛,它可看作是数据源和UI组件之间的桥梁,其中Adapter、数据和UI之间的关系,可以用下图表示:
t2A9A
3)、常用子类
Adapter常用子类
2、BaseAdapter简介
BaseAdapter是实现了ListAdapter和SpinnerAdapter两个接口,当然它也可以直接给ListView和Spinner等UI组件直接提供数据。
相关类结构如下图所示:
tCCA2
3、示例
示例一:Gallery显示一组图片
运行结果:

说明:上面一行图片是Gallery画廊,每次点击一个Gallery图片时,会同时在下面以大图形式显示出来该图片
布局文件:
复制代码
  
  
<? 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" > < TextView android:layout_width ="fill_parent" android:layout_height ="wrap_content" android:text ="@string/hello" /> < Gallery android:id ="@+id/gallery1" android:layout_width ="match_parent" android:spacing ="5px" android:layout_height ="wrap_content" ></ Gallery > < ImageView android:id ="@+id/iv" android:layout_gravity ="center_vertical" android:layout_marginTop ="20px" android:layout_width ="320px" android:layout_height ="320px" ></ ImageView > </ LinearLayout >
复制代码
MainActivity类:
复制代码
   
   
package com.magc.adapter; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.Gallery; import android.widget.ImageView; import android.widget.AdapterView.OnItemClickListener; public class MainActivity extends Activity { private Gallery gallery; private ImageView imgview; private int [] imgs = {R.drawable.a6,R.drawable.a1,R.drawable.a2,R.drawable.a3,R.drawable.a4,R.drawable.a5}; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); imgview = (ImageView)findViewById(R.id.iv); gallery = (Gallery)findViewById(R.id.gallery1); MyImgAdapter adapter = new MyImgAdapter( this ); gallery.setAdapter(adapter); gallery.setOnItemClickListener( new OnItemClickListener() { // 用户点击图片时,将该图片的ResourceID设到下面的ImageView中去, @Override public void onItemClick(AdapterView <?> arg0, View view, int position, long arg3) { imgview.setImageResource(imgs[position]); } }); } class MyImgAdapter extends BaseAdapter {      //自定义图片Adapter以内部类形式存在于MainActivity中,方便访问MainActivity中的各个变量,特别是imgs数组 private Context context; // 用于接收传递过来的Context对象 public MyImgAdapter(Context context) { super (); this .context = context; } /* (non-Javadoc) * @see android.widget.Adapter#getCount() */ @Override public int getCount() { return imgs.length; } /* (non-Javadoc) * @see android.widget.Adapter#getItem(int) */ @Override public Object getItem( int position) { return position; } /* (non-Javadoc) * @see android.widget.Adapter#getItemId(int) */ @Override public long getItemId( int position) { return position; } /* (non-Javadoc) * @see android.widget.Adapter#getView(int, android.view.View, android.view.ViewGroup) */ @Override public View getView( int position, View convertView, ViewGroup parent) { // 针对每一个数据(即每一个图片ID)创建一个ImageView实例, ImageView iv = new ImageView(context); // 针对外面传递过来的Context变量, iv.setImageResource(imgs[position]); Log.i( " magc " , String.valueOf(imgs[position])); iv.setLayoutParams( new Gallery.LayoutParams( 80 , 80 )); // 设置Gallery中每一个图片的大小为80*80。 iv.setScaleType(ImageView.ScaleType.FIT_XY); return iv; } }

}

Android界面中有时候需要显示稍微复杂的界面时,就需要我们自定义一个adapter,而此adapter就要继承BaseAdapter,重新其中的方法.
        Android中Adapter类其实就是把数据源绑定到指定的View上,然后再返回该View,而返回来的这个View就是ListView中的某一行item。这里返回来的View正是由我们的Adapter中的getView方法返回的。这样就会容易理解数据是怎样一条一条显示在ListView中的。
       在完成这篇文章中的例子之后,我思考了很长时间,关于重写一个adapter,这其中真的有很多讲究,遇到一处不懂的都会查阅很长时间,但也不能保证我已经把其中的重中之重已经找完了,只要你想延伸都可以发现其中的无限.....
       问题1:为什么我们要重写一个adapter?
       问题2:android中这么多adapter,什么情况下该重写哪一个adapter(ArrayAdapter/SimpleAdapter/SimpleCursorAdapter...)?
       问题3:我们重写的adapter为什么是一个内部类,是否建议把adapter做成一个内部类?
       问题4:理解应用中的数据源一般都会用一个Map类型的List,有何意途?
       问题5:通过adapter是怎样做到把一条一条的item放到ListView中的?
       问题6:理解重写adapter时,重写的几个方法(getCount()/getItem()/getItemId()/getView())?
       问题7:理解ListView使用adapter的机制
      
 
案例概览步骤:
1)创建2个layout,一个是界面顶部的显示,一个是ListView中的内容
   1.1)ListView_header.xml( 注:自我感觉界面中的控件的位置摆放与layout_width/layout_height/orientation/gravity/layout_gravity的属性设置关系非常大,一定要注意每个属性的用法)
 
<?xml version="1.0" encoding="UTF-8"?> <!-- 第一个LinearLayout,充当父容器,要包揽两行,因此设置其 android:orientation为    纵向--> <LinearLayout xmlns:android=" http://schemas.android.com/apk/res/android"      android:layout_width="fill_parent"     android:layout_height="fill_parent"      android:orientation="vertical">           <!-- 第二个LinearLayout      android:gravity 表示该LinearLayout中的类容相对于该LinearLayout 水平居中     android:layout_gravity 表示的是该LinearLayout相对于它上面的父容器(这里是第一个LinearLayout)水平居中     -->     <LinearLayout android:id="@+id/toprow"          android:layout_width="fill_parent"         android:layout_height="wrap_content"          android:orientation="horizontal"         android: gravity="center_horizontal">               <TextView android:id="@+id/quna"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:textColor="#ff9966ff"          android:textSize="25dp"          android:text="@string/places"/>            <!-- 用一个图片按钮 -->      <ImageButton android:id="@+id/goBtn"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:src="@drawable/quna"/>     </LinearLayout>          <TextView android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:text="@string/placesList"          android:textColor="#ff9966ff"          android:textSize="20dp"/>          <ListView android:id="@+id/list_places"         android:layout_width="fill_parent"         android:layout_height="wrap_content"/>      </LinearLayout>
 
1.2)listview_item.xml
 
<?xml version="1.0" encoding="UTF-8"?> <LinearLayout xmlns:android=" http://schemas.android.com/apk/res/android"      android:orientation="horizontal"  //此属性的设置非常重要,决定里面的控件横向摆放     android:layout_width="fill_parent"     android:layout_height="fill_parent">      <!-- android:layout_margin设置图片与旁边文章的距离 -->     <ImageView android:id="@+id/image"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_margin="5dp"/>     <LinearLayout  android:orientation="vertical"  //也很重要决定里面的两个textview竖着放         android:layout_width="wrap_content"         android:layout_height="wrap_content">         <TextView android:id="@+id/title"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:textColor="#ff3399ff"             android:textSize="20dp"/>         <TextView android:id="@+id/info"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:textColor="#ff3399ff"             android:textSize="13dp"/>     </LinearLayout>      <!-- 注意此处button的属性android:layout_gravity的用法 ,这里设置了都没效果     这里不是很理解为什么要在加一个LinearLayout,里面的button才可以居右??     而且LinearLayout的width必须为fill_parent才可以     -->     <LinearLayout  android:layout_width="fill_parent"         android:layout_height="wrap_content"         >     <Button android:id="@+id/viewBtn"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:text="@string/btn_select"          android:layout_gravity="bottom|right"/>          </LinearLayout> </LinearLayout>
 
2)、写java class,开发activity(建一个class继承Activity,添加click事件的时候还要实现onClickListener接口)
       2.1)  重写onCreate方法----------------------------------------------->
 
         private ListView listView;          private ImageButton goBtn;          private List<Map<String, Object>> testData;
      protected void onCreate(Bundle savedInstanceState) {                       super.onCreate(savedInstanceState);                       setContentView(R.layout. listview_header); // 这里运行该项目的时候,让其显示listview_header.xml界面(layout),然后再将listview要显示的item项加到里面                        //获得 listview_header.xml中的ListView控件
                      listView = (ListView) findViewById(R.id.list_places);                        //获得imageButton给它添加click事件                       goBtn = (ImageButton) findViewById(R.id.goBtn);                       goBtn.setOnClickListener(new OnClickListener() {                                   //这里只是做出了简单的弹出框                                 @Override                                  public void onClick(View v) {                                             new AlertDialog.Builder(BaseAdapterTest2.this).setTitle("想去的国家:")
                                                                                  .setMessage("i want to go France")
                                                                                  .setPositiveButton("确定", null).sho();                                   }                                  });                          //数据源                      testData =  buildData();                      MyAdapter adapter = new MyAdapter(this);
                      //通过setAdapter而把数据绑定到ListView中                      listView.setAdapter(adapter);             }
 
      2.2)创建数据,注意这里为什么要是Map类型的List集合
            private List<Map<String, Object>> buildData(){                         List<Map<String, Object>> data = new ArrayList<Map<String,Object>>();                         Map<String, Object> map = new HashMap<String, Object>();
                        map.put("title", "中国");                        map.put("info", "China");                        map.put("image", R.drawable.p6);                        data.add(map);                           map = new HashMap<String, Object>();                        map.put("title", "英国");                        map.put("info", "England");                        map.put("image", R.drawable.p7);                        data.add(map);                           map = new HashMap<String, Object>();                        map.put("title", "美国");                        map.put("info", "America");                        map.put("image", R.drawable.p9);                            map = new HashMap<String, Object>();                         map.put("title", "荷兰");                         map.put("info", "Dutch");                         map.put("image", R.drawable.p9);                        data.add(map);                           map = new HashMap<String, Object>();                        map.put("title", "新西兰");                        map.put("info", "New Zealand");                        map.put("image", R.drawable.p7);                        data.add(map);
 
                       data.add(map);                           return data;
           }
 
         2.3)写自定义adapter( 它是一个内部类,继承自BaseAdapter,并不确定是否自定义的adapter一般都是继承它),尤其注意其中的几个方法
           public class MyAdapter extends BaseAdapter{
                        private LayoutInflater inflater ;//这个一定要懂它的用法及作用                           //构造函数:要理解(这里构造方法的意义非常强大,你也可以传一个数据集合的参数,可以根据需要来传参数)                       public MyAdapter(Context context){                                  this.inflater = LayoutInflater.from(context);                       }                          //这里的getCount方法是程序在加载显示到ui上时就要先读取的,这里获得的值决定了listview显示多少行                      @Override                      public int getCount() {                                 //在实际应用中,此处的返回值是由从数据库中查询出来的数据的总条数                                return testData.size();                      }
                    
                      //根据ListView所在位置返回View
                    @Override                      public Object getItem(int position) {                                 // TODO Auto-generated method stub                                return this.testData.get(position);                      }
 
                       //根据ListView位置得到数据源集合中的Id
                     @Override                      public long getItemId(int position) {                                // TODO Auto-generated method stub                                return position;                      }
                     //重写adapter最重要的就是重写此方法,此方法也是决定listview界面的样式的                     @Override                     public View getView(int position, View convertView, ViewGroup parent) {                                      //有很多例子中都用到这个holder,理解下??                                ViewHolder holder = null;
                                 //思考这里为何要判断convertView是否为空  ??                                 if(convertView == null){                                          holder = new ViewHolder();                                                //把vlist layout转换成View【LayoutInflater的作用】                                          convertView = inflater.inflate(R.layout.vlist, null);                                           //通过上面layout得到的view来获取里面的具体控件                                          holder.image = (ImageView) convertView.findViewById(R.id.image);                                          holder.title = (TextView) convertView.findViewById(R.id.title);                                          holder.info = (TextView) convertView.findViewById(R.id.info);                                          holder.viewBtn = (Button) convertView.findViewById(R.id.viewBtn);                                           //不懂这里setTag什么意思??                                          convertView.setTag(holder);                                }                                else{                                           holder = (ViewHolder) convertView.getTag();                                 }                              //这里testData.get(position).get("title1")),其实就是从list集合(testData)中取出对应索引的map,然后再根据键值对取值                             holder.image.setBackgroundResource((Integer) testData.get(position).get("image1"));                             holder.title.setText((String) testData.get(position).get("title1"));                             holder.info.setText((String) testData.get(position).get("info1"));                              //为listview上的button添加click监听                             holder.viewBtn.setOnClickListener(new View.OnClickListener() {                                        @Override                                        public void onClick(View v) {                                                    .....                                        }                             });                   return convertView;   }     }
 
        到此,整个案例的关键部分已经全部出来了,做的过程中有很多地方没有想通也都做有注释,做完以后,多揣摩了几遍才将就理解,嘿嘿
重点提出一个疑问:不能确定是否在onCreate方法中的 new Adapter,在里面表面上看是只调用了一次而进入自定义Adapter中调用( 其实也没有直接调用,自己想的它可能有一个自己的内部机制,每new完一个Adapter就直接调用getCount/getView方法吗)它里面的方法 ,调用一次就会绘制一个ListView中的 一个item项,那么有很多条item的时候,它是否要那样循环调用很多次呢??
        getView方法中的参数,convertview那块。在初始化的时候,每显示一行item项都会调用一次getView方法但每次调用的时候convertview为null(因为还没有旧的view);如果屏幕移动了之后,并且导致某些item项跑到屏幕外面,此时如果还有新的item需要产生,则这些item显示时调用的getView方法中的convertview就不为null,而是那些移出到屏幕之外的view,我们所要做的就是将需要显示的item项填充到移除屏幕外的(旧的)view中去,注意【convertview为null的不仅仅是初始化显示的那些item,还有一些是已经开始移入屏幕但还没有view被回收的那些item】。
  
运行结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值