iT邦幫忙

DAY 24
2

以「寶寶聯絡簿」為例,適合 Android 初學者的學習筆記系列 第 24

寶寶生活記錄 App (Day24 AdapterView初探)

  • 分享至 

  • twitterImage
  •  

關於 BabyEditorActivity 的實作細節,我們還有兩個細節需要討論:(1) RadioGroup 的使用;(2) 如何從 SD 卡的相片或透過拍攝來設定大頭貼。然而在介紹這兩個議題之前,筆者想先暫時停止「新增寶寶」的實作,改成先實作「寶寶列表」,原因是這樣我們可以做一些簡單的測試,在昨天的程式碼中,讀者應該不難發現「完成」按鈕按下後會呼叫 BabyDB.addBaby 將寶寶的資料儲存到資料庫,如果堅持要完成所有「新增寶寶」的功能後再實作「寶寶列表」的功能,依筆者現在的開發進度,可能要好幾天後才能測試寶寶資料是否有正確儲存。

基於上述的理由,今天我們來討論「寶寶列表」的實作,寶寶列表會使用到 ListView,這個 ListView 跟我們已介紹過的 View (如TextView, ImageView, Button等)有一點點的不同,ListView繼承了AdapterView,繼承 AdapterView 的介面元件的特性是:「資料」和「介面元件」需要透過 Adapter做結合 [1]。

我們就實際用「寶寶生活記錄 App」的「寶寶列表 Activity」 來解說 ListView 的使用方法,首先這個 Activity 的版面設計檔如下所示:

<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"
    android:paddingBottom="6dp"
    android:paddingLeft="7dp"
    android:paddingRight="7dp"
    android:id="@+id/rootview"
    android:paddingTop="5dp"
    android:background="#EBEBEB" >

    <LinearLayout android:id="@+id/ll_loading"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:visibility="gone"
        android:gravity="center"
        android:layout_centerHorizontal="true"
        android:layout_alignParentTop="true"
        >
        <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="center_vertical"
            android:gravity="center_vertical"
            android:textSize="16sp"
            android:text="@string/loading"
            />
    </LinearLayout>

    <LinearLayout android:id="@+id/ll_emptylist"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:visibility="gone"
        android:weightSum="7">
        <TextView
            android:layout_weight="6"
            android:layout_width="0dip"
            android:layout_height="match_parent"
            android:textSize="16sp"
            android:textColor="#F00"
            android:gravity="center"
            android:layout_gravity="center"
            android:text="@string/emptybaby"
            />
        <ImageView android:id="@+id/iv_addbaby"
            android:layout_weight="1"
            android:layout_width="0dip"
            android:layout_height="match_parent"
            android:src="@drawable/add_black"/>
    </LinearLayout>

    <LinearLayout android:id="@+id/ll_notempty"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <RelativeLayout android:id="@+id/rl_usage"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#A0000000"
            >
            <ImageView android:id="@+id/iv_close"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/remove"
                android:layout_alignParentRight="true"/>
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_toLeftOf="@id/iv_close"
                android:layout_alignParentLeft="true"
                android:background="#00000000"
                android:textColor="#FFF"
                android:textSize="16sp"
                android:gravity="center"
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:text="@string/babylist_usage"/>
        </RelativeLayout>
        <ListView android:id="@+id/lv_babylist"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            />
     </LinearLayout>
</RelativeLayout>

這份 XML 文件應該不需要特別解說了,使用 ListView 標籤就可在版面中新增一個列表 (List)。我們把重心放在 BabyListActivity,其內容如下所示:

package lincyu.babylog.babymanager;

import android.app.ActionBar;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;

import java.util.ArrayList;

import lincyu.babylog.R;
import lincyu.babylog.db.Baby;
import lincyu.babylog.db.BabyDB;


public class BabyListActivity_20141016 extends ActionBarActivity {

    private ListView lv_babylist;
    private LinearLayout ll_emptylist, ll_loading, ll_notempty;
    private ImageView iv_addbaby, iv_close;

