(原作于2010-05-09)
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:
<?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-filter> </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:
<?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:
<?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:
<?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:
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:
/** * */ 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:
<?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-filter> </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”被我们在第二个Activity的Intent中取出来, 然后从里面抽取一个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中显示, 那么就是如下的效果了:
本文链接:https://www.poisonbian.com/post/180.html 转载需授权!