1. 程式人生 > >某宅的Android學習筆記(5)——可通用的介面卡

某宅的Android學習筆記(5)——可通用的介面卡

 本文內容參考自慕課網

 ListView、GridView 是我們在 Android 中很常用的控制元件,通常來說,對於每一個控制元件都要寫對應的 ViewHolder 和 Adapter。但是當專案中的 ListView 很多時,寫 ViewHolder 就成了一件很枯燥的事。那麼有沒有辦法,寫一個通用的 ViewHolder 與 Adapter,將可複用的程式碼放在裡面,對於具體的控制元件,稍作修改就能適用呢?

傳統的 Adapter 寫法

 首先是佈局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.commonviewholder.MainActivity">

    <ListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>
</RelativeLayout>

 主佈局裡簡單地放了一個 ListView。
 item 佈局也很簡單,因為是做示例,並沒用太複雜的佈局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/item_listview_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:text="THIS IS TITLE"
        android:textColor="#444"
        android:textSize="30sp" />

    <TextView
        android:id="@+id/item_listview_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="This is content"
        android:textSize="25sp" />

    <TextView
        android:id="@+id/item_listview_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:padding="10dp"
        android:text="2016-9-17"
        android:textColor="#898989"
        android:textSize="16sp" />
</LinearLayout>

 接著要新增 Bean 類,來獲取 item 裡的各控制元件:

package com.example.commonviewholder.bean;

/**
 * Created by 某宅 on 2016/9/17.
 */
public class Bean {

    String itemTitle;
    String itemContent;
    String itemTime;

    public Bean(String itemTitle, String itemContent, String itemTime) {
        this.itemTitle = itemTitle;
        this.itemContent = itemContent;
        this.itemTime = itemTime;
    }

    public String getItemTitle() {
        return itemTitle;
    }

    public String getItemContent() {
        return itemContent;
    }

    public String getItemTime() {
        return itemTime;
    }
}

 自定義 Adapter, 這裡用繼承自 BaseAdapter 為例:

package com.example.commonviewholder.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.example.commonviewholder.R;
import com.example.commonviewholder.bean.Bean;

import java.util.List;

/**
 * Created by 某宅 on 2016/9/17.
 */
public class Adapter extends BaseAdapter {

    private LayoutInflater mInflater;
    private List<Bean> mDatas;

    public Adapter(Context context, List<Bean> datas) {
        mInflater = LayoutInflater.from(context);
        mDatas = datas;
    }

    @Override
    public int getCount() {
        return mDatas.size();
    }

    @Override
    public Object getItem(int i) {
        return mDatas.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder;
        if (view == null) {
            view = mInflater.inflate(R.layout.item_listview, viewGroup, false);
            viewHolder = new ViewHolder();
            viewHolder.mTitle = (TextView) view.findViewById(R.id.item_listview_title);
            viewHolder.mContent = (TextView) view.findViewById(R.id.item_listview_content);
            viewHolder.mTime = (TextView) view.findViewById(R.id.item_listview_time);
            view.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) view.getTag();
        }
        Bean bean = mDatas.get(i);
        viewHolder.mTitle.setText(bean.getItemTitle());
        viewHolder.mContent.setText(bean.getItemContent());
        viewHolder.mTime.setText(bean.getItemTime());
        return view;
    }

    private class ViewHolder {
        TextView mTitle;
        TextView mContent;
        TextView mTime;
    }
}

 最後在 MainActivity 中定義資料集,獲取並繫結 Adapter:

package com.example.commonviewholder;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;

