Android自定義介面卡---實現簡單檔案管理器
一、介面卡Adapter
現實生活中的介面卡就是一種“轉化器”,將兩個不相容的事物做一個連線。Android在檢視顯示和後臺資料上使用介面卡,顧名思義,就是把一些資料給變得適當,適合以便於在View上顯示。可以看作是介面資料繫結的一種理解。它所操縱的資料一般都是一些比較複雜的資料,如陣列,連結串列,資料庫,集合等。
介面卡在檢視與資料之間扮演了一個橋樑的作用,它將資料中的每一項資料轉化為介面卡檢視可以使用的每一個檢視項。
介面卡類圖:
該圖是關於介面卡Adapter的類圖,可以看到BaseAdapter抽象類實現了ListAdapter和SpinnerAdapter
在開發中,我們經常使用到ListView這個控制元件。Android的API也提供了許多建立ListView介面卡的多種方式。例如ArrayAdapter、SimpleAdapter和SimpleCursorAdapter等。但你是否發現,如果採用這些系統自帶的介面卡,對於事件的響應只能侷限在一個行單位。假設一行裡面有一個按鈕和一個圖片控制元件,它們之間的響應操作是不一樣的。若採用系統自帶的介面卡,就不能精確到每個控制元件的響應事件。這時,我們一般採取自定義介面卡來實現這個比較精確地請求。
所以我們在實際開發中如果需要實現各種各樣的介面卡樣式,則需要自定義適合自己的介面卡,也就是說需要繼承BaseAdapter。而如果獲取的json資料是千變萬化的,可以使用android程式碼進行方便的呼叫相應的資料,就可以達到圖文混排等好看的樣式效果,具體的使用方法如下。
二、BaseAdapter類中的重要方法
BaseAdapter類是一個抽象類,實現了ListAdapter和SpinnerAdapter這兩個介面,在我們自定義的介面卡中,就是要繼承BaseAdapter這個類。類中的重要方法如下:
public int getCount() //得到資料的行數
public Object getItem(intposition) //
public long getItemId(int position) //的到某一條記錄的ID
publicView getView(int position,View convertView, ViewGroup parent)
//相比於其它幾個方法這個方法是最重要的,它顯式的定義了介面卡將要以什麼樣的方式去顯示我們所填充的資料,在自定義的介面卡裡面我們通常會給它寫個佈局檔案。第一個引數position指定位置,即要獲得哪一個資料項的View,第二個引數convertView可複用的檢視項,第三個引數指定父元素檢視組。
三、自定義介面卡
通過一個完整例項,逐步探討自定義介面卡的實現過程。實現的功能如下圖,類似於一個檔案管理器,一頁螢幕上顯示了七八個檔案項:
例項分析
(1)主活動的佈局檔案裡其實就是一個ListView,ListView裡面每一行都是一個“自定義控制元件集”列表項。這個“自定義控制元件集”列表項其實就是一個模板,模板顯示樣式見下圖,這個模板定義了將要以什麼樣的方式去顯示我們所填充的資料。它由多個控制元件構成:最左邊是一個ImageView用於顯示檔案圖示,旁邊有兩個TextView用於顯示檔案資訊,最右邊是一個ImageButton用於實現對檔案操作事件處理。介面卡將“檢視”和“資料”做關聯,將SD卡外部儲存讀取到的一個個檔案[資料],按照此佈局檔案指定的樣式顯示出來。
注意:一個檔案[資料]對應一個檢視項[就是這個模板],讓所有檔案都按此樣式顯示;檔案可能有千萬條,但一頁螢幕只能顯示七八個檢視項;在 ListView 上下滾動時,可以重複使用消失的列表項裝載新的資料出現的底部或頂部,所以這裡可做效能優化,後面細講。
該模板對應的佈局檔案需要自己新建,命名為file_item.xml
程式碼如下:
<?xml version="1.0"
encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:descendantFocusability="blocksDescendants">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:id="@+id/imageView_icon"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:src="@drawable/ic_folder"/>
<TextViewandroid:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="檔名稱"
android:id="@+id/textView_name"
android:layout_alignTop="@+id/imageView_icon"
android:layout_toRightOf="@+id/imageView_icon"
android:layout_toEndOf="@+id/imageView_icon"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:textSize="18sp"/>
<TextViewandroid:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="檔案型別及大小"
android:id="@+id/textView_info"
android:layout_alignBottom="@+id/imageView_icon"
android:layout_alignLeft="@+id/textView_name"
android:layout_alignStart="@+id/textView_name"
android:textSize="12sp"/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageButton_action"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:src="@drawable/ic_more_vert_black_24dp"
style="@android:style/Widget.DeviceDefault.Button.Borderless.Small"
/>
</RelativeLayout>
(2)資料都是從手機SD卡外部儲存讀取到的,使用自定義的FileAdapter(extends BaseAdapter)檔案介面卡將“檢視”和“資料”做關聯。從手機SD卡外部儲存讀取資料,需要許可權設定,在清單檔案中加入2行程式碼(加在<application 標籤上面):
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
自定義介面卡
1.繼承BaseAdapter類
新建一個Java類FileAdapter程序,繼承BaseAdapter類,重寫如下四個方法及構造方法。
2.所有方法的具體實現
3.建立檢視項
重寫的4個方法中getView()最重要,也最複雜。要讓“資料”按照我們自己定義的“模板”顯示,就需要載入我們定義的佈局檔案(file_item.xml)。
在FileAdapter類中定義一個LayoutInflater inflater佈局載入物件,用於載入和解析XML佈局檔案,並在FileAdapter的構造方法中對其初始化(具體程式碼實現上面有)。
convertView = inflater.inflate(R.layout.file_item,parent,fause);這行使用佈局載入物件,載入我們定義的檢視模板file_item.xml,使資料按照模板指定樣式顯示。getView()方法實現如下:
4.存在的問題
ListView 中的資料可能有成千上萬條,每條的資料的顯示都會呼叫 getView() 方法獲得一個檢視項:使用 LayoutInflater 例項化 XML 佈局檔案[檢視項模板]及通過findViewById 查詢獲得控制元件引用,這兩個操作的效能開銷很大;而當檢視項[就是我們定義的檢視模板]從底部或頂部消失後(沒有重用),又需要不停呼叫 GC 回收檢視項。
四、解決方案----使用ViewHolder 模式
1.再看convertView引數
ListView 中的資料可能有成千上萬條,但顯示在螢幕上的條目(列表項)是非常有限的,一般也就七八個;在ListView 上下滾動時,可以重複使用消失的列表項裝載新的資料出現的底部或頂部;getView() 方法中的 convertView 引數就是可重複使用的列表項(file_item.xml 檔案的例項)。
2.第一步:利用convertView 引數
convertView 引數為null時才載入新的檢視項,按檢視項模板指定樣式顯示。不為null時,說明有可複用的檢視項,上下滾動時,可以重複使用消失的列表項裝載新的資料。
3.第二步:使用---檢視的 tag
View 類有兩個方法:
方法 |
描述 |
public void setTag(Object tag) |
給檢視繫結一個物件(資料、檢視的結構) |
public Object getTag() |
獲得與檢視關聯的物件(資料、檢視的結構) |
4.列表項模版
就是最前面新建的file_item.xml檔案。
5.ViewHolder 類
因為file_item.xml佈局檔案[檢視項模板]指定了每一個數據[檔案]要顯示的樣式,convertView 引數為null時,就載入該佈局檔案,且通過findViewById()方法獲得該佈局檔案中宣告控制元件的引用,並在事件處理中,改變這些控制元件的屬性。但前面說過,該佈局檔案[檢視項模板]是一個“自定義控制元件集”,它包含多個控制元件,所以這裡使用ViewHolder 類將他們封裝起來,統一處理。
6.在getView()方法中使用 ViewHolder
7.在 ViewHolder 中載入資料
此處演示的程式碼,是使用通過ViewHolder類名直接訪問欄位屬性,然後通過findViewById()方法獲得佈局檔案中宣告控制元件的引用,其實下面的方法更通用一些。
/**
* 建立檢視項
*
* @param i
位置
* @param convertView
可複用的檢視,可能 null (需要新建)
* @param viewGroup 介面卡檢視
* @return
*/
@Override
public View getView(
int i,
View convertView,
ViewGroup viewGroup) {
ViewHolder holder;
if (convertView == null) {
// 沒有可複用,需要建立
// 開銷很大 載入檔案、XML
解析 控制元件和佈局的
convertView = layoutInflater.inflate(R.layout.file_item,
null);
// 每個檢視項需要一個 viewHolder
// 構造ViewHolder把View convertView傳給它
holder = new ViewHolder(convertView);
……………………………..
return convertView;
}
/**
* ViewHolder 模式
*/
static class ViewHolder {
ImageView icon;
TextView title;
TextView info;
ImageButton action;
/**
* 構造方法
* 得到View v
通過findViewById獲得佈局引用
* @param v
*/
public ViewHolder(View v) {
icon = (ImageView) v.findViewById(R.id.imageView_icon);
title = (TextView) v.findViewById(R.id.textView_name);
info = (TextView) v.findViewById(R.id.textView_info);
action = (ImageButton) v.findViewById(R.id.imageButton_action);
}
……………………………….
}
8.業務功能實現---列表項中的監聽器
定義監聽器
建立監聽器
設定監聽器(或重置資料)
點選事件(彈出選單)
定義彈出選單
PopupMenu 選單res/menu/popup.xml
文章推薦---介面卡檢視與介面卡AdapterView& Adapter:
http://blog.csdn.net/ljheee/article/details/52302591