Activity從某種程度上說, 是Android大多數程序的骨架子. 一般很少會有程序只有一個Activity, 因此很多時候, Activity之間的通信和變量傳遞是非常重要的.
Android SDK本身是提供了四種跨進程通訊方式的, 對應了四種應用程序組件: Activity, Content Provider, Broadcast和Service. 在Ophone社區也有對這幾種方式的簡單說明: Activity可以跨進程調用其他應用程序的Activity(自身應用程序當然也可以); Content Provider可以訪問其他應用程序提供的數據, 以Cursor對象形式返回, 也可以進行增刪改查操作, 就相當於是對數據庫的訪問一樣; Broadcast可以向所有應用程序發送廣播, 進而被”有意者”監聽到; Service類似於Content Provider, 不過返回的是Java對象.
我們現在只關注於Activity的通訊.
當我們有如下的xml, 即有兩個Activity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
< ?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.mishi8" 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> </activity> <activity android:name=".TargetActivity"> </activity> </application> <uses -sdk android:minSdkVersion="1" /> </manifest> |
我們有這樣的需求, 啓動MainActivity, 包含一個輸入框(EditText)和一個按鈕(Button), 輸入一個字符串(String)作爲名字, 把它傳給第二個Activity(Target), 第二個Activity將顯示, 從某某處接收到消息, 並在界面上也提供一個按鈕(Button), 點擊後返回第一個Activity, 告訴它, “我收到你的消息了!”
首先是簡單的頁面佈局, 我們提供兩個xml文件, 分別去對應MainActivity和TargetActivity的layout.
main.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
< ?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" > <edittext android:id="@+id/main_edittext1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:hint="@string/main_edittext1"> </edittext> <button android:id="@+id/main_button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/main_button1"> </button> </linearlayout> |
target.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
< ?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/target_textview1" android:layout_width="fill_parent" android:layout_height="wrap_content"> </textview> <button android:id="@+id/target_button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/target_button1"> </button> </linearlayout> |
其中使用”@string”的屬性, 自然是需要在string.xml中去註冊的.
string.xml:
1 2 3 4 5 6 7 8 |
< ?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World, MainActivity!</string> <string name="app_name">第一個Android程序</string> <string name="main_edittext1">輸入你的名字</string> <string name="main_button1">發送消息</string> <string name="target_button1">我知道啦</string> </resources> |
下面是MainActivity和TargetActivity兩個類的代碼,
MainActivity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
|
TargetActivity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
|
另外, 一定要記得, 在AndroidManifest.xml中去註冊兩個Activity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
< ?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.mishi8" 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> </activity> <activity android:name=".TargetActivity"> </activity> </application> <uses -sdk android:minSdkVersion="1" /> </manifest> |
下面來結合截圖看一看, 我們的兩個Activity做了什麼:
MainActivity如下, 它以main.xml爲layout: setContentView(R.layout.main); 頁面有兩個控件, 分別是EditText和Button. Button上有一個Click的Listener, click之後有如下動作:
Intent intent = new Intent();
intent.setClass(MainActivity.this, TargetActivity.class);
bundle.putString(“name”, mainEditText1.getText().toString());
startActivityForResult(intent, 0);
//by poisonbian
finish();
新建一個Intent, 源與目標分別爲MainActivity與TargetActivity, 新建一個”郵包”Bundle, bundle中放了一個Map, key是”name”, value是mainEditText1中輸入的字符串, intent將這個bundle攜帶在身上, 啓動intent(即啓動目標Activity), 並且使用的是”startActivityForResult”, 不是”startActivity”, 這表明啓動目標Activity是需要等待其返回結果的. 因此這個地方的”finish()”實際是有bug的!
我們不妨先忽略它, 看最終的效果是什麼樣子.
輸入一個字符串, 點擊”發送消息”, 跳轉到了第二個Activity, 它又做了什麼呢?
首先是接收信息:
Bundle bundle = getIntent().getExtras();
String name = bundle.getString(“name”);
targetTextView1.setText(“收到消息, From: ” + name);
郵包”bundle”被我們在第二個Activity的Intent中取出來, 然後從裏面抽取一個string, 它的key叫做”name”, 對應的value被直接放在了一個TextView中輸出.
接下來, 是TargetActivity的Button.
result.putExtra(“result”, “知道啦知道啦~”);
setResult(RESULT_OK, result);
finish();
點擊後做這樣一些事情, 再次聲明一個Intent, 它放一個map進去, key爲”result”, 然後調用setResult. “RESULT_OK”是Activity的自帶變量, 表明這個result的性質, 或者也當做是一個”key”. 然後這個Activity就finish掉了.
再看第一個Activity, 它是想接收到Target的返回信息的.
但是實際上呢? 我們在模擬器中運行, 卻會發現, 第二個按了Button之後, 程序全部退出了?
這就是我們剛剛說的那個MainActivity中”finish()”這個語句的bug!
因爲啓動第二個Activity之後, 自己已經通過finish()結束了, 怎麼還能夠接收到返回呢?
所以, 這個地方, 如果我們註釋掉這句話, 就能夠正確地執行以下的語句了:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
switch (resultCode)
{
case RESULT_OK:
Bundle bundle = data.getExtras();
String result = bundle.getString(“result”);
mainEditText1.setText(result);
break;
default:
break;
}
}
當有結果返回時, 判斷resultCode, 如果是RESULT_OK, 那麼執行case中對應的語句. 這樣的switch就表明, 我們在Target中完全可以構造不同類型的RESULT_*(例如RESULT_CANCELED, 去讓源Activity採取不同的操作.
這次對於第一個Activity來說, 它從結果Intent中去獲得返回的郵包, 取出”result”, 直接放在EditText中顯示, 那麼就是如下的效果了: