Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 初級開發 >> Android開發教程之高煥堂-上課講義(1)

Android開發教程之高煥堂-上課講義(1)

編輯:初級開發

上課講義之 1: 高煥堂講解 Intent-based Programming

Android的4種嫡系組件(即Activity、Service、IntentReceiver和ContentProvider)之間如何互相溝通呢?這4種嫡系組件都是由android啟動的,並不是組件之間透過直接呼叫而啟動的。就像我們打手機去車行叫計程車,而不是直接到街道上叫車。我們送給行一個簡訊一通電話,表明我們的「意圖」(Intent),當車行經理接到此意圖,就依據你的意圖的內含條件而去挑選最合適的計程車,然後派遣它去接你。

「意圖」(Intent)本身是定義為一個類別(Class),一個Intent物件表達一個目的(Goal)或期望(Expectation),敘述其所期望的服務或動作、與動作有關的資料等。Android則根據此Intent物件之敘述,負責配對,找出相配的組件,然後將 Intent物件傳遞給所找到的組件,android的媒婆任務就完成了。

因此,Intent物件扮演著媒體仲介的角色,提供「ClIEnt組件 à android à Server組件」之間互相溝通的相關資訊,實現了ClIEnt組件與Server組件之間『不知而亦能用』之效果,這又稱為疏結合(Loosely-coupled)效果。其創造了Server組件抽換的自由度,這又稱為PnP(Plug and Play)。

茲以下圖為例,Activity主要是提供UI畫面來與User進行互動,兩個Activity之間的直接互動較少。其它如ContentProvider則常是為Activity等提供服務的。所以Activity發出Intent物件委託android挑選到適當的ContentProvider物件(並且將Intent物件傳遞給ContentProvider物件)之後,通常會透過ContentProvider介面而呼叫ContentProvider的各項服務或功能。

clip_image001

在此圖所示的範例裡,當我們在一個訂單列表畫面(如Activity-1),點選某個訂單之後,希望能夠呈現出此訂單的採購細項畫面(如Activity-2)。此時,Activity-1需要發出一個 Intent物件,這個Intent物件說明了意圖:包括“查找”(Get)動作、訂單ID等資料,然後呼叫Activity父類別的startActivity (Intent intent)函數,將此Intent物件傳送給Android。而Android會根據此Intent物件中的敘述,與androidManifest.XML所敘述的各嫡系類別之條件相比較,找出與此Intent敘述相配的組件(如Activity-2),然後android將該Intent物件遞交給它,於是Activity-2會根據此Intent物件之敘述而執行相應的動作。

上課講義摘錄之2: 高煥堂講解 ContentProvider & 範例

1. 何謂android的嫡系組件
Android有4項一等公民(或稱為嫡系親屬),包括:Activity、ContentProvider、IntentReceiver與Service。它們都必須宣告於androidManifest.XML檔案裡,如下:

 

package="com.misoo.SQ03">


android:name="android.permission.INTERNET">

 

<provider android:name="DataProvider"

android:authoritIEs="com.misoo.provider.SQ03">

provider>

<activity android:name=".ac01" android:label="@string/app_name">

 

 

activity>

<activity android:name=".DispActivity" android:label="DispActivity">

activity>

 

這讓Android知道我們城市裡定義了多少個嫡系組件類別;Android可以在啟動時就將它們執行起來,成為共享的(Shared)服務組件。這些嫡系服務組件間的溝通,通常是透過「意圖」(Intent)物件來請Android轉達給對方,android則會依據意圖而找出最佳的配對。配對成功,就展開相互的溝通與服務了。

2. 什麼是ContentProvider嫡系組件
---- 以SQLite為例
在Android裡,SQLite資料庫是最典型的ContentProvider,負責儲存各式各樣的內容。除了資料庫之外,還有許多其他種類的ContentProvider。在這裡並不是要介紹這些ContentProvider,而是要透過SQLite認識ContentProvider介面,然後將舶來Linter組件,配上這種ContentProvider介面,讓它搖身一變成為android的嫡系組件。

