Android開發淺談-04-Activity信息傳遞

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
package cn.mishi8;
 
import android.app.Activity;
 
import android.content.Intent;
 
import android.os.Bundle;
 
import android.view.View;
 
import android.widget.Button;
 
import android.widget.EditText;
 
public class MainActivity extends Activity {
 
         private EditText mainEditText1;
 
         private Button mainButton1;
 
         private void initView()
 
         {
 
                   mainEditText1 = (EditText)findViewById(R.id.main_edittext1);
 
                   mainButton1 = (Button)findViewById(R.id.main_button1);
 
         }
 
         private void initListeners()
 
         {
 
                   mainButton1.setOnClickListener(
 
                            new Button.OnClickListener()
 
                            {
 
                                     @Override
 
                                     public void onClick(View v) {
 
                                               // TODO Auto-generated method stub
 
                                               Intent intent = new Intent();
 
                                               intent.setClass(MainActivity.this, TargetActivity.class);
 
                                               Bundle bundle = new Bundle();
 
                                               bundle.putString("name", mainEditText1.getText().toString());
 
                                               intent.putExtras(bundle);
 
                                               startActivityForResult(intent, 0);
 
                                               //by poisonbian
 
                                               finish();
 
                                     }
 
                            }
 
                   );
 
         }
 
    /** Called when the activity is first created. */
 
    @Override
 
    public void onCreate(Bundle savedInstanceState) {
 
        super.onCreate(savedInstanceState);
 
        setContentView(R.layout.main);
 
        initView();
 
        initListeners();
 
    }
 
         /* (non-Javadoc)
 
          * @see android.app.Activity#onActivityResult(int, int, android.content.Intent)
 
          */
 
         @Override
 
         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;
 
                   }
 
         }
 
}

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
/**
 
 *
 
 */
 
package cn.mishi8;
 
import android.app.Activity;
 
import android.content.Intent;
 
import android.os.Bundle;
 
import android.view.View;
 
import android.widget.Button;
 
import android.widget.TextView;
 
/**
 
 * @author poisonbian
 
 *
 
 */
 
public class TargetActivity extends Activity {
 
         private TextView targetTextView1;
 
         private Button targetButton1;
 
         private void initView()
 
         {
 
                   targetTextView1 = (TextView)findViewById(R.id.target_textview1);
 
                   targetButton1 = (Button)findViewById(R.id.target_button1);
 
                   Bundle bundle = getIntent().getExtras();
 
                   String name = bundle.getString("name");
 
                   targetTextView1.setText("收到消息, From: " + name);
 
         }
 
         private void initListeners()
 
         {
 
                   targetButton1.setOnClickListener(
 
                            new Button.OnClickListener()
 
                            {
 
                                     @Override
 
                                     public void onClick(View v) {
 
                                               // TODO Auto-generated method stub
 
                                               Intent result = new Intent();
 
                                               result.putExtra("result", "知道啦知道啦~");
 
                                               setResult(RESULT_OK, result);
 
                                               finish();
 
                                     }       
 
                            }
 
                   );
 
         }
 
         /* (non-Javadoc)
 
          * @see android.app.Activity#onCreate(android.os.Bundle)
 
          */
 
         @Override
 
         protected void onCreate(Bundle savedInstanceState) {
 
                   // TODO Auto-generated method stub
 
                   super.onCreate(savedInstanceState);
 
                   setContentView(R.layout.target);
 
                   initView();
 
                   initListeners();
 
         }
 
}

另外, 一定要記得, 在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 bundle = new Bundle();

bundle.putString(“name”, mainEditText1.getText().toString());

intent.putExtras(bundle);

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”被我們在第二個ActivityIntent中取出來, 然後從裏面抽取一個string, 它的key叫做”name”, 對應的value被直接放在了一個TextView中輸出.

接下來, 是TargetActivity的Button.

Intent result = new Intent();

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中顯示, 那麼就是如下的效果了:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章