Activity之间通信

向下一个Activity对象传递数据

场景:用户从activity1跳转到activity2,并将activity1的数据传递给activity2中。主要步骤如下:

  1. 在Intent对象中添加要传递的参数;
  2. startActivity(Intent)方式启动Activity对象;
  3. 在被启动的Activity对象中通过Intent对象获取数据。

分解步骤如下:

1.在Intent对象中添加数据

Intent简介

在 Android 中,不同的 Activity 实例可能运行在一个进程中,也可能运行在不同的进程中。因此我们需要一种特别的机制帮助我们在 Activity 之间传递消息。Android 中通过 Intent 对象来表示一个意图,一个 Intent 对象不仅包含有这个意图的目的地,还可以包含意图的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个 Intent 对象,意图“目的地”是必须的,而内容则是可选项。具体详情请见我的另一篇1。

添加数据

Intent对象可以添加八大基本数据类型,String,CharSequence及对应的数组,也可以添加Bundle对象,Serializable实例,Parcelable实例。Serializable和Parcelable可用于实现传递自定义对象类型。

下面具体以代码演示如何传递不同的数据类型。

传递非对象数据

使用Intent传递数据包括以下两种:

  • 传递Bundle对象

    Bundle维护了一个 HashMap<String,Object>对象,将我们的数据存在 HashMap 中来进行传递;

  • 直接传递键值对

    这种方式也是通过Bundle传递,只是Bundle由系统管理.

这两种实现代码如下:

        /**
         * 第一种方式:传递Bundle对象
         */
        Bundle bundle = new Bundle();
        //名字,值
        bundle.putString("name","sywyg");
        bundle.putInt("age",26);
        intent.putExtra("person",bundle);

        /**
         * 第二种方式:直接传递键值对
         * 内部也是通过Bundle实现的
         */
        intent.putExtra("sex","男");

传递对象

包括以下两种方法

Serializable序列化方式

Serializable读作[s??r??la?’z?bl],表示序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上传输,也可以存储在本地。只要将准备序列化的对象实现Serializable接口即可,例如要实现对Cat的序列化,代码如下:

package com.sywyg.activity_test;

import java.io.Serializable;

/**
 * Created by sywyg on 2015/4/21.
 */
public class Cat implements Serializable{
//为了方便描述就不封装了
    String name;
    int age;

    @Override
    public String toString() {
        return "Cat[name:" + name + "age:" + age + "]";
    }
}

上述代码完成了对Cat类的序列化。下面在MainActivity(第一个Activity)中设置传送Cat类对象到MainActivity2(第二个Activity)中,主要代码如下:

        /**
         * 通过Serializable接口传递对象
         */
        Cat cat = new Cat();
        cat.name = "小猫";
        cat.age = 3;
        //参数为:对象名,Serializable引用变量
        intent.putExtra("cat",cat);

接下来在MainActivity2中获取对象的主要代码如下:

//getIntent()返回Intent对象
 Cat cat = (Cat)getIntent().getSerializableExtra("cat");
Parcelable方式

Parcelable方式的实现原理是将一个完整的对象进行分解,分解后的每一部分都是Intent所支持的数据类型,这样就可以传输对象了。

Parcelable接口主要代码如下:

package android.os;
public interface Parcelable
{
    //内容描述
    public int describeContents();
    //写入接口方法,打包
    public void writeToParcel(Parcel dest, int flags);
    //读取接口,目的是要从Parcel中构造一个实现了Parcelable的类的实例处理。因为实现类在这里还是不可知的,所以需要用到模板的方式,继承类名通过模板参数传入
    //为了能够实现模板参数的传入,这里定义Creator嵌入接口,内含两个接口函数分别返回单个和多个继承类实例
    public interface Creator<T>
    {
           public T createFromParcel(Parcel source);
           public T[] newArray(int size);
    }
}

假设要传输Dog类对象,则需实现Parcelable接口,具体代码如下:

package com.sywyg.activity_test;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by sywyg on 2015/4/21.
 */