2.1 一般(即非嫡系)SQLite的範例
沒有透過ContentProvider介面來使用SQLite,就是對SQLite的「非嫡系」用法。此時,應用程式透過JDBC介面和SQL語句來與SQLite溝通,以存取資料庫裡的內容。先認識這種傳統用法。此範例將從SQLite讀取資料。首先建立一個程式專案,其含有兩個Java程式檔:ac01.java和DataProvider.java。其中,ac01.Java 是典型的Activity類別,負責UI畫面的顯示工作,而DataProvider則負責與SQLite溝通。其詳細程式碼為:

/* ----- ac01.Java 程式碼 ------*/

package com.misoo.pklx;

import Java.util.ArrayList;

import Java.util.HashMap;

import Java.util.Map;

import android.app.ListActivity;

import android.database.Cursor;

import android.os.Bundle;

import android.view.VIEw;

import android.widget.ListVIEw;

import android.widget.SimpleAdapter;

public class ac01 extends ListActivity {

private static final String[] PROJECTION = new String[] { "stud_no", "stud_name" };

@Override protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

DataProvider dp = new DataProvider(this);

Cursor cur = dp.query(PROJECTION, null, null, null);

ArrayList> coll

= new ArrayList>();

Map item;

cur.moveToFirst();

while(!cur.isAfterLast()) {

item = new HashMap();

item.put("c1", cur.getString(0) + ", " + cur.getString(1));

coll.add(item);

cur.moveToNext();

}

dp.close();

this.setListAdapter(new SimpleAdapter(this, coll,

android.R.layout.simple_list_item_1, new String[] { "c1" },

new int[] {android.R.id.text1}));

}

@Override

protected void onListItemClick(ListView l, VIEw v, int position, long id) {

finish();

}}

指令:

DataProvider dp = new DataProvider(this);

這和一般類別之用法是一樣的。ac01物件指名要誕生一個DataProvider的物件。然後呼叫它,如下指令:

Cursor cur = dp.query(PROJECTION, null, null, null);

這要求SQLite從資料庫查詢出某些資料。詳細的DataProvider.Java程式碼如下:

/* ----- DataProvider.Java 程式碼 ------*/

package com.misoo.pklx;

import android.content.Context;

import android.database.Cursor;

import android.database.SQLException;

import android.database.sqlite.SQLiteDatabase;

import android.util.Log;

public class DataProvider {

private static final String DATABASE_NAME = "StudDB";

private static final String TABLE_NAME = "Student";

private final int DB_MODE = Context.MODE_PRIVATE;

private SQLiteDatabase db=null;

public DataProvider(Context ctx) {

try { db = ctx.openOrCreateDatabase(DATABASE_NAME, DB_MODE, null); }

catch (Exception e) { Log.e("ERROR", e.toString()); return; }

try { db.execSQL("drop table "+ TABLE_NAME); }

catch (Exception e) { Log.e("ERROR", e.toString()); }

db.execSQL("CREATE TABLE " + TABLE_NAME + " (" + "stud_no" + " TEXT,"

+ "stud_name" + " TEXT" + ");");

String sql_1 = "insert into "+ TABLE_NAME +

" (stud_no, stud_name) values('S101', 'Lily');";

String sql_2 = "insert into " + TABLE_NAME +

" (stud_no, stud_name) values('S102', 'Linda');";

String sql_3 = "insert into " + TABLE_NAME +

" (stud_no, stud_name) values('S103', 'Bruce');";

try { db.execSQL(sql_1); db.execSQL(sql_2); db.execSQL(sql_3); }

catch (SQLException e) { Log.e("ERROR", e.toString()); return; }

}

public Cursor query(String[] projection, String selection, String[] selectionArgs,

String sortOrder) {

Cursor cur = db.query(TABLE_NAME, projection, null, null, null, null, null);

return cur;

}

public void close(){ db.close(); }

}

這種用法屬於非嫡系的用法:在ac01.Java程式碼裡,其指令:

DataProvider dp = new DataProvider(this);

明確指定由DataProvider物件來提供服務。反之,嫡系用法則是透過意圖(Intent)來請android代為配對,進而找出適當的ContentProvider物件來為aco1物件提供服務。

2.2 嫡系SQLite的範例
剛才的範例裡,我們直接使用DataProvider類別的介面來與SQLite溝通。本節的範例,將替DataProvider配上ContentProvider介面,讓ac01物件能透過ContentProvider新介面來溝通。此範例也是從SQLite資料庫讀取3筆資料;請仔細看看其程式碼的微妙差異:

/* ----- ac01.Java 程式碼 ------*/

package com.misoo.pkrr;

import Java.util.ArrayList;

import Java.util.HashMap;

import Java.util.Map;

import android.app.ListActivity;

import android.content.Intent;

import android.database.Cursor;

import android.Net.Uri;

import android.os.Bundle;

import android.view.VIEw;

import android.widget.ListVIEw;

import android.widget.SimpleAdapter;

public class ac01 extends ListActivity {

public static int g_variable;

public static final String AUTHORITY = "com.misoo.provider.rx09-02";

public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY

+ "/Student");

private static final String[] PROJECTION

= new String[]{ "stud_no", "stud_name"};

@Override protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

Intent intent = getIntent();

if (intent.getData() == null) intent.setData(CONTENT_URI);

Cursor cur = getContentResolver().query(getIntent().getData(),

PROJECTION, null, null, null);

ArrayList> coll = new ArrayList>();

Map item;

cur.moveToFirst();

while (!cur.isAfterLast()) {

item = new HashMap();

item.put("c1", cur.getString(0) + ", " + cur.getString(1));

coll.add(item);

cur.moveToNext();

}

this.setListAdapter(new SimpleAdapter(this, coll,

android.R.layout.simple_list_item_1, new String[] { "c1" },

new int[] { android.R.id.text1 }));

}

@Override

protected void onListItemClick(ListView l, VIEw v, int position, long id) { finish();}

}

指令:

Cursor cur = getContentResolver().query(getIntent().getData(),

PROJECTION, null, null, null);

要求android代為尋找適合的ContentProvider來提供服務,並不刻意指定由DataProvider物件來擔任。只要合乎ConentProvider介面,且符合意圖條件的物件皆可以來為ac01物件提供服務。於是,ac01程式碼就不再直接呼叫DataProvider類別的函數了,而是呼叫ContentProvider介面所提供的函數。再來仔細看看DataProvider類別與ContentProvider介面的搭配情形:

/* ----- DataProvider.Java 程式碼 ------*/

package com.misoo.pkrr;

import android.content.ContentProvider;

import android.content.ContentValues;

import android.content.Context;

import android.database.Cursor;

import android.database.SQLException;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteOpenHelper;

import android.Net.Uri;

import android.util.Log;

public class DataProvider extends ContentProvider {

private static final String DATABASE_NAME = "StudNewDB";

private static final int DATABASE_VERSION = 2;

private static final String TABLE_NAME = "StudTable";

private static class DatabaseHelper extends SQLiteOpenHelper {

DatabaseHelper(Context context) {

super(context, DATABASE_NAME, null, DATABASE_VERSION); }

@Override public void onCreate(SQLiteDatabase db) {

db.execSQL("CREATE TABLE " + TABLE_NAME + " (" + "stud_no"

+ " TEXT," + "stud_name" + " TEXT" + ");");

String sql_1 = "insert into " + TABLE_NAME

+ " (stud_no, stud_name) values('S1001', 'Pam');";

String sql_2 = "insert into " + TABLE_NAME

+ " (stud_no, stud_name) values('S1002', 'Steve');";

String sql_3 = "insert into " + TABLE_NAME

+ " (stud_no, stud_name) values('S1003', 'John');";

try { db.execSQL(sql_1); db.execSQL(sql_2); db.execSQL(sql_3); }

catch (SQLException e) { Log.e("ERROR", e.toString()); }

}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}

}

// ---------------------------------------------------------------------------------

private DatabaseHelper mOpenHelper;

@Override public boolean onCreate() {

mOpenHelper = new DatabaseHelper(getContext()); return true; }

@Override public Cursor query(Uri uri, String[] projection, String selection,

String[] selectionArgs, String sortOrder) {

SQLiteDatabase db = mOpenHelper.getReadableDatabase();

Cursor c = db.query(TABLE_NAME, projection, null, null, null, null, null);

return c;

}

@Override public String getType(Uri uri) { return null; }

@Override public Uri insert(Uri uri, ContentValues initialValues) { return uri; }

@Override public int delete(Uri uri, String where, String[] whereArgs) { return 0; }

@Override public int update(Uri uri, ContentValues values, String where,

String[] whereArgs)

{ return 0; }

}

類別定義:

public class DataProvider extends ContentProvider {

// …..…..

}

DataProvider類別繼承ContentProvider父類別,也繼承了它的介面定義。ContentProvider介面定義了多個函數,主要包括:

l query()函數---- 它查詢出合乎某條件的資料。

l insert()函數---- 它將存入一筆新資料。

l delete()函數---- 它刪除合乎某條件的資料。

l update()函數---- 更新某些筆資料的內容。

在這個DataProvider類別裡,撰寫了query()函數內的指令,來實現query()介面,這個query()函數實際呼叫SQLite資料庫的功能。也就是說,ac01等應用程式透過ContentProvider介面間接呼叫到DataProvider的query()函數,然後此query()函數才使用SQLite的服務。

由於此範例的DataProvider已經是ContentProvider嫡系身份了,必須由Android來啟動它,而不是有ac01等應用程式來直接啟動它,所以必須在androidManifest.XML文檔裡給android一些指示,如下:

/* ----- androidManifest.XML 文檔 ------*/

 

package="com.misoo.pkrr"

android:versionCode="1"

android:versionName="1.0.0">

 

android:label="@string/app_name">

 

 


 

android:authoritIEs="com.misoo.provider.rx09-02">

 


這特別說明DataProvider是一個ContentProvider,於是android就會來啟動它。

上課講義摘錄之3: 實際演練android模擬器之操作
實際演練android模擬器之操作


l android的嫡系組件(first-class citizen)

Activity:敘述User使用此AP時會進行的一連串活動。

Intent Receiver:用以接收外來的事件通知(Notification)。

Service:非UI的幕後服務程式。

Content Provider:將資料儲存於檔案系統或資料庫(如SQLite或 Linter)裡。

l android的角色

android是在Windows或Linux上執行一個ARM-CPU模擬器,並在此模擬器上執行

Linux2.6.23. android是一個應用框架(Application Framework),執行於上述的模擬

環境裡。

l 從Windows XP環境進入android裡的Linux環境

使用XP環境的命令列模式,進入:\android-sdk-Windows-1.0_r1\tools\打入命令:

adb shell 就會出現#號,就進入Linux地盤了。

l adb是什麼

adb是Android裡的一個管理程式,稱為android Debug Bridge。儲存於

c:\android-sdk-Windows-1.0_r1\tools\裡的一個.exe程式。必需在命令列模式

裡執行。它能安裝.apk檔案、將檔案拷貝到模擬器裡等等。

l 如何載入android的 *.apk呢?

Step-1: 啟動Android的模擬器(以mouse點選c:\android-sdk-Windows-1.0_r1\tools\ 裡

的android圖像)。

