Intent 是一個動作與內容的集合。Intent 像是一串網址,傳送到系統並意圖靠其他 Activity 來處理網址中所指定的動作跟內容。 前一章中,我們已學過獨立的 Activity。Android 使用 Intent 來完成在螢幕間切換的動作。Intent 包含 Activity 間切換所需的動作、分類、傳送資料等訊息,就像是 Activity 之間的宅急便一樣。 因此當我們得在 Activity 之間交換資料時,需要先了解 Intent 的用法。 Intent 可以分為兩種類型:「現成的 Intent」與「自訂的 Intent」。使用現成的 Intent 的例子,可以參考「初見 Intent」一章。在 Android 清單中作設定時,我們還可以使用 IntentFilter,來過濾和找尋對應的 Intent。而一般開發者在程式中所自行撰寫的 Intent,則是透過自訂 Intent 來做很多事情。比如切換 Activity、在其間傳遞各式的資料。 要完成在 Activity 之間透過 Intent 傳送資訊的動作,可以分成「傳遞資訊」與「接收資訊」兩部分。 使用 Intent 傳遞資訊上一章的範例中,我們新增了一個 Report Activity 頁面,但是還沒有為新頁面填入實值內容。在本章中我們會完成將 BMI 應用程式從一個頁面改寫成為兩個頁面:「輸入頁面」(原本的 Bmi Activity),與「結果頁面」(Report Activity)的應用程式。「輸入頁面」從介面上取得身高、體重值,透過傳送 Intent,將值攜帶到「結果頁面」。「結果頁面」從 Intent 中取出其攜帶的身高、體重值,用這兩個參數來產生 BMI 報告結果。 打開 「src/com/demo/android/bmi/Bmi.java」,修改「Button.OnClickListener」 函式: 1 private Button.OnClickListener calcBMI = new Button.OnClickListener()
2 {
3 public void onClick(View v)
4 {
5 //Switch to report page
6 Intent intent = new Intent();
7 intent.setClass(Bmi.this, Report.class);
8 Bundle bundle = new Bundle();
9 bundle.putString("KEY_HEIGHT", field_height.getText().toString());
10 bundle.putString("KEY_WEIGHT", field_weight.getText().toString());
11 intent.putExtras(bundle);
12 startActivity(intent);
13 }
14 };講解Intent intent = new Intent(); intent.setClass(Bmi.this, Report.class); ... startActivity(intent); 是的,如果你真的有學懂上一章的內容,那麼你可能會發現:我們準備講解的這段程式碼主體,與上一章中所提到的程式碼其實一模一樣。這段程式碼的作用是透過 Intent 通知系統(Android 框架):我們將要從 Bmi Activity 這個頁面(輸入頁面)前往 Report Activity 頁面(結果頁面)。如果把我們多加的用來附加資料的程式碼拿掉,這段程式碼即原來獨立的 Activity 的程式碼。 Bundle bundle = new Bundle(); ... intent.putExtras(bundle); 相依的 Activity 與獨立的 Activity 不同之處,就在於相依的 Activity 會附帶傳送額外資訊到新的 Activity。這些額外資訊都是靠著 Intent 物件來攜帶的。 傳送 intent 時,我們可以在其上附加一些訊息,比如說本例中我們從輸入介面中取出了的身高、體重值,要將身高、體重值傳送給 Report Activity 後作計算。這些附加在 Intent 上的訊息都儲存在 Bundle 物件中。透過「intent.putExtras(bundle)」敘述,我們將「bundle」 物件附加在 Intent 上,隨著 Intent 送出而送出。 bundle.putString("KEY_HEIGHT", field_height.getText().toString());
bundle.putString("KEY_WEIGHT", field_weight.getText().toString());這段程式是實際用來附加資料的程式碼。將使用者輸入的身高、體重值,儲存到 bundle 物件中。 Bundle 其實是一種特別定義的映射(map)型別。「KEY_HEIGHT」、「KEY_WEIGHT」是我們為儲存在 bundle 物件中的身高、體重值,所指定的「識別符號」。在這邊,我們直接把身高、體重值都儲存成字串。因為整個程式都是我們控制,到時候在接收的 Activity 一端,再透過「KEY_HEIGHT」、「KEY_WEIGHT」這兩個「識別符號」來取得實際的身高、體重值。讀出的值也是字串,等值讀出來以後,再去做型別轉換就好了。當然你也可以直接把身高、體重值存成數字。 Bundle 型別額外提供了很多 API。在傳送 Intent 時,使用 Bundle 型別的物件來攜帶資料,相當方便。 使用 Intent 接收資訊在使用 Intent 接收資訊前,我們先來加上「Report」這個 Activity 的介面。 相關工作打開「res/values/report.xml」檔案,修改如下: <?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="report_title">BMI 報告</string>
<string name="report_back">前一頁</string>
</resources>打開「res/layout/report.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:id="@+id/result"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=""
/>
<TextView android:id="@+id/suggest"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=""
/>
<Button android:id="@+id/report_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/report_back"
/>
</LinearLayout>這時打開 Eclipse 開發環境的 layout 檢視,或是執行模擬器,我們可以看到一個「前一頁」按鈕,按鈕前其實還有兩個沒有內容的 TextView 介面元件,下一節中我們將在「Report」這個 Activity 中取得從「Bmi」Activity 傳過來的身高體重資料,根據這些資料產生報告資訊。 在 Activity 中解開資訊用作接收 Intent,透過 Intent 攜帶的資訊來計算出 BMI 值的「src/com/demo/android/bmi/Report.java」完整程式碼如下: 1 package com.demo.android.bmi;
2
3 import java.text.DecimalFormat;
4 import android.app.Activity;
5 import android.os.Bundle;
6 import android.view.View;
7 import android.widget.Button;
8 import android.widget.TextView;
9
10 public class Report extends Activity {
11 /** Called when the activity is first created. */
12 @Override
13 public void onCreate(Bundle savedInstanceState) {
14 super.onCreate(savedInstanceState);
15 setContentView(R.layout.report);
16 findViews();
17 showResults();
18 setListensers();
19 }
20
21 private Button button_back;
22 private TextView view_result;
23 private TextView view_suggest;
24
25 private void findViews()
26 {
27 button_back = (Button) findViewById(R.id.report_back);
28 view_result = (TextView) findViewById(R.id.result);
29 view_suggest = (TextView) findViewById(R.id.suggest);
30 }
31
32 //Listen for button clicks
33 private void setListensers() {
34 button_back.setOnClickListener(backMain);
35 }
36
37 private Button.OnClickListener backMain = new Button.OnClickListener()
38 {
39 public void onClick(View v)
40 {
41 // Close this Activity
42 Report.this.finish();
43 }
44 };
45
46 private void showResults() {
47 DecimalFormat nf = new DecimalFormat("0.00");
48
49 Bundle bundle = this.getIntent().getExtras();
50 double height = Double.parseDouble(bundle.getString("KEY_HEIGHT"))/100;
51 double weight = Double.parseDouble(bundle.getString("KEY_WEIGHT"));
52 double BMI = weight / (height * height);
53 view_result.setText(getString(R.string.bmi_result) +nf.format(BMI));
54
55 //Give health advice
56 if(BMI>25){
57 view_suggest.setText(R.string.advice_heavy);
58 }else if(BMI<20){
59 view_suggest.setText(R.string.advice_light);
60 }else{
61 view_suggest.setText(R.string.advice_average);
62 }
63
64 }
65 }講解整個程式的架構我們在「完成 BMI 程式」與「重構程式」兩章中已經詳細說明過了。 Bundle bundle = this.getIntent().getExtras(); 當我們透過 Intent 傳到新的 Activity 後,只要使用 Activity.getIntent() 函數,就可以得到傳來的 Intent 物件。然後使用「getExtras」函式,就能取得附加在 Intent 上的 bundle 物件。 double height = Double.parseDouble(bundle.getString("KEY_HEIGHT"))/100;
double weight = Double.parseDouble(bundle.getString("KEY_WEIGHT"));在當前的 Activity 取得了 bundle 物件後,我們可以透過指定儲存在 bundle 物件中的身高、體重值的識別符號「KEY_HEIGHT」、「KEY_WEIGHT」來取出身高、體重值的資料。由於我們傳參數值來時,所使用的是是字串格式,所以我們在此得做個型別轉換,將參數從字串轉換成雙倍精度浮點數(Double)型別。 private Button.OnClickListener backMain = new Button.OnClickListener()
{
public void onClick(View v)
{
// Close this Activity
Report.this.finish();
}
};當按下 backMain 按鈕元件後,結束 Report Activity,顯示出原本的 Bmi Activity。 不透過 Bundle 交換資訊使用 Intent 傳遞資訊時,我們看到可以用「setClass」方法來指定要傳送到的 Activity。我們也可以使用類似的「setString」、「setInt」方法來指定要透過 Intent 附帶傳送的參數。 在使用 Intent 接收資訊時,我們再使用「this.getIntent().getData()」方法就能取到參數了。「getData」方法取到的參數一般是字串型態的。 若事先已經知道傳來參數的型別,還可以用比「getData」方法更精確的「getString」、「getInt」等方法來取得參數值。 不過既然有好用的 Bundle 類別可用,為什麼要自己把事情弄得複雜呢? < 加入新 Activity | 回目錄 | 記錄與偵錯 > 對於本章,您還期望知道什麼樣的內容呢?請在下方提出建議! | |
通俗易懂。
加油,期待下一章节。
继续学习
chengen0402: 請參考 http://code.google.com/p/androidbmi/source/browse/tags/BMI07/src/com/demo/android/bmi/Report.java 原始碼,看看跟你寫的有什麼不一樣
另外我想問個問題 本章的try..catch功能已經拿掉 如果什麼都不打,就會強制關閉,沒有除錯的功能
如果要使用try..catch 要加在什麼地方呢?
我有試過把它加在report.java裡,是可以正常執行,不過這樣的順序很奇怪 也有試著把它放在各種地方,不過問題似乎是出在 startActivity(intent);在把資料傳過去的過程中出問題,而這卻不在try的範圍內(?)
a19870..., 你已經講到問題的答案了。既然是出在 startActivity(intent);在把資料傳過去的過程就出問題,那麼這些 error check 的動作在前一個 Activity 傳送時就應該先處理掉。
謝謝g大跟a大 a大的方法把main.xml部分的 <TextView? android:id="@+id/suggest" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="" /> <Button android:id="@+id/report_back" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/report_back" /> 拿掉即可執行 也解決了我意外結束的問題
按照本节内容我全部复制到我的程序里面,没有error check 我发现一个现象就是 当不填写信息 体重和身高都是空的时候 提示程序错误,但我点击强制关闭后 程序还是跑到填写身高体重的那一页,这里的关系我不是很理解,为什么会出现这样的情况 请老大们指点???????
我照這個Sample code 執行到最後,Report 會出現,但是也會出現 Force Close。後來在 Debug 模式下看到
ActivityThread?.performStopActivityInner(ActivityThread?$ActivityRecord?, ActivityThread?$StopInfo?, boolean) line: 2905 這裡出問題
還有一個 Source not found 的訊息
不知有沒有人碰過?
coloer, 因為當前 Activity (Report) 出錯關閉, 所以回到上一個可以跑的 Activity (BMI), 具體參考 LifeCycle 那章
當我新增一個activity,畫面也確實轉過去,但是,一旦我在新的activity的onCreat執行任何方法(),就會出現The application BMI(process com.demo.android.bmi)has stopped unexpectedly,畫面已轉,在新的activity建立方法,並執行卻不行,why
shusia19, 忘了在 AndroidManifest.xml 加上新 activity 標籤?
gasolin您好,我已找到問題點了,感謝您的回覆,只是因為個人的疏乎,浪費您寶貴的時間,實在抱歉。在新的layout report.xml tag標錯了所導致
請問一下, 我在report.xml中使用中文的caption, 結果在 Layout的頁籤上無法顯示(顯示亂碼), 雖然在模擬器上面是沒有問題的, 但是總是美中不足, 請問有解嗎
換一台 Mac 或 Ubuntu 都可以解.....不過這可能不是你要的答案 :p
@jesse.chan.tw 你可以試試修改模擬器的語言設置。
您好,想請問一下, 如果我自行開發了兩個App(A與B),想要從App A中開啟App B,App B結束之後回到App A,這樣是可行的嗎?可以用intent來實現嗎?謝謝.
可以, 用 startActivityForResult 來呼叫, 很抱歉目前只有實體書上講到...
請問您指的是書本裡的第34章嗎?我有您的書,可是這一章裡面的兩個activity是屬於同一個package.如果我寫的兩個app屬於不同的package,仍然可以用這個方法嗎?謝謝.
是可以的, 例如呼叫 Barcode Scanner 也可以這樣用。
但是new Intent()的時候要傳入被開啟的activity的class name, 但是如果兩個class屬於不同的package,App A就會不認得App B的class name, 請問要如何解決這個問題呢? 不好意思,因為是初學者,所以問題很多.
剛開始接觸Android的開發,如果問題很糟的話,敬請見諒!! 請教一下,如果從service直接fire up一個application,並透過intent的傳遞給予該application一個初始值。 要如何實做呢??又,要如何在該application裡判斷傳遞的intent是否正確成功呢?? 謝謝
这样Report Activity就没有Bmi Activity的Menu选单,如果想在Report Activity也加入Menu选单,能否先定义一个更基础的类来继承Activity类,同时编写好Menu选单代码后,Bmi Activity和Report Activity再来继承它,妥否?谢谢!
Menu 選單也可以用 xml 定義
gasolin先生,您好! 冒昧一問,似乎Intent已經不提供「setString、setInt」等方法了?
--引用-- 使用 Intent 傳遞資訊時,我們看到可以用「setClass」方法來指定要傳送到的 Activity。我們也可以使用類似的「setString」、「setInt」方法來指定要透過 Intent 附帶傳送的參數。
請自行參照 http://developer.android.com/intl/zh-TW/reference/android/content/Intent.html
bundle.putString("KEY_HEIGHT", field_height.getText().toString()); bundle.putString("KEY_WEIGHT", field_weight.getText().toString()); 要改為 bundle.putString("KEY_HEIGHT", fieldheight.getText().toString()); bundle.putString("KEY_WEIGHT", fieldweight.getText().toString());
發現了一個不好除錯的小問題 就是在xml檔如果打錯..譬如 <TextView android:id="@+id/..... 打成 <TextView android="@+id/..... 還滿難發現的XD
此外感謝gasolin大的無償教學
假如我當前有個 pulic void class A extends B 由於 B 不是 Activity ,當我需要在 class A 執行類似 Oncreate 等等動作時該怎麼做呢?
gasolin您好 我想要問一下關於假如第二個頁面他是繼承 MapActivity? 而不是Activity,該如何使用Intent來轉換頁面?
我試過若兩個都是extends Activity,兩個的頁面轉換是正常的,今天我測試了一下建立一個繼承Activity,裡面就只有一個按鍵,按下去後會到第二版課本第37章的地圖範例,按下去後出現強制關閉了,是否因為不是繼承Activity的關係??
多半是因為沒有在AndroidManifest裡面宣告這個新activity吧?
我有在AndroidManifest加入新的activity了,我自己試過如果兩個都是extends Activity 可以正常切換... 而這邊它繼承MapActivity?就不成功了。
everything goes well,thx so much. 这个案例需要学习者自己动手加Report.xml;而xml无语法检查,如果稍不注意,运行时android就会报错。 we should be careful.
請問一下上面的xpecial.tw大大,我跟你一樣把底線給他去掉,怎麼就成功了呢??
G大感謝您的賣力教導,我有買您的實體書喔!
我對MapActivity?切換也有相同的問題...
gasolin您好 如果我從Activity1進入到Activity2然後想從Activity2把資料帶回Activity1了話,showResults()應該就不是在onCreat裡,那請問要怎麼抓出資料並且丟到Activity1理的textview呢?
參照 http://developer.android.com/intl/zh-TW/reference/android/content/Intent.html Intent 似乎沒有setInt setString的方法
gasolin您好 依照此範例 我在report.xml這個active的layout檔案中, 加入了@+id/result跟@+id/suggest兩個TextView 同樣的在原本的BMI Active的layout檔main.xml中 也有@+id/result跟@+id/suggest兩個TextView
這樣我怎麼知道我抓到的是哪裡active的TextView呢? 如果我對它修改值,是只修改目前的active的textview 還是兩個都會修改呢?
會修改在setContentView中指定的xml的值