Android中的各種Adapter

1.概念

 

        Adapter是連接後端數據和前端顯示的適配器接口,是數據和UI(View)之間一個重要的紐帶。在常見的View(ListView,GridView)等地方都需要用到Adapter。如下圖直觀的表達瞭Data、Adapter、View三者的關系:

 

 

Android中所有的Adapter一覽:

 

 

        由圖可以看到在Android中與Adapter有關的所有接口、類的完整層級圖。在我們使用過程中可以根據自己的需求實現接口或者繼承類進行一定的擴展。比較常用的有 BaseAdapter,SimpleAdapter,ArrayAdapter,SimpleCursorAdapter等。

 

BaseAdapter是一個抽象類,繼承它需要實現較多的方法,所以也就具有較高的靈活性;

ArrayAdapter支持泛型操作,最為簡單,隻能展示一行字。

SimpleAdapter有最好的擴充性,可以自定義出各種效果。

SimpleCursorAdapter可以適用於簡單的純文字型ListView,它需要Cursor的字段和UI的id對應起來。如需要實現更復雜的UI也可以重寫其他方法。可以認為是SimpleAdapter對數據庫的簡單結合,可以方便地把數據庫的內容以列表的形式展示出來。

 

Adapter的繼承關系

有兩個adapter的體系,如下:

1、

 

 

 

 

 

 

2、

 

 

 

2.應用案例

 

1)ArrayAdapter

 

列表的顯示需要三個元素:

 

a.ListVeiw 用來展示列表的View。

 

b.適配器 用來把數據映射到ListView上的中介。

 

c.數據    具體的將被映射的字符串,圖片,或者基本組件。

 

案例一

 

 

public class ArrayAdapterActivity extends ListActivity {

     @Override

     public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         //列表項的數據

         String[] strs = {"1","2","3","4","5"};

         ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_expandable_list_item_1,strs);

         setListAdapter(adapter);

     }

 }

 

案例二

 

 

    public class MyListView extends Activity {

    

        private ListView listView;

        //private List<String> data = new ArrayList<String>();

        @Override

        public void onCreate(Bundle savedInstanceState){

            super.onCreate(savedInstanceState);

             

            listView = new ListView(this);

            listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1,getData()));

            setContentView(listView);

        }

         

        private List<String> getData(){

             

            List<String> data = new ArrayList<String>();

            data.add("測試數據1");

            data.add("測試數據2");

            data.add("測試數據3");

            data.add("測試數據4");

             

            return data;

        }

    }

 

        上面代碼使用瞭ArrayAdapter(Context context, int textViewResourceId, List<T> objects)來裝配數據,要裝配這些數據就需要一個連接ListView視圖對象和數組數據的適配器來兩者的適配工作,ArrayAdapter的構造需要三個參數,依次為this,佈局文件(註意這裡的佈局文件描述的是列表的每一行的佈局,android.R.layout.simple_list_item_1是系統定義好的佈局文件隻顯示一行文字,數據源(一個List集合)。同時用setAdapter()完成適配的最後工作。效果圖如下:

 

 

2)SimpleAdapter

  simpleAdapter的擴展性最好,可以定義各種各樣的佈局出來,可以放上ImageView(圖片),還可以放上Button(按鈕),CheckBox(復選框)等等。下面的代碼都直接繼承瞭ListActivity,ListActivity和普通的Activity沒有太大的差別,不同就是對顯示ListView做瞭許多優化,方面顯示而已。

 

案例一

 

simple.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"

>

<ImageView

android:id="@+id/img"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_margin="5dp"

/>

<TextView

android:id="@+id/title"

android:layout_width="wrap_content" 

android:layout_height="wrap_content" 

android:textColor="#ffffff"

android:textSize="20sp"

/>

</LinearLayout>

 

 

public class SimpleAdapterActivity extends ListActivity {

     @Override

     public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         

         SimpleAdapter adapter = new SimpleAdapter(this, getData(), R.layout.simple, new String[] { "title",  "img" }, new int[] { R.id.title, R.id.img });

         setListAdapter(adapter);

     }

     

     private List<Map<String, Object>> getData() {

         //map.put(參數名字,參數值)

         List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

         Map<String, Object> map = new HashMap<String, Object>();

         map.put("title", "摩托羅拉");

         map.put("img", R.drawable.icon);

         list.add(map);

         

         map = new HashMap<String, Object>();

         map.put("title", "諾基亞");

         map.put("img", R.drawable.icon);

         list.add(map);

         

         map = new HashMap<String, Object>();

         map.put("title", "三星");

         map.put("img", R.drawable.icon);

         list.add(map);

         return list;

         }  

     

 }

 

