My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
AndroidIntent  
傳送資料到新 Activity
tw, Intent
Updated Nov 16, 2009 by gasolin
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 | 回目錄 | 記錄與偵錯 >


對於本章,您還期望知道什麼樣的內容呢?請在下方提出建議!

Comment by bdchina2...@gmail.com, Oct 5, 2008

通俗易懂。

加油,期待下一章节。

Comment by roji...@gmail.com, Oct 5, 2008

继续学习

Comment by project member gasolin, Feb 11, 2009

chengen0402: 請參考 http://code.google.com/p/androidbmi/source/browse/tags/BMI07/src/com/demo/android/bmi/Report.java 原始碼,看看跟你寫的有什麼不一樣

Comment by a19870...@gmail.com, Feb 13, 2009

另外我想問個問題 本章的try..catch功能已經拿掉 如果什麼都不打,就會強制關閉,沒有除錯的功能

如果要使用try..catch 要加在什麼地方呢?

我有試過把它加在report.java裡,是可以正常執行,不過這樣的順序很奇怪 也有試著把它放在各種地方,不過問題似乎是出在 startActivity(intent);在把資料傳過去的過程中出問題,而這卻不在try的範圍內(?)

Comment by project member gasolin, Feb 14, 2009

a19870..., 你已經講到問題的答案了。既然是出在 startActivity(intent);在把資料傳過去的過程就出問題,那麼這些 error check 的動作在前一個 Activity 傳送時就應該先處理掉。

Comment by chengen0...@gmail.com, Feb 14, 2009

謝謝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" /> 拿掉即可執行 也解決了我意外結束的問題

Comment by col...@gmail.com, Jul 11, 2009

按照本节内容我全部复制到我的程序里面,没有error check 我发现一个现象就是 当不填写信息 体重和身高都是空的时候 提示程序错误,但我点击强制关闭后 程序还是跑到填写身高体重的那一页,这里的关系我不是很理解,为什么会出现这样的情况 请老大们指点???????

Comment by hcye...@gmail.com, Sep 20, 2009

我照這個Sample code 執行到最後,Report 會出現,但是也會出現 Force Close。後來在 Debug 模式下看到

ActivityThread?.performStopActivityInner(ActivityThread?$ActivityRecord?, ActivityThread?$StopInfo?, boolean) line: 2905 這裡出問題

還有一個 Source not found 的訊息

不知有沒有人碰過?

Comment by project member gasolin, Sep 20, 2009

coloer, 因為當前 Activity (Report) 出錯關閉, 所以回到上一個可以跑的 Activity (BMI), 具體參考 LifeCycle 那章

Comment by shusi...@gmail.com, Oct 10, 2009

當我新增一個activity,畫面也確實轉過去,但是,一旦我在新的activity的onCreat執行任何方法(),就會出現The application BMI(process com.demo.android.bmi)has stopped unexpectedly,畫面已轉,在新的activity建立方法,並執行卻不行,why

Comment by project member gasolin, Oct 10, 2009

shusia19, 忘了在 AndroidManifest.xml 加上新 activity 標籤?

Comment by shusi...@gmail.com, Oct 10, 2009
android:label 加了,在新的activity沒有執行任何方法下,report頁面也有顯示label的字串
Comment by shusi...@gmail.com, Oct 10, 2009

gasolin您好,我已找到問題點了,感謝您的回覆,只是因為個人的疏乎,浪費您寶貴的時間,實在抱歉。在新的layout report.xml tag標錯了所導致

Comment by jesse.ch...@gmail.com, Nov 5, 2009

請問一下, 我在report.xml中使用中文的caption, 結果在 Layout的頁籤上無法顯示(顯示亂碼), 雖然在模擬器上面是沒有問題的, 但是總是美中不足, 請問有解嗎

Comment by project member gasolin, Nov 5, 2009

換一台 Mac 或 Ubuntu 都可以解.....不過這可能不是你要的答案 :p

Comment by gzzhouj...@gmail.com, Nov 16, 2009

@jesse.chan.tw 你可以試試修改模擬器的語言設置。

Comment by jojoy991...@gmail.com, Mar 3, 2010

您好,想請問一下, 如果我自行開發了兩個App(A與B),想要從App A中開啟App B,App B結束之後回到App A,這樣是可行的嗎?可以用intent來實現嗎?謝謝.

Comment by project member gasolin, Mar 3, 2010

可以, 用 startActivityForResult 來呼叫, 很抱歉目前只有實體書上講到...

Comment by jojoy991...@gmail.com, Mar 4, 2010

請問您指的是書本裡的第34章嗎?我有您的書,可是這一章裡面的兩個activity是屬於同一個package.如果我寫的兩個app屬於不同的package,仍然可以用這個方法嗎?謝謝.

Comment by project member gasolin, Mar 4, 2010

是可以的, 例如呼叫 Barcode Scanner 也可以這樣用。

Comment by jojoy991...@gmail.com, Mar 4, 2010

但是new Intent()的時候要傳入被開啟的activity的class name, 但是如果兩個class屬於不同的package,App A就會不認得App B的class name, 請問要如何解決這個問題呢? 不好意思,因為是初學者,所以問題很多.

Comment by chengy...@gmail.com, Mar 29, 2010

剛開始接觸Android的開發,如果問題很糟的話,敬請見諒!! 請教一下,如果從service直接fire up一個application,並透過intent的傳遞給予該application一個初始值。 要如何實做呢??又,要如何在該application裡判斷傳遞的intent是否正確成功呢?? 謝謝

Comment by triston...@gmail.com, Jul 30, 2010

这样Report Activity就没有Bmi Activity的Menu选单,如果想在Report Activity也加入Menu选单,能否先定义一个更基础的类来继承Activity类,同时编写好Menu选单代码后,Bmi Activity和Report Activity再来继承它,妥否?谢谢!

Comment by project member gasolin, Jul 30, 2010

Menu 選單也可以用 xml 定義

Comment by jqgsnin...@hotmail.com, Sep 2, 2010

gasolin先生,您好! 冒昧一問,似乎Intent已經不提供「setString、setInt」等方法了?

--引用-- 使用 Intent 傳遞資訊時,我們看到可以用「setClass」方法來指定要傳送到的 Activity。我們也可以使用類似的「setString」、「setInt」方法來指定要透過 Intent 附帶傳送的參數。

Comment by project member gasolin, Sep 2, 2010
Comment by xpecial...@gmail.com, Jan 5, 2011

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());

Comment by mimis...@gmail.com, Mar 24, 2011

發現了一個不好除錯的小問題 就是在xml檔如果打錯..譬如 <TextView android:id="@+id/..... 打成 <TextView android="@+id/..... 還滿難發現的XD

此外感謝gasolin大的無償教學

Comment by lh126...@gmail.com, Apr 27, 2011

假如我當前有個 pulic void class A extends B 由於 B 不是 Activity ,當我需要在 class A 執行類似 Oncreate 等等動作時該怎麼做呢?

Comment by license2...@gmail.com, May 21, 2011

gasolin您好 我想要問一下關於假如第二個頁面他是繼承 MapActivity? 而不是Activity,該如何使用Intent來轉換頁面?

我試過若兩個都是extends Activity,兩個的頁面轉換是正常的,今天我測試了一下建立一個繼承Activity,裡面就只有一個按鍵,按下去後會到第二版課本第37章的地圖範例,按下去後出現強制關閉了,是否因為不是繼承Activity的關係??

Comment by project member gasolin, May 21, 2011

多半是因為沒有在AndroidManifest裡面宣告這個新activity吧?

Comment by license2...@gmail.com, May 21, 2011

我有在AndroidManifest加入新的activity了,我自己試過如果兩個都是extends Activity 可以正常切換... 而這邊它繼承MapActivity?就不成功了。

Comment by liyuanji...@gmail.com, Jun 23, 2011

everything goes well,thx so much. 这个案例需要学习者自己动手加Report.xml;而xml无语法检查,如果稍不注意,运行时android就会报错。 we should be careful.

Comment by funnyjam...@gmail.com, Jul 6, 2011

請問一下上面的xpecial.tw大大,我跟你一樣把底線給他去掉,怎麼就成功了呢??

G大感謝您的賣力教導,我有買您的實體書喔!

Comment by notc...@gmail.com, Jul 19, 2011

我對MapActivity?切換也有相同的問題...

Comment by kaokaoli...@gmail.com, Jul 24, 2011

gasolin您好 如果我從Activity1進入到Activity2然後想從Activity2把資料帶回Activity1了話,showResults()應該就不是在onCreat裡,那請問要怎麼抓出資料並且丟到Activity1理的textview呢?

Comment by thisismy...@gmail.com, Nov 21, 2011

參照 http://developer.android.com/intl/zh-TW/reference/android/content/Intent.html Intent 似乎沒有setInt setString的方法

Comment by thisismy...@gmail.com, Nov 26, 2011

gasolin您好 依照此範例 我在report.xml這個active的layout檔案中, 加入了@+id/result跟@+id/suggest兩個TextView 同樣的在原本的BMI Active的layout檔main.xml中 也有@+id/result跟@+id/suggest兩個TextView

這樣我怎麼知道我抓到的是哪裡active的TextView呢? 如果我對它修改值,是只修改目前的active的textview 還是兩個都會修改呢?

Comment by project member gasolin, Nov 27, 2011

會修改在setContentView中指定的xml的值


Sign in to add a comment
Powered by Google Project Hosting