public class Dog implements Parcelable{
    String name;
    int age;
    public Dog(){}
    //或放在createFromParcel(Parcel source)方法里直接new Dog()然后在调用readXXX(),不用定义构造器
    private Dog(Parcel in){
    //写
        name = in.readString();
        age = in.readInt();
    }
    //匿名内部类实现接口实例
    /**其中public static final一个都不能少,内部对象CREATOR的名称也不能改变,必须全部大写。需重写本接口中的两个方法:createFromParcel(Parcel in) 实现从Parcel容器中读取传递数据值,封装成Parcelable对象返回逻辑层,newArray(int size) 创建一个类型为T,长度为size的数组,仅一句话即可(return new T[size]),供外部类反序列化本类数组使用。
    */
    public static final Parcelable.Creator<Dog> CREATOR = new Parcelable.Creator<Dog>() {
        @Override
        public Dog createFromParcel(Parcel source) {
            return new Dog(source);
        }
        @Override
        public Dog[] newArray(int size) {
            return new Dog[size];
        }
    };
    /**
    *重写writeToParcel方法,将你的对象打包为一个Parcel对象,即:将类               的数据写入外部提供的Parcel中,打包需要传递的数据到Parcel容器保存,以便从 Parcel容器获取数据
    */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
    //读
        dest.writeString(name);
        dest.writeInt(age);
    }
//内容描述接口,返回0即可
    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public String toString() {
        return "Dog[name:" + name + "age:" + age + "]";
    }
}

简而言之:通过writeToParcel将你的对象映射成Parcel对象,再通过createFromParcel将Parcel对象映射成你的对象。也可以将Parcel看成是一个流,通过writeToParcel把对象写到流里面,在通过createFromParcel从流里读取对象,只不过这个过程需要你来实现,因此写的顺序和读的顺序必须一致。

在MainActivity中使用相同的代码传递Dog类对象,在MainActivity2中获取对象的代码如下:

Dog dog = (Dog)getIntent().getParcelableExtra("dog");

性能:

  1. Serializable要对整个对象序列化,因此性能要低于Parcelable,所以通常情况下推荐使用Parcelable的方式实现Intent传递对象的功能。
  2. Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
  3. Parcelable不能使用在要将数据存储在磁盘上的情况,因为在外界有变化的情况下Parcelable不能很好的保证数据的持续性。尽管Serializable效率低点, 也不提倡用,但在这种情况下,还是建议你用Serializable 。

注意:关于以上内容还要继续了解,这里只是简单的使用一下(how),至于what和why还需要进一步了解。

2. 启动另一个Activity对象

代码如下:

//this表示当前Activity,MainActivity2.class表示要跳转到的Activity
//MainActivity2需要在AndroidManifest.xml中声明。
 Intent intent = new Intent(this,MainActivity2.class);
 intent.putExtra("name",XXX);
 startActivity(intent);

3. 获得数据

在启动的Activity通过getXXXExtra()方法获取数据,代码如下:

        //获取第一种方式传递过来的数据
        Bundle bundle = intent.getBundleExtra("person");
        String name = bundle.getString("name");
        int age = bundle.getInt("age");

        //获取第二种方式传递过来的数据
        String sex = intent.getStringExtra("sex");

        //第三种方式传递数据
        Cat cat = (Cat)intent.getSerializableExtra("cat");

        //第四种方式传递数据
        Dog dog = (Dog)intent.getParcelableExtra("dog");

返回数据给启动该Activity的Activity

场景:用户从activity1跳转到activity2,将activity2的结果返回到activity1中。主要步骤如下:

  1. 使用startActivityForResult()方法启动一个Activity
  2. 重写onActivityResult()事件方法,处理返回结果
  3. 在带放回结果的Activity里,使用setResult()设置返回结果。

下面详解:

1. 启动另一个Activity

代码如下:

//启动一个带返回结果的Activity,返回结果给当前Activity
        Intent  intent = new Intent(this, MainActivity32Activity.class);
//参数为:Intent对象,参数编码
//参数编码(对应设置它的Activity)用于判断哪个Activity响应的,REQUESTCODE大于等于0就会返回结果
startActivityForResult(intent,REQUESTCODE);

2. 启动带返回结果的Activity