案例二

  下面的程序是實現一個帶有圖片的類表。首先需要定義好一個用來顯示每一個列內容的xml,vlist.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">   

        <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5px"/>

        <LinearLayout android:orientation="vertical"  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="#FFFFFFFF" android:textSize="22px" />

            <TextView android:id="@+id/info"  android:layout_width="wrap_content" android:layout_height="wrap_content"

                android:textColor="#FFFFFFFF" android:textSize="13px" />

        </LinearLayout>

     </LinearLayout>

 

 

public class MyListView3 extends ListActivity {

        // private List<String> data = new ArrayList<String>();

        @Override

        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

     

            SimpleAdapter adapter = new SimpleAdapter(this,getData(),R.layout.vlist,

                    new String[]{"title","info","img"},

                    new int[]{R.id.title,R.id.info,R.id.img});

            setListAdapter(adapter);

        }

     

        private List<Map<String, Object>> getData() {

            List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

     

            Map<String, Object> map = new HashMap<String, Object>();

            map.put("title", "G1");

            map.put("info", "google 1");

            map.put("img", R.drawable.i1);

            list.add(map);

     

            map = new HashMap<String, Object>();

            map.put("title", "G2");

            map.put("info", "google 2");

            map.put("img", R.drawable.i2);

            list.add(map);

     

            map = new HashMap<String, Object>();

            map.put("title", "G3");

            map.put("info", "google 3");

            map.put("img", R.drawable.i3);

            list.add(map);

             

            return list;

        }

    }

 

  使用simpleAdapter的數據用一般都是HashMap構成的List,list的每一節對應ListView的每一行。HashMap的每個鍵值數據映射到佈局文件中對應id的組件上。因為系統沒有對應的佈局文件可用,我們可以自己定義一個佈局vlist.xml。下面做適配,new一個SimpleAdapter參數一次是:this,佈局文件(vlist.xml),HashMap的 title 和 info,img。佈局文件的組件id,title,info,img。佈局文件的各組件分別映射到HashMap的各元素上,完成適配。

 

運行效果如下圖:

 

 

3)SimpleCursorAdapter

 

 

public class SimpleCursorAdapterActivity extends ListActivity {

     @Override

     public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         //獲得一個指向系統通訊錄數據庫的Cursor對象獲得數據來源

         Cursor cur = getContentResolver().query(People.CONTENT_URI, null, null, null, null);

         startManagingCursor(cur);

         //實例化列表適配器

         

         ListAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cur, new String[] {People.NAME}, new int[] {android.R.id.text1});

         setListAdapter(adapter);

     }

 }

 

一定要以數據庫作為數據源的時候,才能使用SimpleCursorAdapter,這裡特別需要註意的一點是:不要忘瞭在AndroidManifest.xml文件中加入權限

 

<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>

效果如下:

 

 

4)BaseAdapter

 

  有時候,列表不光會用來做顯示用,我們同樣可以在在上面添加按鈕。添加按鈕首先要寫一個有按鈕的xml文件,然後自然會想到用上面的方法定義一個適配器,然後將數據映射到佈局文件上。但是事實並非這樣,因為按鈕是無法映射的,即使你成功的用佈局文件顯示出瞭按鈕也無法添加按鈕的響應,這時就要研究一下ListView是如何現實的瞭,而且必須要重寫一個類繼承BaseAdapter。下面的示例將顯示一個按鈕和一個圖片,兩行字如果單擊按鈕將刪除此按鈕的所在行。並告訴你ListView究竟是如何工作的。

 

vlist2.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">

        <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5px"/>

        <LinearLayout android:orientation="vertical" 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="#FFFFFFFF" android:textSize="22px" />

           <TextView android:id="@+id/info" android:layout_width="wrap_content" android:layout_height="wrap_content"

                android:textColor="#FFFFFFFF" android:textSize="13px" />

       </LinearLayout>

 

       <Button android:id="@+id/view_btn" android:layout_width="wrap_content"  android:layout_height="wrap_content"

            android:text="@string/s_view_btn" android:layout_gravity="bottom|right" />

    </LinearLayout>

 

 

 

 

/**

002     * @author 

003     *

004     */

