Android中Adapter之BaseAdapter使用


 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】。
  
運行結果:
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM