Android平台架構及特性
Android系統的底層是建立在Linux系統之上,改平台由操作系統、中間件、用戶界面和應用軟件四層組成,它采用一種被稱為軟件疊層(Software Stack)的方式進行構建。
好處:這種軟件疊層結構使得層與層互相分離,明確各層的分工,這種分工保證了層與層之間的低耦合,當下層內或者層下發生改變時,上層應用程序無需任何改變。
下圖顯示Android系統的體系結構:
1.應用程序層(Application)
Android平台不僅僅是操作系統,也包含了許多應用程序,諸如SMS短信客戶端程序、電話撥號程序、圖片瀏覽器、Web瀏覽器等應用程序。這些應用程序都是用Java語言編寫的,並且這些應用程序都是可以被開發人員開發的其他應用程序所替換,這點不同於其他手機操作系統固化在系統內部的系統軟件,更加靈活和個性化。我們編寫的主要是這一層上的應用程序。
2.應用程序架構層(Application Framework)
應用程序框架層是我們從事Android開發的基礎,很多核心應用程序也是通過這一層來實現其核心功能的,該層簡化了組件的重用,開發人員可以直接使用其提供的組件來進行快速的應用程序開發,也可以通過繼承而實現個性化的拓展。Android應用程序框架提供了大量的API供開發者使用。
a) Activity Manager(活動管理器)
管理各個應用程序生命周期以及通常的導航回退功能
b) Window Manager(窗口管理器)
管理所有的窗口程序
c) Content Provider(內容提供器)
使得不同應用程序之間存取或者分享數據
d) View System(視圖系統)
構建應用程序的基本組件
e) Notification Manager(通告管理器)
使得應用程序可以在狀態欄中顯示自定義的提示信息
f) Package Manager(包管理器)
Android系統內的程序管理
g)Telephony Manager(電話管理器)
管理所有的移動設備功能
h)Resource Manager(資源管理器)
提供應用程序使用的各種非代碼資源,如本地化字符串、圖片、布局文件、顏色文件等
i)Location Manager(位置管理器)
提供位置服務
j)XMPP Service(XMPP服務)
提供Google Talk服務
3.系統運行庫層:
1)函數庫(Libraries)
函數是應用程序框架的支撐,是連接應用程序框架層與Linux內核層的重要紐帶。一般來說,Android應用開發者不能直接調用這套C/C++庫集,但可以通過上面的應用程序框架來調用這些庫。
下面列出一些核心庫:
a)系統C庫( Libc):
從BSD繼承來的標准C系統函數庫,專門為基於embedded linux的設備定制。
b)Surface Manager:
執行多個應用程序時候,負責管理顯示與存取操作間的互動,另外也負責2D繪圖與3D繪圖進行顯示合成.
c) SGL
底層的2D圖形渲染引擎
d) SSL
在Andorid上通信過程中實現握手
e) Media Framework
多媒體庫,基於PacketVideo OpenCore;支持多種常用的音頻、視頻格式錄制和回放,編碼格式包括MPEG4、MP3、H.264、AAC、ARM。
f) WebKit:
一套網頁瀏覽器的軟件引擎
g) OpenGL|ES:
根據OpenGL ES 1.0API標准實現的3D繪圖函數庫
h) SQLite:
小型的關系型數據庫引擎
2)Android運行時(Android Runtime):
Android應用程序時采用Java語言編寫,程序在Android運行時中執行,其運行時分為核心庫和Dalvik虛擬機兩部分。
@ 核心庫
核心庫提供了Java語言API中的大多數功能,同時也包含了Android的一些核心API,如android.os、android.net、android.media等等。
@ Dalvik虛擬機
Dalvik虛擬機非常適合在移動終端上使用,相對於在PC或者服務器上運行的虛擬機而言,Dalvik虛擬機不需要很快的CPU計算速度和大量的內存空間,它主要有以下兩個特點:
(1)運行專有的.dex文件。
專有的.dex文件減少了.class文件中的冗余信息,而且會把.class文件整合到一個文件中,從而提高了運行性能;而且DX工具還會對.dex文件進行一些性能上的優化。
(2)基於寄存器實現.
大多數虛擬機包括JVM都是基於棧的,而Dalvik虛擬機則是基於寄存器的。一般來說基於寄存器的虛擬機具有更好的性能表現,但在硬件通用性上略差。
JVM和Dalvik的區別:由於Android應用程序的編寫語言是java,因此有人會把它們搞混。但實際上Dalvik並未遵守JVM規范,兩者也不兼容。
JVM運行的是java字節碼(通常就是.class文件),但Dalvik運行的是其專有的dex(Dalvik Executable)文件。
JVM直接從.class文件或者JAR包中加載字節碼后運行;而Dalvik則無法直接從.class文件或者JAR包中加載字節碼,他需要將應用程序的所有的.class文件編譯成.dex文件,Dalvik則運行該.dex文件。
2.Linux內核(Linux kernel)
Android系統建立在Linux2.6之上,Linux內核提供了安全性、內存管理、進程管理、網絡協議棧和驅動模型等核心系統業務,除此之外,Linux內核也是系統硬件和軟件疊層之間的抽象層。
Android開發--Activity生命周期回顧理解
Activity和Servlet一樣,都用了回調機制。我們通過類比servlet來學習Activity。當一個servlet開發出來之后,該servlet運行於Web服務器中。服務器何時創建servlet的實例,何時調用servlet的方法向用戶生成響應,程序員無法控制,這種回調由服務器自行決定。Activity也一樣,被開發出來,開發者只要在AndroidManifest.xml文件配置該Activity即可。至於該Activity何時被實例化,它的方法何時被調用,對開發者來說完全是透明的。
當開發者開發一個Servlet時,根據不同的需求場景,可能需要選擇性的的實現如下方法:
- init(servletConfig config)
- destroy()
- doGet(HttpServletRequest req,HttpServletResponse resp)
- doPost(HttpServletRequest req,HttpServletResponse resp)
- sevice(HttpServletRequest req,HttpServletResponse resp
- 當把Servlet部署到Web應用中之后,Web服務器將會在特定的時刻,調用該Servlet上面的各種方法---這種調用就被稱為回調。
Activity的回到機制與此類似,當Activity被部署到Android應用之后,隨着應用程序的運行,Activity會不斷的在不同的狀態進行切換,該activity中特定的方法就會被回調-----開發者就可以選擇性的重寫這些方法來加入業務相關的處理。Android運行過程的不同狀態被稱為生命周期。
Android的生命周期:當activity處於Android的應用中的運行時,它的活動狀態由Android運行時以Activity棧的形式管理。當前活動的Activity位於棧頂。
Android的生命周期演示:android大致經過如下四個狀態:
- 活動狀態:當前Activity位於前台,用戶可見,可以獲得焦點。
- 暫停狀態:其他Activity位於前台,該Activity依然可見,只是不能獲得焦點。
- 停止狀態:該Activity不可見,失去焦點
- 銷毀裝填:該activity結束,或者activity所在的Dalvik進程被結束。
下面是官方API所提供的生命周期圖:
下面使用代碼親自測下Android的生命周期,測完就明白了:
package com.lp.ecjtu.activitydemo1; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.widget.EditText; public class MainActivity extends Activity { private static final String TAG = "MainActivity"; private EditText editText; //創建Activity被回調 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); editText = (EditText) findViewById(R.id.editText); Log.e(TAG, "Start onCreate ========="); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } //啟動Activity被回調 @Override protected void onStart() { // TODO Auto-generated method stub super.onStart(); Log.e(TAG, "Start onStart ========="); } //重新啟動Activity被回調 @Override protected void onRestart() { // TODO Auto-generated method stub super.onRestart(); Log.e(TAG, "Start onRestart ========="); } //恢復Activty被回調 @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); Log.e(TAG, "Start onResume ========="); } //暫停Activity被回調 @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); Log.e(TAG, "start onPause============="); } //停止Activity被回調 @Override protected void onStop() { // TODO Auto-generated method stub super.onStop(); Log.e(TAG, "start onStop============="); } //銷毀Activity被回調 @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.e(TAG, "start onDestroy============="); } }
運行上面的代碼:我們打開應用程序時回調了OnCreate()-->onStart()-->onResume()方法。在LogCat窗口可以看到:
Back鍵:當我們按返回鍵的時候這個應用程序或者Activity將結束,依次回調了OnPause()-->onStop()-->Ondestroy()方法:在LogCat窗口可以看到:
HOME鍵:當我們正在打游戲的時候,突然來了條短信,我們想看短息,按HOME鍵,然后打開短信的應用,當我們按HOME鍵的時候Activity先后執行了OnPause()-->OnStop方法,在LogCat窗口可以看到:
而我們看完短息在啟動應用的時候:會執行OnRestart()-->onStart-->OnResume方法。在LogCat窗口可以看到:
通過上面的操作,想必我們都對Android Activity生命周期有了深刻的了解,我們就可以在開發Activity的時候,選擇性的重寫生命周期的方法來解決業務上的一些需求。
例如:下面的這個例子,當我們在看視屏的時候,或者在注冊的時候,剛好填完用戶的注冊信息,不小心按到了Home鍵,當我們在進入應用程序的時候,發現之前填的注冊信息全沒了,這時候我們就要哭了,說明這個應用程序做的比較垃圾。正常情況下,我們之前填寫的注冊信息還在,也就是說和我們按Home鍵之前的狀態是一致的。
為了理解,我們用一個小例子說明問題:
在XML代碼代碼中增加EditText:
<LinearLayout 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="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" android:orientation="vertical"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello_Activity" /> <EditText android:id="@+id/editText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:ems="10" /> </LinearLayout>
java代碼不變,運行程序,在EditText中輸入peter,
然后按HOME鍵,在次啟動MainActivity,發現之前輸入的內容沒了。
這顯然不是正常的應用程序,我們都會哭的。那么就需要我們隊生命周期非常了解了,當我們按Home鍵的時候,Activity回調了onPause-->OnStop()方法,再次進入應用程序的時候回調了OnRestart-->OnStart-->onResume()方法,說明我們只要在onPause()和OnRestart方法里面做處理既可以保存之前的狀態:下面看代碼
package com.lp.ecjtu.activitydemo1; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.widget.EditText; public class MainActivity extends Activity { private static final String TAG = "MainActivity"; private EditText editText; //定義一個String字符串用於存放用戶輸入的字符串 private String userString; //創建Activity被回調 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); editText = (EditText) findViewById(R.id.editText); Log.e(TAG, "Start onCreate ========="); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } //啟動Activity被回調 @Override protected void onStart() { // TODO Auto-generated method stub super.onStart(); Log.e(TAG, "Start onStart ========="); } //重新啟動Activity被回調 @Override protected void onRestart() { // TODO Auto-generated method stub super.onRestart(); //再次啟動應用時,把先前用戶輸入的值重新設置EditText editText.setText(userString); Log.e(TAG, "Start onRestart ========="); } //恢復Activty被回調 @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); Log.e(TAG, "Start onResume ========="); } //暫停Activity被回調 @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); //按home鍵的時候,保存用戶輸入的字符串信息。 userString = editText.getText().toString(); Log.e(TAG, "start onPause============="); } //停止Activity被回調 @Override protected void onStop() { // TODO Auto-generated method stub super.onStop(); Log.e(TAG, "start onStop============="); } //銷毀Activity被回調 @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.e(TAG, "start onDestroy============="); } }
重新啟動app,按home鍵,在進入應用程序OK了,看下面的圖:
總結:理解生命周期的關鍵是,我們可以在開發過程選擇性的重寫生命周期中的方法,解決一些實際問題,這才是關鍵,學以致用!
Notification定義與應用
首先要明白一個概念:
Intent 與 PendingIntent 的區別:
Intent:是意圖,即告訴系統我要干什么,然后做Intent應該做的事,而intent是消息的內容
PendingIntent 為Intent的包裝,這里是啟動Intent的描述,PendingIntent.getActivity 返回的PendingIntent表示,此PendingIntent實例中的Intent是用於啟動 Activity 的Intent。PendingIntent.getActivity的參數依次為:Context,發送者的請求碼(可以填0),用於系統發送的 Intent,標志位。
包裝Intent,intent是我們直接使用startActivity,startService,senbBroadcast啟動某項工作的內容,而某些時候我們並不能直接調用 startActivity,startService,senbBroadcast,而是系統或者程序達到某一條件才發送intent,例如下面要學習的Notification,當用戶點擊Notification之后,由系統發出一條activity的intent。如果我們不用某種方法告訴系統的話,系統是不知道是使用startActivity(),startService還是senbBroadcast...來啟動intent的,因此需要PendingIntent,對intent進行包裝,調用getActivity()方法。
前面我們說過,NotificationManager是所有Notification的大管家,它的主要職責是加入/移除Notification。
NotificationManager類
通過獲取系統服務來獲取該對象:
NotificationManager mNotificationManager = (NotificationManager)getSystemServic(Context.NOTIFICATION_SERVICE) ;
常用方法:
public void cancelAll() 移除所有通知 (只是針對當前Context下的Notification)
public void cancel(int id) 移除標記為id的通知 (只是針對當前Context下的所有Notification)
public voidnotify(String tag ,int id, Notification notification) 將通知加入狀態欄, 標簽為tag,標記為id
public void notify(int id, Notification notification) 將通知加入狀態欄,,標記為id
一般來說, 一個Notification應該傳送的消息包括:
1 、一個狀態條圖標
2、在拉伸的狀態欄窗口中顯示額外的信息和啟動一個Application的Intent
3、閃燈或LED
4、電話震動
在狀態欄(Status Bar)中,通知主要有兩類(使用FLAG_標記,后面講解到):
1、正在運行的事件
2、通知事件
Notification類介紹:
常量:
//表示發送一個Notification的所攜帶的效果
DEFAULT_ALL 使用默認字段
DEFAULT_LIGHTS 默認閃光
DEFAULT_SOUND 默認聲音(uri,指向路徑)
DEFAULT_VIRATE 默認震動,后來得知需要添加震動權限VIBRATE: android.permission.VIBRATE
其中震動和閃光都需要在AndroidManifest.xml中添加權限
<!-- 添加操作閃光燈的權限 -->
<uses-permission android:name="android.permission.VIBRATE"/>
<!-- 添加操作震動的權限 -->
<uses-permission android:name="android.permission.FLASHLIGHT"/>
PS:以上的效果常量可以累加,即通過mNotifaction.defaults |=DEFAULT_SOUND (有些效果只能在真機上才有,比如震動)
//設置Flag位
FLAG_AUTO_CANCEL 該通知能被狀態欄的清除按鈕給清除掉
FLAG_NO_CLEAR 該通知不能被狀態欄的清除按鈕給清除掉
FLAG_ONGOING_EVENT 通知放置在正在運行
常用字段
contentView 通知在狀態欄的顯示View(自定義,具體請看下文) ,常與contentIntent配合使用,點擊該通知后,
即觸發contentIntent
contentIntent 設置PendingIntent對象,點擊該通知時發送該Intent
flags 設置flag位,例如FLAG_NO_CLEAR等
defaults 添加效果
tickerText 顯示在狀態欄中的文字
when 發送此通知的時間戳
icon 設置圖標
常用方法介紹:
void setLatestEventInfo(Context context , CharSequence contentTitle,CharSequence contentText,PendingIntent contentIntent)
功能: 顯示在拉伸狀態欄中的Notification屬性,點擊后將發送PendingIntent對象。
參數: context 上下文環境
contentTitle 狀態欄中的大標題
contentText 狀態欄中的小標題
contentIntent 點擊后將發送PendingIntent對象
另外的就是Notification的幾步不同構造方法了,其構造方法的參數含義如上,請參考SDK 。
注意,關於通知(Notification)的顯示類型有兩種:
第一種:使用默認的形式(效果圖如上顯示)。具體使用是為Notification對象設置setLatestEventInfo()方法(該方法內部創建
了默認的RemoteViews對象,因此為默認顯示),否則程序會報異常 ;
第二種: 使用自定義的View(RemoteViews對象)顯示(功能更加自由,強大),具體方法為設置Notification對象的
contentView 屬性和contentIntent屬性 ,此時不需要設置setLatestEventInfo()方法。具體使用方法如下:
第一種:例子:main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<Button android:id="@+id/showButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="showNotification"/>
<Button android:id="@+id/cancelButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="cancelNotification"/>
</LinearLayout>
Intent.FLAG_ACTIVITY_CLEAR_TOP :如果在當前Task中,有要啟動的Activity,那么把該Acitivity之前的所有Activity都關掉,並把此Activity置前以避免創建Activity的實例
Intent.FLAG_ACTIVITY_NEW_TASK :系統會檢查當前所有已創建的Task中是否有該要啟動的Activity的Task,若有,則在該Task上創建Activity,若沒有則新建具有該 Activity屬性的Task,並在該新建的Task上創建Activity。更多請參見 “ (轉載)Android下Affinities和Task ”
NotificationDemoActivity.java
package com.lp.ecjtu;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class NotificationDemoActivity extends Activity implements OnClickListener {
/** Called when the activity is first created. */
private Context mContext;
private Button showButton,cancelButton;
private Notification mNotification;
private NotificationManager mNotificationManager;
private static final int NOTIFICATION_ID = 0x0001;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setupViews();
}
private void setupViews() {
mContext = NotificationDemoActivity.this;
showButton = (Button) findViewById(R.id.showButton);
cancelButton = (Button) findViewById(R.id.cancelButton);
mNotification = new Notification(R.drawable.ic_launcher, "this is Notification", System.currentTimeMillis());
//將使用 默認的聲音來提醒用戶,添加震動,后來得知需要添加震動權限 : Virbate Permission
//mNotification.defaults = Notification.DEFAULT_SOUND;
//mNotification.defaults = Notification.DEFAULT_VIBRATE;
mNotification.defaults = Notification.DEFAULT_LIGHTS;
mNotificationManager = (NotificationManager) this.getSystemService(NOTIFICATION_SERVICE);
showButton.setOnClickListener(this);
cancelButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v==showButton){
Intent intent = new Intent(mContext, NotificationDemoActivity.class);
//這里需要設置Intent.FLAG_ACTIVITY_NEW_TASK屬性
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK );
PendingIntent mContentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
//這里必需要用setLatestEventInfo(上下文,標題,內容,PendingIntent)不然會報錯.
mNotification.setLatestEventInfo(mContext, "10000", "您的話費不足,請充值!", mContentIntent);
//這里發送通知,消息ID,通知對象
mNotificationManager.notify(NOTIFICATION_ID,mNotification);
}else if(v==cancelButton){
mNotificationManager.cancel(NOTIFICATION_ID);
}
}
}
別忘了添加震動的權限:
<!-- 添加操作閃光燈的權限 -->
<uses-permission android:name="android.permission.VIBRATE"/>
效果圖:
第二種:自定義view
代碼如下:
view.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<ImageView android:id="@+id/image" android:layout_width="wrap_content"
android:layout_height="fill_parent" />
<TextView android:id="@+id/text" android:layout_width="wrap_content"
android:layout_toRightOf="@+id/image"
android:layout_height="wrap_content" android:textColor="#000" />
<ProgressBar android:id="@+id/progress_horizontal"
style="?android:attr/progressBarStyleHorizontal"
android:layout_below="@+id/text"
android:layout_toRightOf="@+id/image"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:max="100" android:progress="50" android:secondaryProgress="75" />
</RelativeLayout >
java 代碼
NotificationRomoteViewActivity.java
package com.lp.ecjtu;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.RemoteViews;
public class NotificationRomoteViewActivity extends Activity {
private Notification mNotification;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
showViewNotification();
}
private void showViewNotification() {
// TODO Auto-generated method stub
mNotification = new Notification(R.drawable.ic_launcher, "自定義View", System.currentTimeMillis()+10000);
//1.創建一個自定義布局
//2.在程序代碼中使用RemoteViews的方法來定義image和text。然后把RemoteViews對象傳到contentView字段
mNotification.flags = Notification.FLAG_INSISTENT;
RemoteViews remoteViews = new RemoteViews(this.getPackageName(), R.layout.view);//自定義Notification
remoteViews.setImageViewResource(R.id.image, R.drawable.ic_launcher);
remoteViews.setTextViewText(R.id.text, "自定義View");
mNotification.contentView = remoteViews;
// 3、為Notification的contentIntent字段定義一個Intent(注意,使用自定義View不需要setLatestEventInfo()方法)
//點擊啟動setting
PendingIntent mPendingIntent = PendingIntent.getActivity(NotificationRomoteViewActivity.this,
0, new Intent("android.settings.SETTINGS"), 0);
mNotification.contentIntent = mPendingIntent;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, mNotification);
}
}
Android handler組件等
一、 基礎篇
需要掌握的技能如下:
1、熟練掌握基本控件以及容器控件的使用 ;
常用的基本控件有:Button 、TextView、EditText、ListView等
常用的容器控件有:FrameLayout、LinearLayout、RelativeLayout等
2、熟練掌握相關監聽器的注冊和使用:
常用監聽器有: OnClickListener、OnLongClickListener、OnItemClickListener等
3、掌握Log的使用以及分析方法 ;
4、掌握Activity、Service的生命周期和使用方法 ;
5、掌握BroadcastReceiver(廣播)的接受和使用 ;
6、掌握Intent以及IntentFilter的使用 ;
7、基本掌握數據庫方面知識,包括SQLiteDatabase以及ContentProvider的使用方法
除此之外,我們必須得掌握adb shell 的使用方法,常用功能有:
adb pull 、 adb push 、 adb remount 指令等
由於shell類同於Linux shell ,我們還得掌握基本的Linux指令等,例如cat、cd 等 。
知識獲取渠道主要為:
Android SDK以及網上大牛的博客。
附: 關於基礎知識的介紹,國內的一些書籍質量真是相當差勁,味同嚼蠟。強烈不建議在此階段買書籍。
這時,您已經小有所成了,能夠基本掌握Android開發了。這兒,我推薦一個手把手講解Android項目的視頻:
zhengping老師講解的,強烈推薦。
視頻下載地址:http://www.verycd.com/topics/2847310/
百度視屏:http://blog.csdn.net/coolszy/
實踐出真知。這個階段,你可以自己編寫一些小Demo了,幫助自己在更深層次發展了。
PS:我通過看了Mars老師視頻后,編寫了一個簡易的音樂播放器Demo, 感覺挺有成就感的。
通過前面的學習,我們可以成功進入第二個階段了。
二、 提高篇
需要掌握的技能如下:
1、掌握Canvas類的使用-- 如何繪圖
2、掌握消息通信機制---Handler相關類的使用以及原理
3、掌握Context類以及實現原理
4、掌握View樹的繪制流程 。 View繪制流程很重要,掌握它就基本上掌握了Android核心之一了。
4.1、掌握觸摸事件的分發流程--- onInterceptTouchEvent以及onTouchEvent方法流程
4.2、掌握相關監聽器的調用機制。例如OnClickListener監聽時怎么調用的?
4.3、能夠編寫自定義View以及ViewGroup
5、理解Binder機制----Binder機制很重要,Android的進程間通信都是靠它完成的。掌握它,才能夠好的完成接下
來的學習。
6、基本掌握ActivityManagerService類的使用,主要掌握的知識點包括如下:
6.1、startActivity()流程,即啟動一個Activity的流程 ;
6.2、startService()流程,即啟動一個Service的流程 ;
7、基本掌握PackageManagerService類的使用,主要掌握的知識點包括如下:
7.1、開機時如何解析所有已安裝應用程序的Apk包的信息
7.2、Intent以及IntentFilter的匹配規則以及解析過程
8、基本掌握View添加至窗口的過程---即WindowManagerIml 、WindowManagerService類的用法
知識渠道:
Android引進的Handler類,可以說是Runnable和Activity交互的橋梁,所有的UI線程要負責View的創建並且維護它,例如更新某個TextView顯示的內容,都必須在主線程中去做,我們不能直接在UI線程中創建子線程,要利用消息機制:handler,如下就是handler的簡單工作原理圖:
下面是一個原理圖:
UI線程中去創建子線程,要利用消息機制:handler,如下就是handler的簡單工作原理圖:
我們只要在run方法中發送Message,而在Handler里,通過不同的Message執行不同的任務。
package com.lp.ecjtu;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
public class HandlerTestActivity extends Activity {
//title為setTitle方法提供變量,這里為了方便我設置成了int型
private int title=0;
private Handler mhandler = new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO 接收消息並且去更新UI線程上的控件內容
switch (msg.what) {
case 1:
updateTitle();
break;
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Timer timer = new Timer();
timer.schedule(new Mytask(), 1,500);
}
private class Mytask extends TimerTask{
@Override
public void run() {
//子線程中通過handler發送消息給handler接收,由handler去更新title
Message msg = new Message();
msg.what=1;
mhandler.sendMessage(msg);
}
}
protected void updateTitle() {
setTitle("welcome to ecjtu:"+title);
title++;
}
}
為什么要使用Handlers?
因為,我們當我們的主線程隊列,如果處理一個消息超過5秒,android 就會拋出一個 ANP(無響應)的消息,所以,我們需要把一些要處理比較長的消息,放在一個單獨線程里面處理,把處理以后的結果,返回給主線程運行,就需要用的 Handler來進行線程建的通信,關系如下圖;
ProgressBar
下面介紹兩種進度條分別是圓形進度條和長形進度條的代表:
下面我們看一下兩都皆有之的Android自帶的瀏覽器的效果圖如下:
第一步:新建一個Android工程命名為ProgressBarDemo.
第二步:修改main.xml代碼如下(圓形進度條和長形進度條這里樣式不同用系統自帶的):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<ProgressBar
android:id="@+id/rectangleProgressBar"
style="?android:attr/progressBarStyleHorizontal" lp_style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone"
/>
<ProgressBar
android:id="@+id/circleProgressBar"
style="?android:attr/progressBarStyleLarge" lp_style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
/>
<Button android:id="@+id/button"
android:text="Show ProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<Button android:id="@+id/button"
android:text="Show ProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
第三步:修改ProgressBarDemo.java代碼如下:
package com.lp.ecjtu;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
public class ProgressBarDemoActivity extends Activity {
/** Called when the activity is first created. */
private ProgressBar rectangleProgressBar,circleProgressBar;
private Button mButton;
protected static final int STOP = 0x10000;
protected static final int NEXT = 0x10001;
private int iCount = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
rectangleProgressBar = (ProgressBar) findViewById(R.id.rectangleProgressBar);
circleProgressBar = (ProgressBar) findViewById(R.id.circleProgressBar);
mButton = (Button) findViewById(R.id.button);
rectangleProgressBar.setIndeterminate(false);//設置不確定模式下
circleProgressBar.setIndeterminate(false);
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
rectangleProgressBar.setVisibility(View.VISIBLE);
circleProgressBar.setVisibility(View.VISIBLE);
rectangleProgressBar.setMax(100);
rectangleProgressBar.setProgress(0);
circleProgressBar.setProgress(0);
//創建一個此線程,每秒步長為5,到100%時停止
Thread mThread = new Thread(new Runnable() {
@Override
public void run() {
//循環
for(int i=0;i<10;i++){
try {
iCount = (i+1)*10;//步長為10進行增加,直到100
Thread.sleep(1000);//1秒
//當i=9的時候進度為100,停止
if(i==9){
Message msg = new Message();
msg.what=STOP;
mHandler.sendMessage(msg);
break;
}else{
Message msg = new Message();
msg.what=NEXT;
mHandler.sendMessage(msg);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//
}
}
});
mThread.start();
}
});
}
//定義一個Handler
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case STOP:
rectangleProgressBar.setVisibility(View.GONE);
circleProgressBar.setVisibility(View.GONE);
Thread.currentThread().interrupt();//中斷線程
break;
case NEXT:
if(!Thread.currentThread().isInterrupted()){//不中斷
rectangleProgressBar.setProgress(iCount);//設置進度條的狀態
circleProgressBar.setProgress(iCount);
}
break;
}
}
};
}
效果圖:
Android——橫屏和豎屏的切換,以及明文密碼的顯示
查看API文檔: android.content.pm.ActivityInfo
在手機的使用中,我們要根據不同的需求來改變屏幕的顯示方向,一般在瀏覽信息時是豎屏,在玩游戲的時候就要切換到橫屏。在Android中要想完成屏幕方向的切換,需要Activity類的一些方法的支持。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
showPass =(CheckBox)
this
.findViewById(R.id.showpass);
showPass.setOnCheckedChangeListener(
new
OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if
(isChecked ==
true
) {
// 如果復選框被選中,文本框內容可見
LoginGalleryActivity.
this
.userpass
.setTransformationMethod(HideReturnsTransformationMethod
.getInstance());
}
else
{
//如果復選框沒有被選中,文本框內容不可見
LoginGalleryActivity.
this
.userpass
.setTransformationMethod(PasswordTransformationMethod
.getInstance());
}
}
});
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
chageScrean = (Button)
this
.findViewById(R.id.screanChange);
//改變屏幕顯示為橫屏或豎屏
chageScrean.setOnClickListener(
new
OnClickListener() {
@Override
public void onClick(View v) {
if
(ShowGallery.
this
.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
chageScrean.setText(
"錯誤,無法改變屏幕方向"
);
}
else
if
(ShowGallery.
this
.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
ShowGallery.
this
.setRequestedOrientation(1);
//設置當期屏幕為豎屏
}
else
if
(ShowGallery.
this
.getRequestedOrientation()==ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
{
ShowGallery.
this
.setRequestedOrientation(0);
//設置當前屏幕為橫屏
}
}
});
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//系統設置改變時觸發該方法,還需要在Manifest.xml文件中進行配置
@Override
public void onConfigurationChanged(Configuration newConfig) {
if
(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE)
{
ShowGallery.
this
.chageScrean.setText(
"改變屏幕方向為豎屏(當前為橫屏)"
);
}
else
if
(newConfig.orientation==Configuration.ORIENTATION_PORTRAIT)
{
ShowGallery.
this
.chageScrean.setText(
"改變屏幕方向為橫屏(當前為豎屏)"
);
}
super
.onConfigurationChanged(newConfig);
}
|
下面是橫豎屏測試的程序:
我們這里主要是運用了getRequestedOrientation(),和setRequestedorientation()兩個方法.但是要利用這兩個方法必須先在AndroidManiefst.xml設置一下屏幕方屬性,不然程序將不能正常的工作.
Step 1:我們建立一個Android工程,命名為ChangeScreemOrientationDemoActivity.
Step 2:設計UI,打開main.xml,將其代碼修改如下,我們這里只是增加了一個按鈕,其他什么都沒有動.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<Button android:id="@+id/press"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="press me change screem orientation"/>
</LinearLayout>
Step 3:設計主程序ChangeScreemOrientationDemoActivity.java,修改其代碼如下:
package com.lp.ecjtu;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class ChangeScreemOrientationDemoActivity extends Activity {
/** Called when the activity is first created. */
private Button pressBtn;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
pressBtn = (Button) findViewById(R.id.press);
pressBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//如果是豎屏,改為橫屏
if(getRequestedOrientation()== ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE){
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
}
//如果是橫屏,改為豎屏
else if(getRequestedOrientation()==ActivityInfo.SCREEN_ORIENTATION_PORTRAIT){
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
});
}
}
Step 4:在AndroidManifest.xml文件里設置默認方向,不然程序不能正常工作哦.代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.test"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".ChangeOrientationDemo"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>
現在我們上網幾乎都會用百度或者谷歌搜索信息,當我們在輸入框里輸入一兩個字后,就會自動提示我們想要的信息,這種效果在Android 里是如何實現的呢? 事實上,Android 的AutoCompleteTextView Widget ,只要搭配ArrayAdapter 就能設計同類似Google 搜索提示的效果.
本例子先在Layout 當中布局一個AutoCompleteTextView Widget ,然后通過預先設置好的字符串數組,將此字符串數組放入ArrayAdapter ,最后利用AutoCompleteTextView.setAdapter 方法,就可以讓AutoCompleteTextView 具有自動提示的功能.例如,只要輸入ab ,就會自動帶出包含ab 的所有字符串列表.
package com.lp.ecjtu;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
public class AutoCompleteTextViewActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//定義字符串數組,作為提示的文本
String[] books = new String[]{
"瘋狂Java講義",
"瘋狂Ajax講義",
"瘋狂XML講義",
"瘋狂Workflow講義"
};
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//創建一個ArrayAdapter,封裝數組
ArrayAdapter<String> aa = new ArrayAdapter<String>(
this,
android.R.layout.simple_dropdown_item_1line,
books);
//獲得AutoCompleteTextView組件
AutoCompleteTextView actv = (AutoCompleteTextView)
findViewById(R.id.auto);
//設置Adapter
actv.setAdapter(aa);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- 定義一個自動完成文本框
,指定輸入一個字符后進行提示 -->
<AutoCompleteTextView
android:id="@+id/auto"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:completionHint="請選擇您喜歡的圖書:"
android:dropDownHorizontalOffset="20dp"
android:completionThreshold="1"
/>
</LinearLayout>
java Android SDK安裝與環境變量配置以及開發第一個Android程序
JAVA的安裝與環境變量的配置
1、先下載JAVA,並且安裝。 下載地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk-7u3- download-1501626.html
2、安裝的時候,最好別改安裝路徑,默認路徑一直點下一步即可!
3、安裝完成后,接下來就是配置java環境變量了。
4、打開計算機屬性,點擊高級系統設置
5、選擇“高級”-“環境變量”
二、 關於JDK 安裝,以及Java環境的設置 1、下載JDK1.6,選擇對應的安裝路徑
2、配置相應的Java 環境變量
A、屬性名稱:JAVA_HOME 屬性值:C:\Program Files\Java\jdk1.6.0_02 B、屬性名稱:PATH 屬性值:;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin C、屬性名稱:CLASSPATH 屬性值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar 要加.表示當前路徑,另外,%JAVA_HOME%就是引用前面指定的JAVA_HOME |
6. 關於環境變量是否安裝成功的測試
“開始”->;“運行”,鍵入“cmd”;
鍵入命令命令,出現畫面,說明環境變量配置成功:
A、java -version;
B、java;
C、javac;
=================華==麗==的==分==割==線======================
Android SDK的安裝與環境變量配置
一、配置Andriod環境變量
1、下載Android SDK,點擊安裝,直接默認路徑即可! 下載地址:http://developer.android.com/sdk/index.html
2、默認路徑安裝后,安裝完成,開始配置環境變量。
3、打開計算機屬性——高級系統設置——環境變量(如上文)
4、新建一個環境變量,變量名:ANDROID_HOME,變量值:D:\Program Files\android-sdk-windows(以你安裝目錄為准,確認里面有tools和add-ons等多個文件夾),點擊確認。
5、在用戶變量PATH后面加上變量值;%ANDROID_HOME%\platform-tools;點擊確認即可。 在系統變量path中添加;D:\Program Files\android-sdk-windows\tools
6、Android SDK配置完成,接下來驗證配置是否成功。
7、點擊運行——輸入cmd——回車——輸入adb——回車,如果出現一堆英文,如下圖所示,即表示配置成功,在輸入Android,啟動Android SDK Manager。
二、下載和安裝Andriod SDK
1.SDK下載
去http://www.android.com/ 在那個頁面中有developers鏈接,點擊后鏈接到developer.android.com網站上,如下圖,下載相應的sdk版本就是了,由於我的電腦的操作系統是windows,所以我直接在選擇了android-sdk_r12-windows(圖中有標識).
下載完成后,解壓后得到android-sdk-windows文件夾,該文件夾包含如下文件結構:
(1)add-ons:該目錄存放額外的附件軟件。剛解壓時該目錄為空。
(2)platforms:該目錄存放不同版本的Android版本。剛解壓時該目錄為空。
(3)tools:該目錄存放大量的Android開發,調試工具
(4)SDK Manager.exe:該程序就是Andriod SDK管理器。
(5)AVD Manager.exe:該程序就是Andoid虛擬設備。
(6)docs:該文件夾存放了Android SDK開發文件和API文檔等
(7)platforms-tools:該文件夾存放Android平台和相關工具
(8)samples:該文件夾存放不同的Android平台和示例程序。
2.安裝sdk開發使用的相應的包
運行之后安裝了sdkmanager,然后sdkmanager啟動后會去android倉庫去取還未安裝的包的信息,如下圖(由於我的系統中已安 裝好,因此每個包前面都是綠色打勾的),為了偷懶,我直接就選擇了accept all,將所有的包安裝上.其實,如果自己對android整個體系比較了解的話,可以選擇只安裝自己需要用到的部分.
三、在eclipes中配置和安裝ADT(Android Development Tools)
1.安裝ADT
首先的下載和安裝Eclipse,登陸http://www.eclipse.org站點,下載Eclipse IDE for java EE Devlelopers的最新版本,然后安裝。
ADT是eclipse的一個插件,如同cdt和jdt一個道理.要開發android程序,至少要有個cde(集成開發環境).而android官方推 薦的是eclipse.並且為eclipse下開發android准備了ADT這樣一個插件.有了這個插件,就能比較方便的開發android程序了.
然后點擊 Help->Install new Software,在彈出的窗口中點擊add按鈕
name:AndroidADT或者其它任何名字。
Location:https://dl-ssl.google.com/android/eclipse/ ,如果網絡有問題的話,可以試下如下地址:http://dl-ssl.google.com/android/eclipse/
然后點擊:ok
勾選Development tools,然后開始安裝ADT插件。在Eclipse安裝其它插件也一樣,這里采用的是在線安裝ADT插件,在網絡好的情況下,可能需要一段時間,耐心等待。
2.配置ADT
點擊eclipse菜單中的window,選擇"Preferences...",在彈出窗口中選擇android sdk的安裝位置:這里是D:\Program Files\android-sdk-windows,配置如下圖:
四.創建AVD(Android 虛擬機)
在eclipse菜單點擊window,選着AVD Manager彈出:
然后點擊 new在彈出的AVD中填寫虛擬機的名稱name:Android2.2,選着Android平台的版本Target:Android2.2 - API Level 8,設置虛擬的SD卡的大小,這里size是512MiB,可以設置彈出的虛擬器外觀的大小:200*350
配置好后點擊Edit AVD,最后點擊Start啟動
如圖:
五、在eclipes中開發第一個Android應用
大致需要如下3步:
(1)創建一個Android項目.
(2)在XML布局文件中定義應用程序的用戶解界面
(3)在java代碼中編寫業務實現
詳細步驟如下:
1.通過在Eclipes下面"File->Android Project"
點擊next:
選着2.3.3在點擊next:
點擊Finish。
第一個項目創建成功。
2.在Android項目的layout目錄下面有一個main.xml文件,該文件用於定義Android的用戶界面:
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/show"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<Button
android:id="@+id/ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="點擊我" />
</LinearLayout>
解
說明UI組件上幾個通用的屬性:
android:id:該屬性指定了該控件的唯一標識,在java程序中可以通過findViewById("id")來獲取指定的Android界面組件。
android:layout_width:指定該組件的寬度。如果屬性為fill_parent,說明該組件與父組件具有相同的寬度;如果屬性為wrap_content,則說明該組件的高度取於它的內容——基本能包裹它的內容即可。
思考:為什么把用戶界面放在XML文檔中定義,這樣可以讓XML文檔專門負責用戶UI設置,而java程序專門負責業務實現,這樣可以較低程序耦合性。大家要接受Android這種優秀的設計,其實這種思想在學習三大框架時候就接觸過了。
3.Android項目的src目錄是Android項目的源代碼:
HelloWorldActivity.java:
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class HelloWorldActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//設置使用main文件定義的布局
setContentView(R.layout.main);
//獲取UI界面中ID為R.id.ok的按鈕
Button bn = (Button) findViewById(R.id.ok);
//為按鈕綁定一個單擊事件的監聽器
bn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//獲取UI界面中ID為R.id.show的文本框
final TextView show = (TextView) findViewById(R.id.show);
//改變文本框的內容
show.setText("hello world!");
}
});
}
上面這個程序只做了三件事情:
(1)設置該Activity使用main文件定義的界面布局作為用戶界面。
(2)獲取ID為R.id.ok的按鈕
(3)為第二部獲得的按鈕綁定事件監聽器--在事件監聽器處理方法中改變ID為R.id.show的文本的內容。
完整的Android應用就開發完成了。