Step-2: 拷貝*.apk檔案到c:\android-sdk-Windows-1.0_r1\tools\裡。

Step-3: 使用命令列模式,進入\tools\,然後執行 adb install *.apk。

此.apk就被存入Linux的\data\app\裡,並出現於模擬器畫面的.apk裡了。

(PS. Andorid應用程式編譯之後會產出一個.apk檔案,它是一個壓縮檔。)
l 如何移除*.apk呢?

使用命令列模式,進入c:\android-sdk-Windows-1.0_r1\tools\,然後,執行

adb shell rm *.apk。或者,執行adb shell打開一個Linux shell,再進入\data\app\,

執行#rm *.apk。

l 清除模擬器裡的資料(Wipe your emulator data)

隨著程式的執行,常常會留下一些資料在模擬器裡,如果你想清除掉它們,

可進入c:\android-sdk-Windows-1.0_r1\tools\裡,打入命令:emulator -wipe-data

來啟動模擬器。

l Kill-Server

如果發現 Eclipse與模擬器溝通不良(例如出現有* daemon not running. starting it

           now  * 的訊息時),可以關掉Eclipse,進入c:\android-sdk-Windows-1.0_r1\tools\裡,

打入命令:adb kill-server,再啟動Eclipse。

l adb功能

adb(Android Debug Bridge)是android提供的的Debug工具,它可以管理設備或手機

模擬器的狀態、更新模擬器中的應用程式碼、執行設備shell命令等。例如:adb

          install 、adb shell、#cd /data/app、#rm app.apk等。

---- 進入設備或模擬器的shell:adb shell就可以進入模擬器的shell環境中,這是

                Linux  Shell,可以執行各種Linux的命令,格式為:adb shell [command]

例如:

               adb shell  dmesg會列印出Linux的debug訊息。

---- 複製一個檔或目錄到模擬器上:adb push

---- 從模擬器上複製一個檔或目錄:adb pull 例如:adb pull /data/data/kk.XML

上課講義摘錄之4:android與Cross Compiler之關係

高煥堂談:android與Cross Compiler之關係
---- 在Ubuntu/Linux/X86 環境裡使用2007q3-51交叉編譯C程式,然後放入android裡執行。

l 何謂Cross compiler(交叉編譯器)?

Cross Compiler主要在資源較豐富的電腦上執行,而編譯出能在別的電腦上執行的目的碼(Object Code)。例如,當我們想寫個C程式,讓它能在Android手機裡跑。Android手機的ARM-CPU及記憶體容量都很小,我們無法在資源有限的android/ARM裡進行編輯及編譯C程式。可行的方法是:在X86 PC環境裏編輯C程式,然後使用Cross Compiler去編譯出適合ARM-CPU裡執行的目的碼。這稱為Cross Compiler。

l 安裝ARM GNU/Linux 交叉編譯器

在Ubuntu裡安裝交叉編譯器的步驟是:

Step-1. 在Ubuntu畫面上,直接上網:

clip_image002

Step-2. 選取2007q3-51版,並下載:

clip_image003

Step-3. 這會自動安裝於 /home/tom/arm-2007q3/裡。

Step-4. 這樣,交叉編譯器就安裝完成了。

l 使用Cross Compiler編譯C函數,放入android裡執行。

可先將.h和.c程式碼存於自訂的Proj_01檔案夾裡,如下:

clip_image004

l 開始進行交叉編譯C程式碼

接下來,對HalfAdder.c和 com_misoo_gx05_NativeJniAdder.c兩個程式檔,進行編譯,

將 產生.o的目的程式(Object Code)檔。

*** 編譯HalfAdder.c程式 ***

clip_image005

*** 編譯com_misoo_gx05_NativeJniAdder.c程式 ***

clip_image006

從畫面可看到他已經產出了兩個ARM-based的 .o 目的程式檔了。

l 連結出可在ARM上執行的 .so程式檔