下面的Activity通过按钮启动带返回结果的Activity,具体代码如下:

package com.sywyg.activity_test;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

/**
 * 启动一个带返回结果的Activity
 * @author sywyg
 * @since 2015/4/22
 */
public class MainActivity3Activity extends Activity implements View.OnClickListener {
    private TextView tv;
    private Button btn_result;
    private static final int REQUESTCODE = 1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_activity3);
        tv = (TextView)findViewById(R.id.tv);
        btn_result = (Button)findViewById(R.id.btn_result);
        btn_result.setOnClickListener(this);
    }

    @Override
    public void onClick(View view){
        //启动一个带返回结果的Activity,返回结果给该Activity
        Intent  intent = new Intent(this, MainActivity32Activity.class);
        //REQUESTCODE大于等于0就会返回结果
        startActivityForResult(intent,REQUESTCODE);
    }

    /**
     * 处理返回过来的结果,系统调用
     * @param requestCode,请求编码,对应传递的REQUESTCODE,一般有多个,注意区分并要进行判断响应的是哪个Activity
     * @param resultCode 返回编码,系统有固定值
     * @param data 返回的Intent,含有返回结果数据
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode){
            case REQUESTCODE:
                if (resultCode == RESULT_OK){
                    String result = data.getStringExtra("result");
                    tv.setText("返回结果为:" + result);
                }
                break;
        }
    }
}

其中,onActivityResult()方法用于处理返回的数据,由系统自行调用。一种有三个参数,详情见代码。这里特别说明一下:由于在一个Activity中可能通过调startActivityForResult()方法去启动多个不同的Activity,每一个返回的数据都是通过onActivityResult()方法处理,因此需要通过requestCode判断数据来源,然后再resultCode判断返回结果是否成功,最后将data中的数据显示出来。

关于startActivityForResult()启动singleTask的Activity,则onActivitResult()立即回调且resultCode为RESULT_CANCELED问题请参见2。

3. 带返回结果的Activity

下面的Activity为带返回结果的Activity,具体代码如下:

package com.sywyg.activity_test;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;

/**
 * 带返回结果的Activity把结果返回给调用它的Activity
 * @author sywyg
 * @since 2015/4/22
 */

public class MainActivity32Activity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_activity32);
        //获得当前Intent对象,也可以自定义一个。不需指定意图,即来源和去向(intent.setClass())
        Intent intent = getIntent();
        //Intent intent = new Intent();

        //添加需传递的数据
        intent.putExtra("result","这是第二个Activity返回的结果");
        /**
         * 设置结果
         * 参数为:结果编码(系统值),当前Intent对象
         */
        setResult(RESULT_OK,intent);

        //销毁该Activity
        //finish();
    }

}

其中,Intent对象可以由该Activity调用getIntent()方法获得一个Intent对象,或者重新构建一个,但是无论如何这里的Intent对象只是传递数据,没有任何的意图,即来源和去向。setResult()方法用于向上一个Activity返回数据,第一个参数用于向上一个Activity返回结果,一般使用RESULT_OK或RESULT_CANCELED这两个值,第二个参数是带有数据的Intent对象。

运行结果

运行结果如下:

可以看到直接按BACK键就能把数据传给上一个Activity中,当然设置按钮也一样,

需要注意一下几点:

  1. 在带返回结果的Activity中的Intent对象不能设置意图(即使设置了,没有startActivity也不会响应意图)。
  2. 有时在复杂的业务逻辑中,可能存在A startActivityForResult 到B,同时C也startActivityForResult 到B,且requestCode可能相同(以表示同意业务请求),这时可能需要在B中针对性的判断此请求来源(来自于A还是C)。此时,可以通过intent传参形式。相信大家都比较熟悉,其实Activity类中也提供了相应的函数可以获取到来源Activity的类型函数:getCallingActivity()。但需要注意此函数仅针对startActivityForResult有效,返回的结果中包含完成包名(Android总结篇系列:Activity中几个主要函数详解)。
  3. 前一个活动的回调方法在后一个活动的onPause()方法之后,该活动的onRestart()方法之前(如果调用该方法的话,注意若后一个活动以Dialog方式显示的或不会onStop()因此也没有onRestart()),且一定在onResume()方法之前。

