2012年4月12日 星期四

了解Android resource檔案 (二)

接續上一個單元了解Android resource檔案 (一)

如果去追一下textAppearanceSmall可以找到

    <style name="TextAppearance.Small">
        <item name="android:textSize">14sp</item>
        <item name="android:textColor">?textColorSecondary</item>
    </style>

這說明textAppearanceSmall這個設定同時設定了字體大小以及顏色。我們有興趣的地方在顏色的設定,所以追蹤一下顏色可以發現

<item name="textColorSecondary">@android:color/secondary_text_dark</item>




以及在....res\color\目錄下的secondary_text_dark.xml檔案





<?xml version="1.0" encoding="utf-8"?>


            .......


<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_window_focused="false" android:state_enabled="false" android:color="@android:color/dim_foreground_dark_disabled"/>
    <item android:state_window_focused="false" android:color="@android:color/dim_foreground_dark"/>
    <item android:state_selected="true" android:state_enabled="false" android:color="@android:color/dim_foreground_dark_inverse_disabled"/>
    <item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_dark_inverse_disabled"/>
    <item android:state_selected="true" android:color="@android:color/dim_foreground_dark_inverse"/>
    <item android:state_activated="true" android:color="@android:color/bright_foreground_dark_inverse"/>
    <item android:state_pressed="true" android:color="@android:color/dim_foreground_dark_inverse"/>
    <item android:state_enabled="false" android:color="@android:color/dim_foreground_dark_disabled"/>
    <item android:color="@android:color/dim_foreground_dark"/> <!-- not selected -->
</selector>




這份文檔在Android裡面稱做State List,一般用來變換一個繪圖元件在不同狀態下的顯示圖片。


狀態的定義有 (原文照拷比較原汁原味)


android:state_pressed
Boolean. "true" if this item should be used when the object is pressed (such as when a button is touched/clicked); "false" if this item should be used in the default, non-pressed state.
android:state_focused
Boolean. "true" if this item should be used when the object has input focus (such as when the user selects a text input); "false" if this item should be used in the default, non-focused state.
android:state_hovered
Boolean. "true" if this item should be used when the object is being hovered by a cursor; "false" if this item should be used in the default, non-hovered state. Often, this drawable may be the same drawable used for the "focused" state.
Introduced in API level 14.
android:state_selected
Boolean. "true" if this item should be used when the object is the current user selection when navigating with a directional control (such as when navigating through a list with a d-pad); "false" if this item should be used when the object is not selected.
The selected state is used when focus (android:state_focused) is not sufficient (such as when list view has focus and an item within it is selected with a d-pad).
android:state_checkable
Boolean. "true" if this item should be used when the object is checkable; "false" if this item should be used when the object is not checkable. (Only useful if the object can transition between a checkable and non-checkable widget.)
android:state_checked
Boolean. "true" if this item should be used when the object is checked; "false" if it should be used when the object is un-checked.
android:state_enabled
Boolean. "true" if this item should be used when the object is enabled (capable of receiving touch/click events); "false" if it should be used when the object is disabled.
android:state_activated
Boolean. "true" if this item should be used when the object is activated as the persistent selection (such as to "highlight" the previously selected list item in a persistent navigation view); "false" if it should be used when the object is not activated.
Introduced in API level 11.
android:state_window_focused
Boolean. "true" if this item should be used when the application window has focus (the application is in the foreground), "false" if this item should be used when the application window does not have focus (for example, if the notification shade is pulled down or a dialog appears).







回到secondary_text_dark.xml這份文件,每一個<item ... />表示一個狀態,所以在寫的時候需要確認到每一個<item ... />之間是互斥的關係。所以
<item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_dark_inverse_disabled"/>


表示當此TextView被按住(state_pressed="true")且此TextView是被除能的(disabled, 看上面的英文會比較理解這在說什麼)則此TextView的顏色變換成dim_foreground_dark_inverse_disabled所定義 (查一下它的顏色代碼是 #80323232)






我們常用State List來變換按鈕的狀態,譬如壓下按鈕然後放開會有一個顏色的變換讓使用者感覺到按鈕確實有被觸碰到。xml範例如下



<!-- filename: buttonbackground.xml  -->


<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
   
    <item 
        android:drawable="@drawable/未按下時的圖片.png" 
        android:state_pressed="false" 
        android:state_selected="false"/>
    
    
    <item 
        android:drawable="@drawable/ 按下時的圖片.png 
        android:state_pressed="true"/>
</selector>


然後將Button的視圖的background屬性指向的這xml檔案即可。








2012年4月10日 星期二

了解Android resource檔案 (一)

資源 (Resource) 在Android裡面凡指一切除了程式碼以外的資料。它可以是一個檔案,像是一個mp3音樂檔或是一個xml的版面layout檔;也可以是一個系統參數值像是一個預設的字串,一個定義button按鈕的高度的整數或是一個背景的顏色定義。撰寫程式的時候應該學習將程式碼與資源當作是獨立的文件來處理,這對日後多語系以及多螢幕的支援都有很大的幫助。

這份文件談資源由兩個方向分別討論。第一個以資源的類型來討論,分別討論資源的取用方式。第二個方向則討論系統預設資源的取用以及使用者自定資源的方式。一般來說我們建議盡量使用系統預設的資源,系統沒有的才使用自定資源來輔助,這樣可以加快程式的撰寫以及各平台間的相容性。

 Android常用資源類型:
  • String (字串)
  • Layout (面板配置)
  • String Array (字串陣列)
  • Plurals (一個字串的集合,用來表示數量通常是複數形式)
  • Color (顏色)
  • Dimension (尺寸)
  • Image (圖片)
  • Color-Drawable (一個被著色的方型,由xml寫成)
 Android系統資源存放於<android-sdk-windows>\platforms\<android version>\data\res 目錄下。初學者最先碰到會使用的應該是...\res\values\attrs.xml 檔案裡面的字型設定還有顏色設定。如果利用Eclipse IDE隨便拉一個TextView控制項,它的屬性如下:
    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge" />

這裡表示這個TextView的文字Style以系統內定的?android:attr/textAppearanceLarge來顯示。定義的資料可以在R.attr裡面找到。定義如下:          

public static final int textAppearanceLarge

Since: API Level 1
Text color, typeface, size, and style for "large" text. Defaults to primary text color.
Must be a reference to another resource, in the form "@[+][package:]type:name" or to a theme attribute in the form "?[package:][type:]name".
Constant Value: 16842816 (0x01010040)

如果仔細去追可以在...\res\values\attrs.xml裡面找到
        <!-- Text color, typeface, size, and style for "large" text. Defaults to primary text color. -->
        <attr name="textAppearanceLarge" format="reference" />

一個 <attr>單元有兩屬性:name以及formatname就是這個<attr>的名字,可以讓他在別的地方被參考到。 format表示這個<attr>是符合哪一種格式。formate可用格式有:
    • reference - if it references another resource id (e.g, "@color/my_color", "@layout/my_layout")
    • color
    • boolean
    • dimension
    • float
    • integer
    • string
    • fraction
    • enum - normally implicitly defined
    • flag - normally implicitly defined
舉上面TextView的例子來說,我們可以在...\res\values\attrs.xml裡面找到

<declare-styleable name="ViewGroup_Layout">
                           .....
        <attr name="layout_width" format="dimension">
           
            <enum name="fill_parent" value="-1" />
            
            <enum name="match_parent" value="-1" />
            
            <enum name="wrap_content" value="-2" />
        </attr>
                                 .....
         

這定義"layout_width"是一種"dimension"的屬性,所以在TextView裡面  android:layout_width="wrap_content"  或是 android:layout_width="60dp" 這樣的敘述句就變成有定義。

回到<attr name="textAppearanceLarge" format="reference" />, reference 表示textAppearanceLarge 可以在...\res\values\themes.xml 裡面找到它的定義。
       <style name="Theme">
                    ....
            <item name="textAppearanceLarge">@android:style/TextAppearance.Large</item>
                    ....
        
繼續往下追可以在...\res\values\style.xml裡面找到
      <style name="TextAppearance.Large">
        <item name="android:textSize">22sp</item>
    </style>

在Android程式設計個過程,我們提供程式碼追蹤的過程但不建議更改這些設定值。這裡我們也了解到textAppearanceLarge其實是一個Style設定,所以程式碼寫成
      
android:textAppearance="?android:attr/textAppearanceLarge"  或是

      sytle="?android:attr/textAppearanceLarge" 實際上是一樣的。

 Android 常用系統預設文字大小以及顏色
  • 文字大小  android:textAppearance="?android:attr/textAppearanceLarge"
    android:textAppearance="?android:attr/textAppearanceMedium"
    android:textAppearance="?android:attr/textAppearanceSmall"
  • 字體顏色 android:textColor="?android:attr/textColorPrimary"
    android:textColor="?android:attr/textColorSecondary"
    android:textColor="?android:attr/textColorTertiary"
    android:textColor="?android:attr/textColorPrimaryInverse"
    android:textColor="?android:attr/textColorSecondaryInverse"

2012年4月6日 星期五

Android上日期與時間的處理 - Calendar

在Android系統裡面可以使用到關於時間的類別有三種


主要使用Calendar類別,Date類別在Android中不建議使用然而我們會用到java.text.SimpleDateFormat這個類別來處理DateString間的轉換所以Data類別常用來當作Calendar類別和String類別轉換的中介類別。

Timestamp類別在Android當中有兩個同名類別,分別是java.sql.Timestamp以及java.security.Timestamp。使用的時候要注意不要import錯誤的package。Timestamp類別使用在SQLite資料庫中。SQLite對於記錄日期時間的方式有兩種欄位宣告的程式撰寫方式,一種是將欄位宣告成為long,直接記錄Calendar.getTimeInMillis()後的數值;另一種則是宣告成為Timestamp,預設值是使用yyyy-MM-dd hh:mm:ss.SSS的字串型式儲存。

整理一些常用的寫法如下:

  • 建立一個新的Calendar物件,預設初值為系統現在時間
    Calendar c = Calendar.getInstance();

    這是一個隱式的敘述,如果追蹤程式碼可以發現它創立了一個新的物件而不是和別人共用物件。Calendar所建立的時間是以197011日開始計算到目前為止的格林威治標準時間的milliseconds,所以不管在哪一個時區所儲存的時間都是一樣的。如果要顯示出不同時區和不同地區的時間則需要在輸出的時候由SimpleDateFormat擔任轉換的工作。
  • 設定Calendar物件到特定的時間
    Calendar c = Calendar.getInstance();
    c.set(2012, 11, 12);        
    //設定日期為20121212日,
                                 //Calendar
    類別中月份的編號是由0~11

    c.set(calendar.YEAR, 2013);                        //將年改成2013 
    c.set(Calendar.MONTH, Calendar.JANUARY);   //
    將月份改成1
    c.set(Calendar.DAY_OF_MONTH, 31);            //
    將日改成31

    c.set(Calendar.HOUR_OF_DAY, 18);               //hour改成下午六點

    c.set(Calendar.AM_PM, Calendar.PM);             //hour改成下午六點 
    c.set(Calendar.HOUR, 6);
    *** 有上面這些範例,其他時間的設定應該可以找出規律來了。
  • 取得Calendar物件資訊
    Calendar c = Calendar.getInstance();
    int year = c.get(Calendar.YEAR);                      //取出年
    int month = c.get(Calendar.MONTH) + 1;           //取出月,月份的編號是由0~11 故+1
    int day = c.get(Calendar.DAY_OF_MONTH);        //取出日

    int weekday = c.get(Calendar.DAY_OF_WEEK);  
    //取出星期幾,編號由Sunday(1)~Saturday(7)


  • CalendarDate間的互轉
    Calendar類別提供getTime()setTime()兩個方法和Date類別互轉,由函式原型來看

    public final Date getTime ()

    public final void setTime (Date date)

    要記得c.getTime()所傳回的型別就是Date類別了,在使用上要稍微留意一下。
    • Calendar to Date
      Date date = c.getTime();
    • Date to Calendar
      c.setTime(date);
  • CalendarTimestamp間的互轉
    CalendarTimestamp之間是利用milliseconds來轉換,利用getTimeInMillis()

    public long getTimeInMillis ()

    • Calendar to Timestamp
      Timestamp time = new Timestamp(c.getTimeInMillis());
    • Timestamp to Calendar
      c.setTime(time)

  • CalendarString間的互轉
    SimpleDateFormat可以用來在StringDate間互轉,透過Date做中介使得Calendar和String間可以互相轉換。
    SimpleDateFormat的樣式表可以由這裡查到,基本用法如下:
    • Calendar to String:
      SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 
      Calendar c = Calendar.getInstance();
      String str = df.format(c.getTime());
    • String to Calendar:
      SimpleDateFormat df2 = new SimpleDateFormat("yyyy/MM/dd");
      Calendar cc = Calendar.getInstance();
      try {
          cc.setTime(df2.parse("2012/12/12"));
      } catch (ParseException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
      }

      simpleDateFormat
      的模板裡面用大寫的"MM"表示月份,小寫的"mm"表示分鐘;大寫的"HH"表示24小時制的hour (0~23),小寫的"hh"表示12小時制的hour (1~12),大寫的"KK"表示
      12小時制的hour (0~11),小寫的"kk"表示24小時制的hour (1~24)。
  • 常用的SimpleDateFormat格式
    • 取出日期
      SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");
      String str = df.format(c.getTime());
    • 取出時間(24 hr)
      SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
      String str = df.format(c.getTime());
    • 取出時間(12 hr am/pm)
      SimpleDateFormat df = new SimpleDateFormat("hh:mm:ss a");
      String str = df.format(c.getTime());

      這個型式會輸出類似:10:25:30 上午 的格式,如果想要輸出成為 10:25:30 AM則需要使用地區設定來幫忙
      SimpleDateFormat df = new SimpleDateFormat("hh:mm:ss a", Locale.US);
      String str = df.format(c.getTime());
    • 模板中如果使用超過3個字符表示需要用全名來印出
      取出月份,以文字模式
      SimpleDateFormat df = new SimpleDateFormat("MMMM dd yy, EEEE");
      會印出 "4月 06 12, 星期五"


  • Calendar常用計算
    • 加減日期 (使用add())
      Calendar c = Calendar.getInstance();
      c.add(Calendar.DAY_OF_MONTH, 2);          //加上兩天
      c.add(Calendar.MONTH, -1);
                               // 減一個月
      在加減日期運算時不需要考慮到是否有跨月份或是跨年度的問題,Calendar會幫我們處理好。
    • 只針對特別欄位作加減運算(使用roll())
      Calendar c = Calendar.getInstance();
      c.roll(Calendar.MONTH, 10); 
         // 若目前日期是2012/6/12
                                                        // 運算過後會變成 2012/4/12
                                                        // 表示只會更改月份,不會影響其他欄位 ( 6 + 10 - 12 = 4)
    • 計算兩個日期間的間隔 ( I )
      Calendar c1 = Calendar.getInstance(); 
      Calendar c2 = Calendar.getInstance(); 
      c1.set(2012, Calendar.JANUARY, 31);
      c2.set(2012, Calendar.MAY, 5);  

      int day1 = c1.get(Calendar.DAY_OF_YEAR);
      int day2 = c2.get(Calendar.DAY_OF_YEAR); 
      int dayDiff = day2 - day1;

      上面的運算中,如果兩個日期不在同一年度則需要先判斷年度再進行日期計算
    • 計算兩個日期間的間隔 ( II )利用millisecond來計算。
      Calendar c1 = Calendar.getInstance(); 
      Calendar c2 = Calendar.getInstance(); 
      c1.set(2012, Calendar.JANUARY, 31);
      c2.set(2012, Calendar.MAY, 5);
       

      long aDayInMilliSecond = 60 * 60 * 24 * 1000;     //一天的毫秒數
      long dayDiff = (c2.getTimeInMillis() - c1.getTimeInMillis()) / aDayInMilliSecond;
    • 取得這個月有幾天
      c.set(Calendar.MONTH, Calendar.FEBRUARY);
      int daysInMonth = c.getActualMaximum(Calendar.DAY_OF_MONTH);

      這個函式會傳回特定欄位的最大值,可以用來傳回一個月有幾天。包含閏年的2月有29天都可以正確的回傳。
  • 利用cursor取得SQLite內的Timestamp內容

    Timestamp c = Timestamp.valueOf(cursor.getString(ColumnIndex);

2012年4月3日 星期二

學習Androidt程式撰寫的第一堂課:程式碼追蹤

首先建立一個簡單的HelloWorld Project。
我們使用debug perspective來追蹤程式碼,在onCreate()裡面的
super.onCreate(savedInstancesState);前面放上一個中斷點。
關於Android Activity的生命週期參考http://developer.android.com/images/activity_lifecycle.png

執行debuge,當程式碼停在中斷點的時候在Outline視窗用滑鼠右鍵點選onCreate(Bundle):void
選擇Open Type Hierarchy會出現如下畫面

按F5 (Step Into)進入super.onCreate()的細節,如果出現Source not found的訊息,則依照使用Android Source Code的內容增加source code。


如果又出現Source not found的訊息而按鈕內容變成 Edit Source Lookup Path... 則參考

Edit Source Lookup的內容,選擇 Add... -->File System Directory 將source code的路徑再指定一次即可



2012年4月2日 星期一

ArrayAdapter的使用

ArrayAdapter是Android當中最簡單的adapter,它可以連結一個字串陣列到一個只有一個TextView元件的List物件當中。語法如下:

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                 android.R.layout.simple_list_item_1, new String[]{"今天", "天氣", "很好"});


android.R.layout.simple_list_item_1.xml是Android SDK所提供的資源檔,放在...\platforms\<android version>\data\res\layout子目錄中。它是一個很好的參考,如果只是需要改動該視圖的長寬、顏色等可以更動這個檔案的內容並以另外的名稱儲存備用。

ArrayAdapter提供其它的建構函式,如果child layout裡面不是只有一個簡單的TextView,我們可以自定layout的型式以及需要輸入的字串陣列。

另外也可以在xml裡面定義字串陣列然後再利用createFromResource()將字串與layout連結起來,範例如下:

ListView listview = (ListView) findViewById(<resource Id>);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
                    R.array.week, android.R.layout.simple_list_item_1);

