Android適配器解析
認識Adapter
什麼是Adapter?
Adapter對象充當AdapterView與該視圖的底層數據之間的橋樑。適配器提供對數據項的訪問。適配器還負責爲數據集中的每個項目進行查看。
Data(底層數據)、Adapter(適配器)、View(視圖)三者的關係:
Android中的Adapter:
圖中列出了Android中與Adapter有關的所有接口、類的完整層級圖。在我們使用過程中可以根據自己的需求實現接口或者繼承類進行一定的擴展。
- BaseAdapter是一個抽象類,繼承它需要實現較多的方法,所以也就具有較高的靈活性;
- ArrayAdapter支持泛型操作,最爲簡單,只能展示一行字。
- SimpleAdapter有最好的擴充性,可以自定義出各種效果。
- SimpleCursorAdapter可以適用於簡單的純文字型ListView,它需要Cursor的字段和UI的id對應起來。如需要實現更復雜的UI也可以重寫其他方法。可以認爲是SimpleAdapter對數據庫的簡單結合,可以方便地把數據庫的內容以列表的形式展示出來。
BaseAdapter
BaseAdapter就Android應用程序中經常用到的基礎數據適配器,它的主要用途是將一組數據傳到像ListView、Spinner、Gallery及GridView等UI顯示組件,它是繼承自接口類Adapter。可以實現複雜的列表佈局,由於BaseAdapter是一個抽象類,使用該類需要自己寫一個適配器繼承該類,正是由於繼承了該類,需要我們重寫一些方法,讓我們可以在代碼裏控制列表的樣式,更加靈活。
BaseAdapter中的方法:
自定義Adapter子類,就需要實現上面幾個方法,其中最重要的是getView()方法,它是將獲取數據後的View組件返回,如ListView中每一行裏的TextView、Gallery中的每個ImageView。
構造函數
如果自定義的BaseAdapter定爲外部類,需要構造方法來獲取實例,構造方法一般傳入的參數有:
- Context對象
- 數據
獲取未綁定在當前activity中佈局文件中的控件
Inflater對象(用於獲取itemView佈局文件的控件)
LayoutInflater mInflater = LayoutInflater.from(context);
View convertView = mInflater.inflate(R.layout.vlist2, null);
holder.img = (ImageView)convertView.findViewById(R.id.img);
實例
new MyBaseAdapter(this,mDatas);
public class MyBaseAdapter extends BaseAdapter {
private static final String TAG = "MyBaseAdapter";
private Context mContext;
private List<BaseItemInfo> infos;
//利用構造方法實例化MyBaseAdapter對象,傳入Context對象,數據
public MyBaseAdapter(Context context, List<BaseItemInfo> datas) {
mContext=context;
infos = datas;
}
@Override
public int getCount() {
return infos.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
ViewHolder holder;
if (convertView != null && convertView instanceof LinearLayout) {
view = convertView;
holder = (ViewHolder) view.getTag();
Log.d(TAG, "getView: 複用緩存 " + position);
} else {
view = View.inflate(mContext, R.layout.item_base, null);
holder = new ViewHolder();
holder.iv_icon = (ImageView) view.findViewById(R.id.iv_item);
holder.tv_title = (TextView) view.findViewById(R.id.tv_title);
holder.tv_content = (TextView) view.findViewById(R.id.tv_content);
view.setTag(holder);
Log.d(TAG, "getView: 創建新的View對象 " + position);
}
holder.iv_icon.setImageDrawable(infos.get(position).getIcon());
holder.tv_title.setText(infos.get(position).getTitle());
holder.tv_content.setText(infos.get(position).getContext());
return view;
}
class ViewHolder {
ImageView iv_icon;
TextView tv_title;
TextView tv_content;
}
}
自定義BaseAdapter的優化
public class MyBaseAdapter extends BaseAdapter{
private LayoutInflater mInflater;
public MyAdapter(Context context){
this.mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mData.size();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder=new ViewHolder();
convertView = mInflater.inflate(R.layout.vlist2, null);
holder.img = (ImageView)convertView.findViewById(R.id.img);
holder.title = (TextView)convertView.findViewById(R.id.title);
holder.info = (TextView)convertView.findViewById(R.id.info);
holder.viewBtn = (Button)convertView.findViewById(R.id.view_btn);
convertView.setTag(holder);
}else {
holder = (ViewHolder)convertView.getTag();
}
holder.img.setBackgroundResource((Integer)mData.get(position).get("img"));
holder.title.setText((String)mData.get(position).get("title"));
holder.info.setText((String)mData.get(position).get("info"));
//給每一個列表後面的按鈕添加響應事件
holder.viewBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showInfo();
}
});
return convertView;
}
------------
public final class ViewHolder{
public ImageView img;
public TextView title;
public TextView info;
public Button viewBtn;
}
ViewHolder這個類的名字是自己定義的, 其作用是在getView() 裏面會有用到.之所以會有這個類的存在, 是由於如列表中, 每一個item 其圖層都是一樣的, 那麼每次getview 的時候就需要重複的去查找, 因此可以通過自己定義一個 類如ViewHolder 來保存下item 圖層的每個View 對象, 方便複用.提升程序的效率。
ArrayAdapter
使用簡單,可在activity中使用ArrayAdapter構造方法直接實例化
傳入的參數爲:
- context對象
- itemView佈局文件(只能有一個定義了id的控件)
- 要顯示數據(具體將被映射的字符串,圖片,或者基本組件)
ArrayAdapter的構造方法:
實例
new ArrayAdapter<>(this, android.R.layout.simple_expandable_list_item_1,datas);
//android.R.layout.simple_expandable_list_item_1的佈局文件,只能有一個定義了id的TextView
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:paddingStart="?android:attr/expandableListPreferredItemPaddingLeft"
android:textAppearance="?android:attr/textAppearanceListItem"
android:gravity="center_vertical"
android:textAlignment="viewStart"/>
SimpleAdapter
SimpleAdapter顧名思義就是Simple,只有一個構造方法。可以顯示比較複雜的列表,包括每行顯示圖片、文字等,但不能對列表進行後期加工(在Java代碼中加工),也是隻是單純的負責顯示(當然可以設計複雜點的佈局來顯示覆雜列表),例如,每行顯示不同背景等。
傳入的參數爲:
- context對象
- 傳入的數據
- itemView佈局文件
- 數據對應的key值
- itemView佈局中控件的Id(按順序與key值一一對應)
SimpleAdapter的構造方法
/**
* Constructor
*
* @param context The context where the View associated with this SimpleAdapter is running
* @param data A List of Maps. Each entry in the List corresponds to one row in the list. The
* Maps contain the data for each row, and should include all the entries specified in
* "from"
* @param resource Resource identifier of a view layout that defines the views for this list
* item. The layout file should include at least those named views defined in "to"
* @param from A list of column names that will be added to the Map associated with each
* item.
* @param to The views that should display column in the "from" parameter. These should all be
* TextViews. The first N views in this list are given the values of the first N columns
*/
public MyAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) {
super(context, data, resource, from, to);
}
實例
new SimpleAdapter(this,getData(),R.layout.item_simple,new String[]{"title","info","img"},
new int[]{R.id.tv_simple_title,R.id.tv_info,R.id.iv_img});
private List<Map<String, Object>> getData() {
List<Map<String, Object>> list = new ArrayList<>();
Map<String, Object> map = new HashMap<>();
map.put("title", "title1");
map.put("info", "info1");
map.put("img", R.mipmap.ic_launcher);
list.add(map);
map = new HashMap<>();
map.put("title", "title2");
map.put("info", "info2");
map.put("img", R.mipmap.ic_launcher);
list.add(map);
map = new HashMap<>();
map.put("title", "title3");
map.put("info", "info3");
map.put("img", R.mipmap.ic_launcher_round);
list.add(map);
return list;
}
SimpleCursorAdapter
SimpleCursorAdapter可以適用於簡單的純文字型ListView,它需要Cursor的字段和UI的id對應起來。如需要實現更復雜的UI也可以重寫其他方法。可以認爲是SimpleAdapter對數據庫的簡單結合,可以方便地把數據庫的內容以列表的形式展示出來。
傳入的參數:
- context對象
- itemView的佈局文件
- Cursor對象
- 傳入數據的key值
- itemView佈局中控件的Id(按順序與key值一一對應)
SimpleCursorAdapter的構造方法
實例
//獲得一個指向系統通訊錄數據庫的Cursor對象獲得數據來源
Cursor cur = getContentResolver().query(Contacts.People.CONTENT_URI, null, null, null, null);
startManagingCursor(cur);
new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cur,
new String[] {Contacts.People.NAME}, new int[] {android.R.id.text1});