    private ArrayList<Baby> babylist;
    private ArrayAdapter<Baby> adapter;

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

    }

    private void viewInitialization() {
        ActionBar actionbar = getActionBar();
        actionbar.setDisplayHomeAsUpEnabled(true);
        actionbar.setDisplayShowHomeEnabled(false);

        ll_loading = (LinearLayout)findViewById(R.id.ll_loading);
        ll_emptylist = (LinearLayout)findViewById(R.id.ll_emptylist);
        ll_notempty = (LinearLayout)findViewById(R.id.ll_notempty);

        iv_addbaby = (ImageView)findViewById(R.id.iv_addbaby);
        lv_babylist = (ListView)findViewById(R.id.lv_babylist);
    }

    @Override
    public void onResume() {
        super.onResume();
        new BackgroundLoadBabyList().execute();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                finish();
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    protected class BackgroundLoadBabyList extends AsyncTask<Void, Void, Void> {

        @Override
        protected void onPostExecute(Void result) {
            ll_loading.setVisibility(View.GONE);

            if (babylist.size() == 0) {
                ll_emptylist.setVisibility(View.VISIBLE);
                ll_notempty.setVisibility(View.GONE);
            } else {
                ll_notempty.setVisibility(View.VISIBLE);
                ll_emptylist.setVisibility(View.GONE);
            }
            lv_babylist.setAdapter(adapter);
        }

        @Override
        protected void onPreExecute() {
            ll_loading.setVisibility(View.VISIBLE);
            ll_emptylist.setVisibility(View.GONE);
            ll_notempty.setVisibility(View.GONE);
        }

        @Override
        protected Void doInBackground(Void... params) {
            babylist = BabyDB.getAllBabies(BabyListActivity_20141016.this);
            adapter = new ArrayAdapter(BabyListActivity_20141016.this,
                android.R.layout.simple_list_item_1, babylist);
            return null;
        }
    }
}

和一般的 View 一樣,程式利用 Activity 類別的 findViewById 初始化 ListView 物件 lv_babylist,接著程式利用 AsyncTask [2] 載入 ListView 所需的資料,AsyncTask 可視為是 Thread 的另一種選擇,若 ListView 的資料需要從網路上下載,連線的動作必須寫在 Thread 於背景執行,另一種選擇是使用 AsyncTask 來實作。若對上述的說明不甚了解也沒有關係,只要記得用 AsyncTask 載入 ListView 資料時,讀取資料的動作 (有些情況可能需要連網) 應該寫在 doInBackground,在我們的例子中,我們呼叫 BabyDB.getAllBabies 取出所有寶寶資料,資料準備好後,我們要準備一個 Adapter,此處我們使用 ArrayAdapter [3]。

程式中使用的建構子是下面這一個:

ArrayAdapter(Context context, int resource, List<T> objects)

利用 ArrayAdapter 產生的 ListView 的每一個 Item 預設是一個 TextView,建構子的第二個參數是一個 Layout 檔的 Resource ID,程式中使用的是內建的 android.R.layout.simple_list_item_1,從 simple_list_item_1 的原始檔可以知道,這個 Layout 裏面就是一個 TextView,而這個 TextView 的 ID 是 「@android:id/text1」,明天我們會針對這個檔案做更詳細的說明,會介紹如何做一個更客製化的 ListView。第三個參數我們填上 babylist,其為一個 Baby 物件的動態陣列 (ArrayList<Baby>),每個動態陣列內的元素 (Baby物件) 會呼叫其 toString 方法將字串顯示於 TextView 上,筆者改寫了 Baby 物件的 toString 如下所示:

    @Override
    public String toString() {
        int namelength = name.length();
        int nicknamelength = nickname.length();

        if (namelength == 0 && nicknamelength == 0) {
            return "";
        } else if (namelength == 0 && nicknamelength != 0) {
            return nickname;
        } else if (namelength != 0 && nicknamelength == 0) {
            return name;
        }
        return nickname + " (" + name + ")";
    }

利用 ArrayAdapter 產生了 adapter 物件後,最後只要呼叫ListView 的 setAdapter 就可以把資料和 ListView 綁定了。讀者可嘗試輸入幾筆資料,並觀看其執行結果,下面是一個範例:

參考資料

[1] 林致宇, Android程式設計入門與應用(附範例光碟), 全華出版社, ISBN: 9789572194126, http://www.opentech.com.tw/search/bookinfo.asp?isbn=9789572194126&companyID=04383129

[2] AsyncTask | Android Developers, http://developer.android.com/reference/android/os/AsyncTask.html

[3] ArrayAdapter | Android Developers, http://developer.android.com/reference/android/widget/ArrayAdapter.html


上一篇
寶寶生活記錄 App (Day23 「新增寶寶」實作-2)
下一篇
寶寶生活記錄 App (Day25 再探 ArrayAdapter)
系列文
以「寶寶聯絡簿」為例,適合 Android 初學者的學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言