listview.setAdapter(adapter);


需要在\res\values\子目錄下建立一個week.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- This file is /res/values/week.xml -->
<resources>
    <string-array name="week">
        <item >星期日</item>
        <item >星期一</item>
        <item >星期二</item>
        <item >星期三</item>
        <item >星期四</item>
        <item >星期五</item>
        <item >星期六</item>
    </string-array>   
</resources>




若是資料的內容有變更,要記住ListView類別是負責顯示在螢幕上,adapter類別才是負責處理資料的繫結。可以利用ArrayAdapter的add()方法新增資料到adapter尾端或是用insert()新增資料到特定的位置;刪除資料則使用remove()方法。


一旦adapter內的資料有了變更,則adapter和ListView的內容就失去了同步,這是侯需要由adapter發送一個notifyDataSetChanged()方法通知ListView重新同步顯示的內容。

當需要自定Layout,且layout當中不只有一個view時,除了系統預設的建構函式以外,比較多的用法是覆寫getView()函式。

ArrayAdapter是繼承自BaseAdapter,當使用BaseAdapter來建構使用者自定的Layout時需要覆寫getCount(), getItem(Int position), getItemId(int position), 還有 getView(int position, View convertView, ViewGroup parent)那麼多函式。雖然大部分有書或是範例可以照抄但是誰曉得一不小心寫錯些什麼會不會搞死自己,這時候可以利用ArrayAdapter化簡一下工作。
我利用一個小技巧,先依照所需要的child view的數量產生一個物件陣列,通常就是String[],或是Bitmap[]或是將會用到的任何物件陣列。將這個物件陣列送給ArrayAdapter當作建構子參數,則ArrayAdapter會幫我們處理掉getCount(), getItem(Int position), getItemId(int position)這幾個函式,剩下的只需要覆寫getView(int position, View convertView, ViewGroup parent)即可,這也是主要的工作。