005    public class MyListView4 extends ListActivity {

006     

007     

008        private List<Map<String, Object>> mData;

009         

010        @Override

011        public void onCreate(Bundle savedInstanceState) {

012            super.onCreate(savedInstanceState);

013            mData = getData();

014            MyAdapter adapter = new MyAdapter(this);

015            setListAdapter(adapter);

016        }

017     

018        private List<Map<String, Object>> getData() {

019            List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

020     

021            Map<String, Object> map = new HashMap<String, Object>();

022            map.put("title", "G1");

023            map.put("info", "google 1");

024            map.put("img", R.drawable.i1);

025            list.add(map);

026     

027            map = new HashMap<String, Object>();

028            map.put("title", "G2");

029            map.put("info", "google 2");

030            map.put("img", R.drawable.i2);

031            list.add(map);

032     

033            map = new HashMap<String, Object>();

034            map.put("title", "G3");

035            map.put("info", "google 3");

036            map.put("img", R.drawable.i3);

037            list.add(map);

038             

039            return list;

040        }

041         

042        // ListView 中某項被選中後的邏輯

043        @Override

044        protected void onListItemClick(ListView l, View v, int position, long id) {

045             

046            Log.v("MyListView4-click", (String)mData.get(position).get("title"));

047        }

048         

049        /**

050         * listview中點擊按鍵彈出對話框

051         */

052        public void showInfo(){

053            new AlertDialog.Builder(this)

054            .setTitle("我的listview")

055            .setMessage("介紹…")

056            .setPositiveButton("確定", new DialogInterface.OnClickListener() {

057                @Override

058                public void onClick(DialogInterface dialog, int which) {

059                }

060            })

061            .show();

062             

063        }

064         

065         

066         

067        public final class ViewHolder{

068            public ImageView img;

069            public TextView title;

070            public TextView info;

071            public Button viewBtn;

072        }

073         

074         

075        public class MyAdapter extends BaseAdapter{

076     

077            private LayoutInflater mInflater;

078             

079             

080            public MyAdapter(Context context){

081                this.mInflater = LayoutInflater.from(context);

082            }

083            @Override

084            public int getCount() {

085                // TODO Auto-generated method stub

086                return mData.size();

087            }

088     

089            @Override

090            public Object getItem(int arg0) {

091                // TODO Auto-generated method stub

092                return null;

093            }

094     

095            @Override

096            public long getItemId(int arg0) {

097                // TODO Auto-generated method stub

098                return 0;

099            }

100     

101            @Override

102            public View getView(int position, View convertView, ViewGroup parent) {

103                 

104                ViewHolder holder = null;

105                if (convertView == null) {

106                     

107                    holder=new ViewHolder(); 

108                     

109                    convertView = mInflater.inflate(R.layout.vlist2, null);

110                    holder.img = (ImageView)convertView.findViewById(R.id.img);

111                    holder.title = (TextView)convertView.findViewById(R.id.title);

112                    holder.info = (TextView)convertView.findViewById(R.id.info);

113                    holder.viewBtn = (Button)convertView.findViewById(R.id.view_btn);

114                    convertView.setTag(holder);

115                     

116                }else {

117                     

118                    holder = (ViewHolder)convertView.getTag();

119                }

120                 

121                 

122                holder.img.setBackgroundResource((Integer)mData.get(position).get("img"));

123                holder.title.setText((String)mData.get(position).get("title"));

124                holder.info.setText((String)mData.get(position).get("info"));

125                 

126                holder.viewBtn.setOnClickListener(new View.OnClickListener() {

127                     

128                    @Override

129                    public void onClick(View v) {

130                        showInfo();                

131                    }

132                });

133                 

134                 

135                return convertView;

136            }

137             

138        }     

139    }

 

  下面將對上述代碼,做詳細的解釋,listView在開始繪制的時候,系統首先調用getCount()函數,根據他的返回值得到listView的長度(這也是為什麼在開始的第一張圖特別的標出列表長度),然後根據這個長度,調用getView()逐一繪制每一行。如果你的getCount()返回值是0的話,列表將不顯示同樣return 1,就隻顯示一行。

 

  系統顯示列表時,首先實例化一個適配器(這裡將實例化自定義的適配器)。當手動完成適配時,必須手動映射數據,這需要重寫getView()方法。系統在繪制列表的每一行的時候將調用此方法。getView()有三個參數,position表示將顯示的是第幾行,covertView是從佈局文件中inflate來的佈局。我們用LayoutInflater的方法將定義好的vlist2.xml文件提取成View實例用來顯示。然後將xml文件中的各個組件實例化(簡單的findViewById()方法)。這樣便可以將數據對應到各個組件上瞭。但是按鈕為瞭響應點擊事件,需要為它添加點擊監聽器,這樣就能捕獲點擊事件。至此一個自定義的listView就完成瞭,現在讓我們回過頭從新審視這個過程。系統要繪制ListView瞭,他首先獲得要繪制的這個列表的長度,然後開始繪制第一行,怎麼繪制呢?調用getView()函數。在這個函數裡面首先獲得一個View(實際上是一個ViewGroup),然後再實例並設置各個組件,顯示之。好瞭,繪制完這一行瞭。那再繪制下一行,直到繪完為止。在實際的運行過程中會發現listView的每一行沒有焦點瞭,這是因為Button搶奪瞭listView的焦點,隻要佈局文件中將Button設置為沒有焦點就OK瞭。

 

效果如下:

You May Also Like