import com.example.commonviewholder.adapter.Adapter;
import com.example.commonviewholder.bean.Bean;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private ListView mListView;
    private List<Bean> mDatas;
    private Bean mBean;
    private Adapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initData();
        initView();
    }

    /**
     * 初始化 View
     */
    private void initView() {
        mListView = (ListView) findViewById(R.id.listview);
        mListView.setAdapter(mAdapter);
    }

    /**
     * 初始化資料
     */
    private void initData() {
        mDatas = new ArrayList<>();
        //假裝自己有很多資料
        mBean = new Bean("TITLE1", "CONTENT", "2016-9-18");
        mDatas.add(mBean);
        mBean = new Bean("TITLE2", "CONTENT", "2016-9-18");
        mDatas.add(mBean);
        mBean = new Bean("TITLE3", "CONTENT", "2016-9-18");
        mDatas.add(mBean);
        mBean = new Bean("TITLE4", "CONTENT", "2016-9-18");
        mDatas.add(mBean);
        mBean = new Bean("TITLE5", "CONTENT", "2016-9-18");
        mDatas.add(mBean);
        mBean = new Bean("TITLE6", "CONTENT", "2016-9-18");
        mDatas.add(mBean);
        mBean = new Bean("TITLE7", "CONTENT", "2016-9-18");
        mDatas.add(mBean);
        mBean = new Bean("TITLE8", "CONTENT", "2016-9-18");
        mDatas.add(mBean);
        mBean = new Bean("TITLE9", "CONTENT", "2016-9-18");
        mDatas.add(mBean);
        mBean = new Bean("TITLE10", "CONTENT", "2016-9-18");
        mDatas.add(mBean);
        //獲得自定義 Adapter 的例項
        mAdapter = new Adapter(this, mDatas);
    }
}

 這樣一個簡單的 ListView 示例就完成了。

通用 ViewHolder 的編寫

 既然是通用的 ViewHolder,首先肯定是要將這個類抽出來。

package com.example.commonviewholder.adapter;

import android.content.Context;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by 某宅 on 2016/9/17.
 */
public class ViewHolder {

    private SparseArray<View> mViews;
    private View mConvertView;
    private int mPosition;

    private ViewHolder(Context context, ViewGroup parent, int layoutId, int position) {
        mViews = new SparseArray<>();
        mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false);
        mConvertView.setTag(this);
        mPosition = position;
    }

    /**
     * 獲取 ViewHolder 的例項
     * 如果 convertView 存在,直接從 convertView 獲取
     * 否則 new 一個
     *
     * @param context
     * @param convertView
     * @param parent
     * @param layoutId    佈局id
     * @param position
     * @return
     */
    public static ViewHolder get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {
        if (convertView == null) {
            return new ViewHolder(context, parent, layoutId, position);
        } else {
            ViewHolder viewHolder = (ViewHolder) convertView.getTag();
            viewHolder.mPosition = position;//防止 item 誤複用
            return (ViewHolder) convertView.getTag();
        }
    }

    /**
     * 通過 ViewId 獲取控制元件例項
     *
     * @param viewId
     * @param <T>
     * @return
     */
    public <T extends View> T getView(int viewId) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = mConvertView.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (T) view;
    }

    public View getConvertView() {
        return mConvertView;
    }
}

 接著 Adapter 就可以簡化為:

package com.example.commonviewholder.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.example.commonviewholder.R;
import com.example.commonviewholder.bean.Bean;

import java.util.List;

/**
 * Created by 某宅 on 2016/9/17.
 */
public class Adapter extends BaseAdapter {

    private LayoutInflater mInflater;
    private List<Bean> mDatas;
    private Context mContext;

    public Adapter(Context context, List<Bean> datas) {
        mInflater = LayoutInflater.from(context);
        mDatas = datas;
        mContext = context;
    }

    @Override
    public int getCount() {
        return mDatas.size();
    }

    @Override
    public Object getItem(int i) {
        return mDatas.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder = ViewHolder.get(mContext, view, viewGroup, R.layout.item_listview, i);
        Bean bean = mDatas.get(i);

        TextView itemTitle = viewHolder.getView(R.id.item_listview_title);
        TextView itemContent = viewHolder.getView(R.id.item_listview_content);
        TextView itemTime = viewHolder.getView(R.id.item_listview_time);

        itemTitle.setText(bean.getItemTitle());
        itemContent.setText(bean.getItemContent());
        itemTime.setText(bean.getItemTime());

        return viewHolder.getConvertView();
    }
}

 省略了之前繁瑣的獲取 convertView 與 ViewHolder 的方法,並且如果 ListView 越多,佈局越複雜,這種寫法的簡便性就會越明顯。

通用的 Adapter

 既然 ViewHolder 的重複程式碼可以加以封裝,那麼能不能對 Adapter 做同樣的事呢?答案當然是肯定的!新建一個 CommonAdapter:

package com.example.commonviewholder.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import java.util.List;

/**
 * Created by 某宅 on 2016/9/17.
 */
public abstract class CommonAdapter<T> extends BaseAdapter {

    protected List<T> mDatas;
    protected Context mContext;
    protected LayoutInflater inflater;

    public CommonAdapter(Context context, List<T> datas){
        mContext = context;
        mDatas = datas;
        inflater = LayoutInflater.from(mContext);
    }

    @Override
    public int getCount() {
        return mDatas.size();
    }

    @Override
    public Object getItem(int i) {
        return mDatas.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public abstract View getView(int i, View view, ViewGroup viewGroup);
}

 這樣我們的 Adapter 就可以繼承自 CommonAdapter, 將重複的程式碼全部清除掉:

package com.example.commonviewholder.adapter;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.example.commonviewholder.R;
import com.example.commonviewholder.bean.Bean;

import java.util.List;

/**
 * Created by 某宅 on 2016/9/17.
 */
public class Adapter extends CommonAdapter<Bean> {

    public Adapter(Context context, List<Bean> datas) {
        super(context, datas);
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder = ViewHolder.get(mContext, view, viewGroup, R.layout.item_listview, i);
        Bean bean = mDatas.get(i);

        TextView itemTitle = viewHolder.getView(R.id.item_listview_title);
        TextView itemContent = viewHolder.getView(R.id.item_listview_content);
        TextView itemTime = viewHolder.getView(R.id.item_listview_time);

        itemTitle.setText(bean.getItemTitle());
        itemContent.setText(bean.getItemContent());
        itemTime.setText(bean.getItemTime());

        return viewHolder.getConvertView();
    }
}

 上面的程式碼足夠簡單了嗎?不,因為在 getView() 裡我們還是要重複寫幾句程式碼。因此可以對 CommonAdapter 進一步簡化,不用抽象 getView() 方法,而是將重複的程式碼放在 getView() 裡,抽象一個接受必要引數的方法來提供給子類獲取控制元件例項:

package com.example.commonviewholder.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import com.example.commonviewholder.R;

import java.util.List;

/**
 * Created by 某宅 on 2016/9/17.
 */
public abstract class CommonAdapter<T> extends BaseAdapter {

    protected List<T> mDatas;
    protected Context mContext;
    protected LayoutInflater inflater;
    private int layoutId;

    public CommonAdapter(Context context, List<T> datas, int layoutId) {
        mContext = context;
        mDatas = datas;
        inflater = LayoutInflater.from(mContext);
        this.layoutId = layoutId;
    }

    @Override
    public int getCount() {
        return mDatas.size();
    }

    @Override
    public T getItem(int i) {
        return mDatas.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder = ViewHolder.get(mContext, view, viewGroup, layoutId, i);
        convert(viewHolder, getItem(i));
        return viewHolder.getConvertView();
    }

    public abstract void convert(ViewHolder viewHolder, T t);
}

 因為修改了 getView() 裡獲取 ViewHolder 的語句,因此佈局 id 改由構造方法獲取。

package com.example.commonviewholder.adapter;

import android.content.Context;
import android.widget.TextView;

import com.example.commonviewholder.R;
import com.example.commonviewholder.bean.Bean;

import java.util.List;

/**
 * Created by 某宅 on 2016/9/17.
 */
public class Adapter extends CommonAdapter<Bean> {

    public Adapter(Context context, List<Bean> datas) {
        super(context, datas, R.layout.item_listview);
    }

    @Override
    public void convert(ViewHolder viewHolder, Bean bean) {
        TextView itemTitle = viewHolder.getView(R.id.item_listview_title);
        TextView itemContent = viewHolder.getView(R.id.item_listview_content);
        TextView itemTime = viewHolder.getView(R.id.item_listview_time);
        itemTitle.setText(bean.getItemTitle());
        itemContent.setText(bean.getItemContent());
        itemTime.setText(bean.getItemTime());
    }
}

進一步的優化

 考慮到我們常用的控制元件有 TextView、ImageView 等等,我們可以提前將這些控制元件的通用方法抽取出來。這裡以 TextView 為例,我們常用的無非是為其設定輸出語句,因此可以在 ViewHolder 類裡提前寫好相應的方法:

/**
     * 子控制元件的通用方法
     *
     * @param viewId
     * @param text
     * @return
     */
    public ViewHolder setText(int viewId, String text) {
        TextView tv = getView(viewId);
        tv.setText(text);
        return this;
    }

 這樣 Adapter 裡的方法可以得到進一步的簡化:

@Override
    public void convert(ViewHolder viewHolder, Bean bean) {
        viewHolder.setText(R.id.item_listview_title, bean.getItemTitle())
                .setText(R.id.item_listview_content, bean.getItemContent())
                .setText(R.id.item_listview_time, bean.getItemTime());
    }

相關推薦

Android學習筆記5——通用介面卡