範例程式碼:

public class TheFirstClassActivity extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);


    ListView listview = (ListView) findViewById(R.id.listView1);
    testAdapter adapter = new testAdapter(this,
                   new String[]{"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"});
    listview.setAdapter(adapter);
  }



private static class testAdapter extends ArrayAdapter<Object> {
    // XML Layout, 通常自定Layou就會寫死在類別裡,不再透過引數傳入以免產生誤用
    private static final int mResourceId = R.layout.statisticcell;  //自定的layout
    private LayoutInflater mInflater;


    // 預設圖片id
    private static final int[] imgId = { R.drawable.ic_01,
        R.drawable.ic_02, R.drawable.ic_03 };


    public testAdapter(Context context, Object[] objects) {
      super(context, mResourceId, objects);
      mInflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);  
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
      View view;
      if (convertView == null) {
        view = mInflater.inflate(mResourceId, parent, false);
      } else {
        view = convertView;
      }
      
      /**Layout中的UI在這裡綁定,這裡只有一個TextView以及一個ImageView作為範例 */
      TextView tx;
      ImageView iv;     
      tx = (TextView)view.findViewById(R.id.textHour);
      tx.setText((CharSequence) getItem(position));   //抓取由主程式傳進來的字串陣列內容
      iv = (ImageView)view.findViewById(R.id.imageDay1);
      iv.setImageResource(imgId[0]);
      
      return view;
    }
  }
}


使用Android Source Code

Android Developers上面所提到的內容過於片段,沒有很熟悉Android系統的人很難有系統的理解Android,檢視原始碼可以幫助我們更加理解Android SDK,也可以拿來當作學習撰寫Android程式的參考。若是程式有錯誤發生,在debug時也可以較有效率的追蹤錯誤的發生和解決錯誤。

通常使用Eclipse開發Android程式,預設值是沒有載入source code,需要額外的設定。Android 開放原始碼是由Git (http://git-scm.com/)所管理,原始碼則發佈在http://source.android.com.

幾個可以線上瀏覽的網站有:
http://android.git.kernel.org
http://android.googlesource.com (上面兩個會轉址到 http://source.android.com/source/downloading.html)
http://code.google.com/p/android/


使用Git下載Android原始碼
  1. 下載並安裝Git
    http://code.google.com/p/msysgit/downloads/list?can=3下載並安裝Git。安裝時候需要設定預設的目錄,我設定的是c:/android/msysgit
  2. 測試Git的安裝
    安裝完成以後進入到c:/android/msysgit子目錄雙擊msys.bat檔案進入模擬環境。在模擬環境中進入/bin子目錄然後執行
    git clone git://git.kernel.org/pub/scm/git/git.git
    若能正確執行則表示Git安裝成功。測試成功以後要將測試用的git目錄刪除否則會影響後面的命令執行。
  3. 下載Android Repositories
    執行:git clone https://android.googlesource.com/platform/manifest.git
    成功以後接著執行:
    git clone https://android.googlesource.com/platform/frameworks/base.git 以及
    git clone https://android.googlesource.com/platform/packages/providers/ContactsProvider
    檔案有些大,需要一點時間才能完成下載 (~~ 1.5GB)。
使用Android SDK Manager下載原始碼
  1. Android SDK 4.0以後可以由Android SDK Manager下載原始碼,位置放置於
    ...sdk目錄\sources\android-xx (14 或 15)
在Eclipse中載入原始碼
  1. 開啟Eclipse,在任意的編輯視窗內按下Ctrl + Shift + T 開啟Open Type,然後隨意查詢一個Android View視圖。 這裡選用ListView


  2. 如果沒有安裝Source Code會出現下面的畫面

  3. 按下Attach Source,然後再按下External Folder...





  4. 選擇剛才下載的來原碼位置,一般會在...\msysgit\bin\base\core\java下(使用Git下載),或是 ...sdk目錄\sources\android-xx (使用Android SDK Manager下載)。點擊OK後即可看到LitView的原始碼,此後其它的原始碼也可以被看到。


網誌開通

Android的程式學了又忘,忘了再學有點辛苦!因為花了一些時間K書,留下一些記錄讓自己記得,也許有其他人也會需要。