android適配器模式設計與實現

 

 

適配器模式是一種重要的設計模式,在 android 中得到了廣泛的應用。適配器類似於現實世界裏面的插頭,通過適配器,我們可以將分屬於不同類的兩種不同類型的數據整合起來,而不必去根據某一需要增加或者修改類裏面的方法。

適配器又分爲單向適配器和雙向適配器,在 android 中前者使用的比較頻繁。比較常見的實現方式是:首先定義一個適配類,內部定義一個私有的需要適配的對象,該類提供一個構造函數,將該對象的一個實例作爲參數傳入,並在構造函數裏面進行初始化,再提供一個公有的方法,返回另外一個需要適配的類所需要的數據類型。這樣通過創建一個額外的類,專門負責數據類型的轉換,在不改動原有類的前提下實現了所需的功能。這種設計模式提供了更好的複用性和可擴展性,尤其在我們無法獲修改其中一個類或者類與類之間有比較多的不同類型的數據需要進行適配的時候顯得格外重要。

android 中常見的適配器類有: BaseAdapter SimpleAdapter ,首先我們看看 android 應用層是如何使用適配器的:

listview 爲例,我們設計一個簡單的適配,效果如下:

新建工程創建一個名爲 AdapterTest Activity ,在 main.xml 裏創建一個 listview 內容如下:

<? 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" >

    < ListView android:id = "@+id/min" android:layout_height = "wrap_content"

       android:layout_width = "wrap_content" />

</ LinearLayout >



新建一個名爲 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 = "wrap_content" >

    < ImageView android:layout_width = "wrap_content"

       android:layout_height = "wrap_content" android:id = "@+id/malone" />

    < TextView android:layout_width = "wrap_content"

       android:layout_height = "wrap_content" android:layout_gravity = "center_vertical"

       android:id = "@+id/malone1" />

</ LinearLayout >

 

AdapterTest 類中定義兩個靜態全局數組,裏面存放我們要顯示的內容

public static String[] mTitles = { "1" , "2" , "3" , "4" };

    public static int [] mIds = { R.drawable. icon , R.drawable. icon ,

           R.drawable. icon ,

           R.drawable. icon };

創建一個內部適配類 MinAdapter 繼承 BaseAdapter ,需要實現四個方法:

getCount getItem getItemId getView

我們先定義兩個私有的數組,並在構造函數中初始化:

private String[] titles ;

    private int [] ids ;

    public MinAdapter(String[] t, int [] idres) {

        titles = t;

        ids = idres;

    }

實現其中的 getCount getView 方法如下:

public int getCount () {

           // TODO Auto-generated method stub

           return titles . length ;

       }

該回調方法返回 listview 中顯示的行數

 

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

           // TODO Auto-generated method stub

           LayoutInflater l = LayoutInflater.from (AdapterTest. this );

           View v = l.inflate(R.layout. item , null );        

           ImageView itemImage = (ImageView)v.findViewById(R.id. malone );

           itemImage.setBackgroundResource( ids [position]);

    ((TextView)v.findViewById(R.id. malone1 )).setText( titles [position]);

           return v;

       }

getView 是一個比較重要的回調方法,它返回 position 位置上的 view

oncreate 中設置 adapter

setContentView(R.layout. main );

        ListView list = (ListView)findViewById(R.id. min );

        MinAdapter adapter = new MinAdapter( mTitles , mIds );

        list.setAdapter(adapter);

這樣就實現了一個簡單的 adapter

 

接下來我們對 BaseAdapter 的實現源碼進行分析:

BaseAdapter 是一個抽象類,實現了了 ListAdapter SpinnerAdapter 兩個接口,這兩個接口都繼承自 Adapter 接口。在這個接口中申明瞭我們需要實現的四個重要的方法。

接下來,我們進入 ListView 中查看 setAdapter 方法, ListView 就是通過調用這個方法與適配器聯繫起來的。該方法的入參數爲 ListAdapter 類型, ListAdapter 同樣繼承了 adapter ,也就是說,我們只能夠重寫 adapter 中的一些回調方法纔會起效。該方法中,首先會調用 getCount 方法來設置 listitem 的數目,進行一系列操作之後會調用 requestLayout 方法。由於 ListView 中並沒有定義該方法,它會調用它的父類 AbsListView 中的 requestLayout 方法,該方法調用後會回調其中的 onLayout 方法,該方法會調用 ListView 中的 layoutChildren 方法,該方法會調用 fillSpecific 方法, fillSpecific 方法,通過調用 makeAndAddView 方法得到需要 view ,然後將 view 放入 list 。查看 makeAndAddView 方法,它會調用父類的 obtainView 方法,而該方法會調用適配器中重寫的 getView 方法。

c hild = mAdapter.getView(position, scrapView, this);

  child = mAdapter.getView(position, null , this );

另外一個比較常見的設置 adapter 的控件是 Gallery Gallery 繼承自 AbsSpinner ,該類內部提供了 setAdapter 方法,該方法的實現與 listview 類似,

通過    mItemCount = mAdapter .getCount(); 得到 item 的數量

調用 requestLayout(); 方法回掉 onLayout 方法,調用 layout 方法,該方法中調用 makeAndAddView 方法,裏面可以找到我們熟悉的語句:

child = mAdapter .getView(position, null , this );

綜合 listview gallery ,發現它們有着類似的實現過程,在 setAdapter 裏面獲取 適配的 item 的個數,然後通知各自的控件構造這些 item ,構造的時候會通過適配器來獲取需要適配的 view

 

爲了更簡單地實現適配器的功能, android 提供了一個更爲方便的類 SimpleAdapter 進行適配。 SimpleAdapter 的構造函數如下:

public SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int [] to)

第一個參數是顯示 適配內容的 activity 的上下文,第二個參數看起來比較複雜,這是一個 List 類型的對象 data ,裏面存放着一個繼承自 Map 類型的任意對象,而這個 Map 中存放的第一個數據類型,即 key 值爲 String 類型,第二個爲任意類型,第三個參數是我們需要存放進去的 item layoutid ,第四個參數爲 map 中的 key 的集合,第五個參數爲 map 中第二個參數在 layout 中對應的各自的 id

上述例子進行簡單修改如下:

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

        for ( int i=0;i< mTitles . length ;i++) {

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

        m.put( "title" , mTitles [i]);

        m.put( "icon" , R.drawable. icon );

        list1.add(m);

        }

SimpleAdapter adapter = new SimpleAdapter( this ,list1,R.layout. item , new String[]{ "icon" , "title" },

             new int []{R.id. malone ,R.id. malone1 });  

        list.setAdapter(adapter);

即可實現同樣的效果。

接下來查看 SimpleAdapter 源碼:

其內部定義了一個私有的對象:

   private List<? extends Map<String, ?>> mData ;

並在構造的時候將其初始化。

SimpleAdapter 重寫了 getCount getView 方法,完成了之前相同的功能

事實上, SimpleAdapter 進行了一次簡單的 適配,將需要適配的數據統一轉化爲存有 map 數據的 list ,給開發者提供了統一的、方便的接口,讓開發者使用起來更爲方便。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章