威哥视频

郭霖 第一行android


  1. http://blog.csdn.net/wangyongge85/article/details/45307337 ?
  2. http://blog.csdn.net/sodino/article/details/22101881 ?

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-08 13:39:46

Activity之间通信的相关文章

Android Service与Activity之间通信的几种方式

在Android中,Activity主要负责前台页面的展示,Service主要负责需要长期运行的任务,所以在我们实际开发中,就会常常遇到Activity与Service之间的通信,我们一般在Activity中启动后台Service,通过Intent来启动,Intent中我们可以传递数据给Service,而当我们Service执行某些操作之后想要更新UI线程,我们应该怎么做呢?接下来我就介绍两种方式来实现Service与Activity之间的通信问题 通过Binder对象 当Activity通过调

Android实战简易教程-第五十二枪(Fragment和Activity之间通信)

Fragment的使用可以让我们的应用更灵活的适配各种型号的安卓设备,但是对于Fragment和Activity之间的通信,很多朋友应该比较陌生,下面我们就通过一个实例来看一看如何实现. 一.Activity->Fragment传递数据 1.main.xml: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.an

Android中Activity之间通信

一.使用Intent 在 Android 中,不同的 Activity 实例可能运行在一个进程中,也可能运行在不同的进程中.因此我们需要一种特别的机制帮助我们在 Activity 之间传递消息.Android 中通过 Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内容.对于一个 Intent 对象,消息“目的地”是必须的,而内容则是可选项. 在上面的实例中通过 Acti

android中fragment与activity之间通信原理以及例子

参考文章 http://blog.csdn.net/guozh/article/details/25327685#comments Activity和fragment通信方式一般有3种方法 1.在fragment中定义接口, Activity去实现接口--->查看上面的参考文章 2.使用广播机制 3.使用EventBus 这3种方式 推荐使用EventBus 下面介绍第2种方式广播通信机制: 首先MainActivity中引入一个fragment, activity的布局很简单,里面只有一个 f

Android Activity之间通信

package com.example.myapp; import android.app.Activity; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; public class MyActivity extends Activity

Android Service与Activity之间通信

主要分为: 通过Binder对象 通过broadcast(广播)的形式 Activity调用bindService (Intent service, ServiceConnection conn, int flags)方法,得到Service对象的一个引用,这样Activity可以直接调用到Service中的方法,如果要主动通知Activity,我们可以利用回调方法: 在Service中新建获取Binder实例: /** * 返回一个Binder对象 */ @Override public IB

Fragment 和 Activity 之间通信

在 Activity 中获取 Fragment 实例: FragmentManager 提供了一个类似于 findViewById 的方法,专门用于从布局文件中获取 Fragment 实例: //通过挂载点的容器id获取对应的 Fragment 实例RightFragment rightFragment = (RightFragment) getSupportFragmentManager().findFragmentById(R.id.right_fragment); 在 Fragment 中

Android——Fragment和Activity之间的通信+Frangment生命周期

Android--Fragment和Activity之间的通信+Frangment生命周期 Fr'agment和Activity之间的通信 1.在Fragment中声明一个接口. 2.在Activity中实现在Fargment中声明的接口. 3.在Fragment中声明一个接口对象. 4.在Frangment的生命周期Onattach方法中判断当前Activity是否实现了此Fragment中声明的接口.如果已实现,就把当前Activity转换成接口对象. 5.调用Activity中实现的方法=

Fragment的生命周期和Activity之间的通信以及使用

Fragment通俗来讲就是碎片,不能单独存在,意思就是说必须依附于Activity,一般来说有两种方式把Fragment加到Activity,分为静态,动态. 静态即为右键单击,建立一个Fragment,选择Blank,在Activity布局中直接加fragment,name属性直接指向之前建立的Fragment,这就添加上了Fragment,这种较为简单. 动态: 我们要做的是在Activity中添加一个Fragment,Fragment中有两个按钮,当按下按钮时分别切换不同的Fragmen