 本文內容參考自慕課網。  ListView、GridView 是我們在 Android 中很常用的控制元件,通常來說,對於每一個控制元件都要寫對應的 ViewHolder 和 Adapter。但是當專案中的 ListView 很多時,寫 ViewHolder

STM32學習筆記5通用定時器PWM輸出

PWM的輸出管腳是確定好的,具體的引腳功能可以檢視《STM32參考手冊》的“8.3.7 定時器複用功能重對映”一節。在此需要強調的是,不同的TIMx有分配不同的引腳,但是考慮到管腳複用功能,STM32提出了一個重映像的概念,就是說通過設定某一些相關的暫存器,來使得在其他非原始指定的管腳上也能輸出PWM。但是這

Android學習筆記——圖片三級快取

圖片三級快取的重要性  很多時候我們都需要從網路上下載圖片,如果在圖片很多的情況下,每次啟動app都要從網上下載,就會造成流量的浪費,影響使用者的體驗。因此,要利用快取來避免圖片的重複載入。 圖片快取方式  所謂三級快取,即: 網路快取 記憶體快取

Swift學習筆記5:集合類型

nbsp roc 三種 一個 刪除指定元素 edge 空值 port 自定義 目錄: 數組:Array 集合:Set 字典:Dictionary Swift提供Array(有序集合數據)、Set(無序無重復集合)和Dictionary(無序鍵值對集合)三

bootstrap 學習筆記5---- 圖片和響應式工具

-h thumb ima ble resp 圓角 rim ucc spl (一)響應式圖片: 在 Bootstrap 版本 3 中,通過為圖片添加 .img-responsive 類可以讓圖片支持響應式布局。其實質是為圖片設置了 max-width: 100%;、 heig

學習筆記5---數學運算

mat tla fix bsp matlab 循環 支持 -- oot 一.開n次方 比如-8的立方根,用nthroot(-8,-3),不建議用(-8)^(1/3) 二. 乘除 向0取整數:clear all;clc;fix(7/2)ans = 3-----------

QT學習筆記5 菜單欄、工具欄、窗口、對話框

let qlabel rman 運行 內存空間 介紹 edi left setw 本程序主要介紹了以下幾種常用控件的使用方法: (1)菜單欄、工具欄 (2)核心控件、狀態欄、浮動窗口 (3)模態窗口、非模態窗口 (4)標準對話框、文件對話框 代碼如下: mainwindow

Hibernate學習筆記5---Query接口

center 結束 mce factory rst lis 聚集 數據庫 ber Hibernate中具有三種檢索方式(HQL,QBC,SQL) Query接口 一個查詢接口,用於向數據庫中查詢對象。並控制執行查詢的過程。Query接口內封裝了一個HQL查詢語句。 舉個栗子

SpringBoot學習筆記5:處理前端JSON返回的日期的格式

處理 date() ring row 學習筆記 post 直觀 val rtt SpringBoot學習筆記(4):處理前端JSON返回的日期的格式 問題描述   前端頁面顯示的時間為毫秒格式,不利於直觀顯示! 解決方法1——後端解決 public class Flow

ojective-C學習筆記5關於面向對象編程

reat com new 面向對象 cti 重要 dispatch circle 術語 先了解幾個OC中有關面向對象編程的術語 類(class)是一種表示對象類型的結構體。這裏所說的結構體和C語言中的結構體不是一回事。 對象(object)是一種包含值和指向其類的隱藏指針的

yii學習筆記5,視圖操作

this 添加 func 創建 fun brush 視圖 urn AS 在控制器調用$this->render()方法來輸出視圖 function actionLogin(){ $name = "admin";    // 加載視圖 return $

Docker學習筆記-5容器數據管理,鏈接容器,構建私有庫

控制 st2 容器數據 pan 備份文件 data- 否則 所有 連接 五、容器數據管理,鏈接容器,構建私有庫 ① 容器數據管理 docker管理數據的方式有兩種: 數據卷 數據卷容器 1. 數據卷 數據卷是一個或多個容器專門指定繞過Union File System的

STM32學習筆記5——通用定時器PWM輸出

part 大小 模式 lan 晶振 kcon 筆記 利用 .cn 1、TIMER輸出PWM基本概念 脈沖寬度調制(PWM),是英文“Pulse Width Modulation”的縮寫,簡稱脈寬調制,是利用微處理器的數字輸出來對模擬

Rust語言學習筆記5

完全 ack 結構 some not eight bject pixel ring Structs(結構體) struct User { username: String, email: String, sign_in_count: u64,

TCP/IP學習筆記5------IP選路

use 網絡通 icmp報文 子網掩碼 出現 很好 ref 命令 時間間隔 靜態IP選路 一個簡單的路由表 選路是IP層最重要的一個功能之一。前面的部分已經簡單的講過路由器是通過何種規則來根據IP數據包的IP地址來選擇路由。這裏就不重復了。首先來看看一個簡單的系統路由表。

C語言學習筆記5—— 語句1

  c程式常見結構大概有選擇結構,迴圈結構,順序結構。c程式由一個一個的函式構成,而構成函式的則是語句,語句包含賦值語句,迴圈語句,條件語句,分支語句。賦值語句對與我們來說是很熟悉的。條件語句,分支語句與迴圈語句則會在後面一一介紹到。   順序結構對於我們來說是很熟悉的,它可以是這個樣子。 &nbs

C語言學習筆記5—— 語句2

  在介紹過順序結構和選擇結構以後,我們能通過c語言做的事依舊很少,比如換硬幣問題。將一元的人民幣換成一分,兩分,五分的硬幣共50枚。如何解決這樣的問題呢?我們可以把它化解成一個求解線性方程組的問題。   可以設需要一分的硬幣x枚,兩分的硬幣y枚,五分的硬幣z枚。於是,我們可以得到一個方程組,像這樣:x+y

cesium 學習筆記52018.11.08

1.預設檢視設定: viewer.zoomTo(viewer.entities); 2.繪製形狀 立方體:box ;點:point ; 橢圓ellipse; 3.繪製橢圓柱體發現的問題: 第一個position的高度為水平高度,semiMinorAxis等為長短軸,height為

linux學習筆記5:檔案許可權

檔案許可權 1.檔案許可權存在的意義 系統最底層安全設定方法之一 保證檔案可以被可用的使用者做相應操作 2.檔案許可權的檢視 ls -l file ls -ld dir ll file ll -d dir 3.檔案許可權的讀取 - |rw-rw-r--|

RocketMQ學習筆記5----RocketMQ監控平臺rocketmq-console-ng的搭建

1. 下載rocketmq-console-ng   官網地址:https://github.com/apache/rocketmq-externals      拉下來之後,使用idea開啟rocketmq-console,在application.properties配置檔案中修改rocketmq.