2010-03-05 傳智播客—Android(六)Activity、請(qǐng)求碼與結(jié)果碼、Intent、廣播、服務(wù)
Posted on 2010-03-07 10:42 長(zhǎng)城 閱讀(6147) 評(píng)論(0) 編輯 收藏今日課程內(nèi)容較多,我們的課上到晚7:20。
一、創(chuàng)建新的Activity
在進(jìn)行桌面開發(fā)時(shí),我們可以通過一個(gè)窗口上的控件事件打開另一個(gè)新的窗口。在WEB應(yīng)用開發(fā)時(shí),我們也可以通過一個(gè)連接打開一個(gè)新的頁(yè)面。通過添加新的窗口開完善或增強(qiáng)軟件的功能,那么在Android應(yīng)用開發(fā)中,我們應(yīng)該怎樣打開新的Activity?
1.添加新的Activity(創(chuàng)建Android工程:MainActivity)
1).新建一個(gè)繼承自Activity類的類NewActivity
package com.changcheng.activity;
import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button;
public class NewActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.new_activity); // 獲取按鈕并未按鈕添加事件 Button button = (Button) this.findViewById(R.id.newa_bt_close); button.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) { NewActivity.this.finish(); } }); }
} |
2).AndroidManifest.xml文件中添加
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.changcheng.activity" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- 新的Activity --> <activity android:name=".NewActivity" android:label="@string/new_activity" /> </application> <uses-sdk android:minSdkVersion="7" /> </manifest> |
3).newactivity.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/newa_activity" />
<!-- 關(guān)閉按鈕 --> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/newa_bt_close" android:id="@+id/newa_bt_close" /> </LinearLayout> |
4).strings.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World, MainActivity!</string> <string name="app_name">創(chuàng)建新的Activity</string> <string name="bt_open_new_activity">打開新的Activity</string> <string name="new_activity">新的Activity</string> <string name="newa_activity">新的Activity</string> <string name="newa_bt_close">關(guān)閉</string> </resources> |
5).MainActivity.java
package com.changcheng.activity;
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button;
public class MainActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 獲取按鈕,并為按鈕添加單擊的事件 Button button = (Button) this.findViewById(R.id.bte_open_new_activity); button.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) { // 創(chuàng)建顯式意圖 Intent intent = new Intent(MainActivity.this, NewActivity.class); // 打開新的Activity startActivity(intent); } });
} } |
二、Activity之間傳遞參數(shù)
在桌面程序中窗口之間,我們可以通過構(gòu)造參數(shù)或全局變量來傳遞數(shù)據(jù)。在WEB應(yīng)用中,我們可以通過域(request\response\session...)在頁(yè)面之間傳遞數(shù)據(jù)。那如何在Android的Activity之間傳遞參數(shù)呢?
通過intent.putExtra方法為意圖添加參數(shù),打開新的Activity后可以通過this.getIntent().getStringExtra()等方法獲取參數(shù)。
三、請(qǐng)求碼與結(jié)果碼
在上面的程序中我們通過startActivity(intent)打開一個(gè)新的Activity,Android為了減少組件間的耦合,所以使用了Intent(Intent在下面會(huì)有介紹)。所以我們?cè)趏nClick事件打開的新Activity不與主Activity在一個(gè)線程中。但是,當(dāng)新Activity被關(guān)閉后,會(huì)觸發(fā)主Activity的onActivityResult事件。
1.請(qǐng)求碼
在一個(gè)業(yè)務(wù)中可能在兩個(gè)按鈕被單擊事件中打開同一個(gè)Activity,但我們?cè)趏nActivityResult事件中如何判斷是哪個(gè)按鈕打開了新的Activity?請(qǐng)求碼就是為解決這個(gè)問題的,那么我們打開新的Activity時(shí)應(yīng)該使用startActivityForResult(intent, 1);。其中的第二個(gè)參數(shù)就是請(qǐng)求碼。
onActivityResult事件:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // TODO Auto-generated method stub super.onActivityResult(requestCode, resultCode, data); } |
在onactivityResult事件中,通過判斷requestCode更可知道被關(guān)閉Activity是通過哪個(gè)位置打開的。
2.結(jié)果碼
在一個(gè)業(yè)務(wù)中可能要打開多個(gè)不同的Activity,那關(guān)閉Activity時(shí)在onactivityResult事件中我們?nèi)绾沃狸P(guān)閉的是哪一個(gè)Activity呢?結(jié)果碼就是為解決這個(gè)問題的,那么我們打開新的Activity時(shí)應(yīng)該使用setResult(2, intent);或在關(guān)閉Activity前調(diào)用ActivityObj.setResult(2);。其中的第一個(gè)參數(shù)就是結(jié)果碼。
在onactivityResult事件中,通過判斷resultCode更可知道是哪個(gè)Activity被關(guān)閉了。
三、Intent意圖
Android基本的設(shè)計(jì)理念是鼓勵(lì)減少組件間的耦合,因此Android提供了Intent (意圖) ,Intent提供了一種通用的消息系統(tǒng),它允許在你的應(yīng)用程序與其它的應(yīng)用程序間傳遞Intent來執(zhí)行動(dòng)作和產(chǎn)生事件。使用Intent可以激活A(yù)ndroid應(yīng)用的三個(gè)核心組件:活動(dòng)、服務(wù)和廣播接收器。
Intent可以劃分成顯式意圖和隱式意圖:
1).顯式意圖:調(diào)用Intent.setComponent()或Intent.setClass()方法指定了組件名或類對(duì)象的Intent為顯式意圖,顯式意圖明確指定了Intent應(yīng)該傳遞給哪個(gè)組件。比如我們上邊的打開新的Activity程序。
2).隱式意圖:沒有調(diào)用Intent.setComponent()或Intent.setClass()方法指定組件名或類對(duì)象的Intent為隱式意圖。 Android系統(tǒng)會(huì)根據(jù)隱式意圖中設(shè)置的動(dòng)作(action)、類別(category)、數(shù)據(jù)(URI和數(shù)據(jù)類型)找到最合適的組件來處理這個(gè)意圖。通過隱式意圖打開新的Activity:
AndroidManifest.xml:
<!-- 新的Activity --> <activity android:name=".NewActivity" android:label="@string/new_activity"> <intent-filter> <action android:name="com.changcheng.activity.NewActivity"/> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> |
MainActivity:
@Override public void onClick(View v) { // 創(chuàng)建顯式意圖 Intent intent = new Intent("com.changcheng.activity.NewActivity"); //Intent intent = new Intent(MainActivity.this, NewActivity.class); // 打開新的Activity startActivity(intent);// 發(fā)送Intent時(shí),意圖里相當(dāng)于有一個(gè)類別:android.intent.category.DEFAULT } |
在intent過濾器中還可以添加多個(gè)action和category,還可以添加data。具體使用在此就不做總結(jié)了,可以查看相關(guān)資料或幫助文檔。
3).顯式意圖與隱式意圖的應(yīng)用場(chǎng)景:
在項(xiàng)目?jī)?nèi)部建議使用顯式意圖。
在應(yīng)用與應(yīng)用之間只能使用隱式意圖。
四、Activity的生命周期
Activity有三個(gè)狀態(tài):
當(dāng)它在屏幕前臺(tái)時(shí)(位于當(dāng)前任務(wù)堆棧的頂部),它是激活或運(yùn)行狀態(tài)。它就是響應(yīng)用戶操作的Activity。
當(dāng)它失去焦點(diǎn)但仍然對(duì)用戶可見時(shí),它處于暫停狀態(tài)。即在它之上有另外一個(gè)Activity。這個(gè)Activity也許是透明的,或者沒有完全覆蓋全屏,所以被暫停的Activity仍對(duì)用戶可見。暫停的Activity仍然是存活狀態(tài)(它保留著所有的狀態(tài)和成員信息并保持和窗口管理器的連接),但系統(tǒng)處于極低內(nèi)存時(shí)仍然可以殺死這個(gè)Activity。
完全被另一個(gè)Activity覆蓋時(shí)則處于停止?fàn)顟B(tài)。它仍然保留所有的狀態(tài)和成員信息。然而對(duì)用戶是不可見的,所以它的窗口將被隱藏,如果其它地方需要內(nèi)存,則系統(tǒng)經(jīng)常會(huì)殺死這個(gè)Activity。
當(dāng)Activity從一種狀態(tài)轉(zhuǎn)變到另一種狀態(tài)時(shí),會(huì)調(diào)用以下保護(hù)方法來通知這種變化:
void onCreate(Bundle savedInstanceState)
void onStart()
void onRestart()
void onResume()
void onPause()
void onStop()
void onDestroy()
這七個(gè)事件定義了Activity的完整生命周期。實(shí)現(xiàn)這些事件方法可以幫助我們監(jiān)視其中的三個(gè)嵌套生命周期循環(huán):
1).Activity的完整生命周期自第一次調(diào)用onCreate()開始,直至調(diào)用onDestroy()為止。Activity在onCreate()中設(shè)置所有“全局”狀態(tài)以完成初始化,而在onDestroy()中釋放所有系統(tǒng)資源。例如,如果Activity有一個(gè)線程在后臺(tái)運(yùn)行從網(wǎng)絡(luò)上下載數(shù)據(jù),它會(huì)在onCreate()創(chuàng)建線程,而在 onDestroy()銷毀線程。
2).Activity的可視生命周期自onStart()調(diào)用開始直到相應(yīng)的onStop()調(diào)用結(jié)束。在此期間,用戶可以在屏幕上看到Activity,盡管它也許并不是位于前臺(tái)或者也不與用戶進(jìn)行交互。在這兩個(gè)方法之間,我們可以保留用來向用戶顯示這個(gè)Activity所需的資源。例如,當(dāng)用戶不再看見我們顯示的內(nèi)容時(shí),我們可以在onStart()中注冊(cè)一個(gè)BroadcastReceiver來監(jiān)控會(huì)影響UI的變化,而在onStop()中來注消。onStart() 和 onStop() 方法可以隨著應(yīng)用程序是否為用戶可見而被多次調(diào)用。
3).Activity的前臺(tái)生命周期自onResume()調(diào)用起,至相應(yīng)的onPause()調(diào)用為止。在此期間,Activity位于前臺(tái)最上面并與用戶進(jìn)行交互。Activity會(huì)經(jīng)常在暫停和恢復(fù)之間進(jìn)行狀態(tài)轉(zhuǎn)換——例如當(dāng)設(shè)備轉(zhuǎn)入休眠狀態(tài)或者有新的Activity啟動(dòng)時(shí),將調(diào)用onPause() 方法。當(dāng)Activity獲得結(jié)果或者接收到新的Intent時(shí)會(huì)調(diào)用onResume() 方法。關(guān)于前臺(tái)生命周期循環(huán)的例子請(qǐng)見PPT下方備注欄。
五、廣播接收者
廣播接收者(BroadcastReceiver)用于異步接收廣播Intent,廣播Intent的發(fā)送是通過調(diào)用Context.sendBroadcast()、Context.sendOrderedBroadcast()或者Context.sendStickyBroadcast()來實(shí)現(xiàn)的。通常一個(gè)廣播Intent可以被訂閱了此Intent的多個(gè)廣播接收者所接收,廣播接收者和JMS中的Topic消息接收者很相似。要實(shí)現(xiàn)一個(gè)廣播接收者方法如下:
1).繼承BroadcastReceiver,并重寫onReceive()方法。
2).訂閱感興趣的廣播Intent,訂閱方法有兩種:
· 使用代碼進(jìn)行訂閱:
IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
IncomingSMSReceiver receiver = new IncomingSMSReceiver();
registerReceiver(receiver, filter);
· 在AndroidManifest.xml文件中的<application>節(jié)點(diǎn)里進(jìn)行訂閱:
<receiver android:name=".IncomingSMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
通常一個(gè)BroadcastReceiver對(duì)象的生命周期不超過5秒,所以在BroadcastReceiver里不能做一些比較耗時(shí)的操作,如果需要完成一項(xiàng)比較耗時(shí)的工作,可以通過發(fā)送Intent給Activity或Service,由Activity或Service來完成。
六、服務(wù)
Android中的服務(wù)和windows中的服務(wù)是類似的東西,服務(wù)一般沒有用戶操作界面,它運(yùn)行于系統(tǒng)中不容易被用戶發(fā)覺,可以使用它開發(fā)如監(jiān)控之類的程序。服務(wù)的開發(fā)比較簡(jiǎn)單,如下:
1.繼承Service類
public class SMSService extends Service { }
2.在AndroidManifest.xml文件中的<application>節(jié)點(diǎn)里對(duì)服務(wù)進(jìn)行配置:
<service android:name=".SMSService" />
服務(wù)不能自己運(yùn)行,需要通過調(diào)用Context.startService()或Context.bindService()方法啟動(dòng)服務(wù)。這兩個(gè)方法都可以啟動(dòng)Service,但是它們的使用場(chǎng)合有所不同。使用startService()方法啟用服務(wù),調(diào)用者與服務(wù)之間沒有關(guān)連,即使調(diào)用者退出了,服務(wù)仍然運(yùn)行。使用bindService()方法啟用服務(wù),調(diào)用者與服務(wù)綁定在了一起,調(diào)用者一旦退出,服務(wù)也就終止。
如果打算采用Context.startService()方法啟動(dòng)服務(wù),在服務(wù)未被創(chuàng)建時(shí),系統(tǒng)會(huì)先調(diào)用服務(wù)的onCreate()方法,接著調(diào)用onStart()方法。如果調(diào)用startService()方法前服務(wù)已經(jīng)被創(chuàng)建,多次調(diào)用startService()方法并不會(huì)導(dǎo)致多次創(chuàng)建服務(wù),但會(huì)導(dǎo)致多次調(diào)用onStart()方法。采用startService()方法啟動(dòng)的服務(wù),只能調(diào)用Context.stopService()方法結(jié)束服務(wù),服務(wù)結(jié)束時(shí)會(huì)調(diào)用onDestroy()方法。
如果打算采用Context.bindService()方法啟動(dòng)服務(wù),在服務(wù)未被創(chuàng)建時(shí),系統(tǒng)會(huì)先調(diào)用服務(wù)的onCreate()方法,接著調(diào)用onBind()方法。這個(gè)時(shí)候調(diào)用者和服務(wù)綁定在一起,調(diào)用者退出了,系統(tǒng)就會(huì)先調(diào)用服務(wù)的onUnbind()方法,接著調(diào)用onDestroy()方法。如果調(diào)用bindService()方法前服務(wù)已經(jīng)被綁定,多次調(diào)用bindService()方法并不會(huì)導(dǎo)致多次創(chuàng)建服務(wù)及綁定(也就是說onCreate()和onBind()方法并不會(huì)被多次調(diào)用)。如果調(diào)用者希望與正在綁定的服務(wù)解除綁定,可以調(diào)用unbindService()方法,調(diào)用該方法也會(huì)導(dǎo)致系統(tǒng)調(diào)用服務(wù)的onUnbind()-->onDestroy()方法。