對HalfAdder.o和 com_misoo_gx05_NativeJniAdder.o兩個目的程式檔,

進行連結而產生.so的共享程式檔案,使用下述命令:

clip_image007

l 將libNativeJniAdder.so共享程式檔拷貝並放置到android模擬器裡

例如,在Windows環境。

Step-1. 先將.so檔案拷貝到c:/android-sdk-Windows-1.0_r1/tools/裡。

Step-2. 啟動模擬器。

Step-3. 進入c:/android-sdk-Windows-1.0_r1/tools/,並使用adb push命令

將.so檔案,存入模擬器的/system/lib/裡。

clip_image008

l 撰寫主程式去呼叫這libNativeJniAdder.so共享程式

在android的Java程式可輕鬆地透過JNI去呼叫此.so程式庫。

也可以再利用Cross Compiler編譯一個C主函數(main())去呼叫它。

~ END ~

上課講義摘錄之5: 認識android Application


認識android 應用程式(Application)

---------------------------------------------------------------------------------------------------------------

PS.  別忘了....

       1.   高煥堂 11月台北 android 教育訓練課程

                        12~1月上海 android 教育訓練課程

       2.   下載 高煥堂 第1本android書籍的免費e-book

-----------------------------------------------------------------------------------------

整個應用程式都定義於androidManifest.XML裡,其宣告了其進入點(Entry Point)、通訊層級(Communication Layer)、授權(Permission),以及各個Activity和意圖(Intent)等。其中,有4種基礎組件,我們稱之為android的嫡系組件。

l Activity: android 應用程式的UI(User Interface)基本組件。

l Intent receiver: 可隨時被啟動來處理Intent,並執行其任務。

l Service: 非UI功能的幕後處理組件。

l Content provider: 跨程式的共享資料之儲存者。

如何添增圖片(Image)資源

圖片資源就直接將圖片檔(例如ok.jpg)拷貝到/res/drawable檔案夾裡。此時,Eclipse的Android插件(android Plug-In)會自動將一個新的ID值添加到R.java裡。所以R.Java檔案裡會多加了一行指令如下:

clip_image009

在應用程式碼將就由此ID值來取得這個圖片檔,並顯示或處理它。

如何定義XML畫面佈局(Layout)

剛才已經新增了一個圖片資源檔。此時,在定義畫面佈局的XML檔案裡,就可以引用它了。畫面佈局的XML檔都擺在/res/layout檔案夾裡,其中Eclipse的android插件已經誕生一個main.xml在那裡了。現在,你可利用Eclipse的File>New>File菜單選項來誕生新的畫面佈局XML檔案,例如:button_layout.xml。然後,以main.xml內容為底稿,將之拷貝到新的button_layout.XML裡。

clip_image010

將部分更改為如下:

clip_image011

在畫面佈局XML檔案裡,使用@drawable/就能輕鬆地引用/res檔案夾裡的資源了,例如上圖的android:src="@drawable/ok"。此外,layout_width和layout_height 則說明這個ImageButton顯示出來的大小(Size)。button_layout.XML也成為一項新的資源。所以在R.Java裡也會自動產生新的一行,如下:

clip_image012

同樣地,在應用程式碼裡也能隨時引用這個資源了,例如將ac01.Java裡的R.layout.main更改為R.layout.button_layout,如下:

clip_image013

此應用程式執行時,就引用到button_layout.XML資源而顯示於畫面上,如下:

clip_image014

~~ END ~~

上課講義摘錄之6:注意android是應用框架,不是一般OS平台
在上一節課程裡,特別強調應用框架的神祕力量,必須由android的設計人角度去看它。不一定要成為框架設計人,但從他的角度和觀點能深刻觀察框架的魅力的源頭。在本課程的第一本教科書<>裡(第1.5節),就提到常見的迷思:

1.5 框架與OS之關係:常見的迷思
1.5.1 迷思
許多人從空間角度去想像OS與應用框架之間的關係。的確,OS(如Linux或Windows)像木板床,應用框架像彈簧床墊,其擺在木版床上。而應用程式則像睡在床墊上的人。這個觀點是對的(如圖1-4所示)。 然而,許多人順勢推論他們之間的互動關係如下圖:

clip_image016

圖1-5 常見的迷思

乍看之下,似乎蠻合理的,其實是個迷思。請你換個角度,採取另一個觀點,如下圖,更容易體會框架的角色和涵意,此新觀點如下圖1-6所示。

回想一下,您寫傳統程式時,主控權掌握在程式手中,其決定如何呼叫庫存函數﹔就像棒球比賽的「投手」一樣。反之,使用框架時,您的程式則擔任「捕手」之角色。盼您在使用框架時,能有這種心理準備(Mindset) 。

clip_image017

圖1-6 較合理的觀點

上課講義摘錄之7: android裡的類別繼承及物件組合
在android裡定義了如下的類別繼承(Class Inheritance)體系:

clip_image018

還有如下的物件組合(Object Composition)關係:

clip_image019

VIEwGroup的子孫類別(如下圖的LinearLayout),也自然繼承了上圖的組合關係:

clip_image020

同樣地,VIEw的子孫類別也具有同樣的繼承,可推導出如下之組合關係:

clip_image021

這些是android已經提供的基類(Base Class)。

在這裡,話插一下,我在北京程序員雜誌上寫的<<基類與愚公移山>>一文裡,我稱之為『畚箕』。Android應用程式的開發者就如同挑畚箕的人,在中華歷史上,有個家喻戶曉的偉大人物就是『愚公』,它是挑畚箕的人,想把泰山的土一擔一擔挑去填北海。現在,我就來扮演愚公的角色,挑一擔(寫個android應用程式)給你看看,但是請你不要叫我愚公就是。此外,我這個超級愚公還可以一根扁擔挑3個畚箕呢!!

首先建立一個android Project:

clip_image022

我這個愚公希望手機畫面出現如下:

clip_image023

在畫面上輸入一個字串,並按下時,就在畫面title區輸出了該字串:

clip_image024

現在開始寫程式了,拿著一根扁擔(Layout)和兩三個畚箕(一個EditText、和兩個Button)。

程式碼如下:

package com.misoo.pkaz;

import android.app.Activity;

import android.graphics.Color;

import android.os.Bundle;

import android.view.VIEw;

import android.view.VIEw.OnClickListener;

import android.widget.Button;

import android.widget.EditText;

import android.widget.LinearLayout;

public class ac01 extends Activity implements OnClickListener {

private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT;

private final int FP = LinearLayout.LayoutParams.FILL_PARENT;

private Button btn, btn2;

private EditText et;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

this.show_layout();

}

public void show_layout(){

LinearLayout layout = new LinearLayout(this);

layout.setOrIEntation(LinearLayout.VERTICAL);

et = new EditText(this);

LinearLayout.LayoutParams param =

new LinearLayout.LayoutParams(FP, WC);

layout.addVIEw(et, param);

btn = new Button(this);

LinearLayout.LayoutParams param2 =

new LinearLayout.LayoutParams(WC, WC);

param2.topMargin = 5;

btn.setText("OK");

btn.setBackgroundResource(R.drawable.x_blue3);

btn.setOnClickListener(this);

layout.addVIEw(btn, param2);

btn2 = new Button(this);

btn2.setText("Exit");

btn2.setTextColor(Color.RED);

btn2.setBackgroundResource(R.drawable.x_gray3);

btn2.setOnClickListener(this);

layout.addVIEw(btn2, param2);

setContentVIEw(layout);

}

public void onClick(VIEw v) {

if(v == btn)

setTitle(et.getText());

else if(v == btn2)

finish();

}

}

透過layout扁擔的addVIEw()函數就將畚箕一個一個挑起來了。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved