如何在Android上将对象从一项活动传递到另一项活动


778

我正在尝试从一个发送客户类的对象,Activity然后在另一个对象中显示它Activity

客户类的代码:

public class Customer {

    private String firstName, lastName, Address;
    int Age;

    public Customer(String fname, String lname, int age, String address) {

        firstName = fname;
        lastName = lname;
        Age = age;
        Address = address;
    }

    public String printValues() {

        String data = null;

        data = "First Name :" + firstName + " Last Name :" + lastName
        + " Age : " + Age + " Address : " + Address;

        return data;
    }
}

我想将其对象从一个发送Activity到另一个,然后在另一个上显示数据Activity

我该如何实现?


1
可能您应该根据大众意见来更改接受的答案。
Rohit Vipin Mathews 2015年

我曾经将对象设置为Pacelable或Serializable,但是每当添加其他变量时,都必须将其全部添加到要获取并设置为Pacelable或Serializable的函数中。因此我制作了DataCache在活动和片段之间进行传输。github.com/kimkevin/AndroidDataCache传输对象超级容易。
kimkevin

Answers:


886

一种选择是让您的自定义类实现该Serializable接口,然后可以使用putExtra(Serializable..)Intent#putExtra()方法的变体在意图中额外传递对象实例。

伪代码

//To pass:
intent.putExtra("MyClass", obj);

// To retrieve object in second Activity
getIntent().getSerializableExtra("MyClass");

注意:确保主定制类的每个嵌套类都实现了Serializable接口,以避免任何序列化异常。例如:

class MainClass implements Serializable {

    public MainClass() {}

    public static class ChildClass implements Serializable {

        public ChildClass() {}
    }
}

126
@OD:在我的辩护中,我从未说过这是最好的选择。OP只是问其他选择,我建议了一个。不管怎么说,多谢拉。
萨木,2011年

83
为什么序列化不是一个好选择?这是一个众所周知的接口,人们的类很有可能已经实现了它(例如,ArrayList已经可序列化)。为什么必须更改数据对象以添加额外的代码,只是将它们从一个类传递到另一类?这似乎是一个糟糕的设计。我可以想象在某种程度上可能会对性能产生影响,但是我认为在99%的情况下,人们正在传递少量数据,而他们却不在乎。更简单,更便携有时也更好。
内特-

16
@Sander:那么这个答案(stackoverflow.com/questions/2139134/…)错误吗?他说,Parcelable IS是专门为此目的设计的(并且速度比快得多Serializable)。我很困惑。
Slauma 2011年

41
Parcelable可能对速度有好处,但是实现起来很复杂。如果您需要在活动之间传递8个对象,该怎么Parcelable办呢?Serializable相反,使用它会更有意义。实现时,Parcelable您必须向类中添加大量代码,并以非常特定的方式对字段进行排序;Serializable你不知道 最终,我认为这取决于您传递的对象数和尝试执行的操作。
BlackHatSamurai 2012年

15
Serializable是标准的Java接口。您只需通过强化接口来标记可序列化的类,Java在某些情况下将自动对其进行序列化。 Parcelable是Android专用界面,您可以在其中实现序列化。它的创建要比Serializable的效率要高得多,并且可以解决默认Java序列化方案的某些问题
Gaurav Arora,2012年

311

使用Serializable实现您的课程。让我们假设这是您的实体类:

import java.io.Serializable;

@SuppressWarnings("serial") //With this annotation we are going to hide compiler warnings
public class Deneme implements Serializable {

    public Deneme(double id, String name) {
        this.id = id;
        this.name = name;
    }

    public double getId() {
        return id;
    }

    public void setId(double id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private double id;
    private String name;
}

我们正在dene将从X活动调用的对象发送到Y活动。X活动中的某处;

Deneme dene = new Deneme(4,"Mustafa");
Intent i = new Intent(this, Y.class);
i.putExtra("sampleObject", dene);
startActivity(i);

在Y活动中,我们正在获取对象。

Intent i = getIntent();
Deneme dene = (Deneme)i.getSerializableExtra("sampleObject");

而已。


1
对我来说真的很有帮助。谢谢...但是,当接收到传递的对象时,语法应为[Deneme dene =(Deneme)i.getSerializableExtra(“ sampleObject”); ] ... 是吗 ???
JibW 2012年

1
@MustafaGüven但是我正在classCastException: java.lang.Long这样做。你能解释为什么吗?
Shajeel Afzal

我的回答没有关系。您得到的是完全不同的东西。您可以分享您的密码吗?
MustafaGüven13年

1
对于大型POJO,可序列化太慢。使用总线是更好的方式。
史蒂文·马克·福特

1
为什么必须(Serializable)在对象之前加上前缀?
Alston 2014年

123
  • 使用全局静态变量不是良好的软件工程实践。
  • 将对象的字段转换为原始数据类型可能会很麻烦
  • 使用serializable是可以的,但在Android平台上性能不高
  • Parcelable是专为Android设计的,您应该使用它。这是一个简单的示例:在Android活动之间传递自定义对象

您可以使用此站点为您的班级生成Parcelable代码。


4
如果我的对象包含嵌套的Arraylist怎么办?
2014年

10
好吧,但是一个人真的应该带着一粒盐imo来表现。如果这是以实现为代价的,Parcelable那么我宁愿让我的POJO类与Android无关并使用Serializable
VH-NZZ 2014年

我不同意您应该使用Parcelable。一个简单的BUS模式在运行时效率更高,并且节省了大量的开发时间。
史蒂文·马克·福特

15
根据此基准,bitbucket.org / afrishman / androidserializationtest Serializable比Parcelable快得多。请停止分享这个5岁的关于Parcelable的废话。
afrish

7
全局静态变量如何“不是良好的软件工程实践”?您可以制作诸如单例缓存和/或数据网格之类的内容,然后传递ID或类似内容。当您在Java中传递引用时,无论如何它们都在使用全局静态变量,因为它们指向同一对象。
突破线

111

使用gson将您的对象转换为JSON并将其通过intent传递。在新的Activity中,将JSON转换为对象。

在您的中build.gradle,将此添加到您的依赖项中

implementation 'com.google.code.gson:gson:2.8.4'

在您的Activity中,将对象转换为json-string:

Gson gson = new Gson();
String myJson = gson.toJson(vp);
intent.putExtra("myjson", myjson);

在接收活动中,将json-string转换回原始对象:

Gson gson = new Gson();
YourObject ob = gson.fromJson(getIntent().getStringExtra("myjson"), YourObject.class);

对于Kotlin来说,它是完全一样的

传递数据

val gson = Gson()
val intent = Intent(this, YourActivity::class.java)
intent.putExtra("identifier", gson.toJson(your_object))
startActivity(intent)

接收数据

val gson = Gson()
val yourObject = gson.fromJson<YourObject>(intent.getStringExtra("identifier"), YourObject::class.java)

3
gson有点过分,只是将字符串序列化为json的一种,更好地实现Serializable或Paracable。
James Roeiter 2013年

14
如果可以使用处理可序列化的库(gson),则无需在每个对象和每个项目中实现可序列化(浪费时间)。关于过度杀伤力,那里有双核和四核电话,按照这个回答的想法,它们甚至可以处理一个清单。
sagits 2015年

4
我还建议使用gson,因为gson除了上述内容之外还可以序列化arraylists。
nurgasemetey 2015年

4
这很棒!就我而言,我使用的是一个对象不实现可序列化或可打包的库。所以这是我唯一的选择afaik
Chad Bingham

2
这是“最佳”选项。有些类非常简单,您无需通过实现可序列化来使它们的实现复杂化
Ojonugwa Jude Ochalifu

98

进行活动时

Intent intent = new Intent(fromClass.this,toClass.class).putExtra("myCustomerObj",customerObj);

在toClass.java中,通过接收活动

Customer customerObjInToClass = getIntent().getExtras().getParcelable("myCustomerObj");

请确保客户类别可包裹

public class Customer implements Parcelable {

    private String firstName, lastName, address;
    int age;

    /* all your getter and setter methods */

    public Customer(Parcel in ) {
        readFromParcel( in );
    }

    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
        public LeadData createFromParcel(Parcel in ) {
            return new Customer( in );
        }

        public Customer[] newArray(int size) {
            return new Customer[size];
        }
    };


    @Override
    public void writeToParcel(Parcel dest, int flags) {

        dest.writeString(firstName);
        dest.writeString(lastName);
        dest.writeString(address);
        dest.writeInt(age);
    }

    private void readFromParcel(Parcel in ) {

        firstName = in .readString();
        lastName  = in .readString();
        address   = in .readString();
        age       = in .readInt();
    }

Adhavan,我有一个问题。创建第一个Intent类时,将fromClass.this作为第一个参数传入。有没有办法在接收活动类中检索此对象?
纽曼

1
Miliu,fromClass fr =(fromClass)getParent(); 这是您需要的吗?
广告

Adhava,我实际上是这样做的,但是fr为空。知道为什么吗?
纽曼

miliu,请与我们分享您的异常跟踪,以便我们进行调查。
广告

Parcelable具有大量不必要的样板代码,坦率地说是浪费时间。宁可乘坐公共汽车。请参阅下面的我的帖子。
史蒂文·马克·福特

89

根据我的经验,有三种主要解决方案,每种都有其缺点和优点:

  1. 实现包裹

  2. 实现可序列化

  3. 使用某种轻量级的事件总线库(例如,Greenrobot的EventBus或Square的Otto)

可打包 -快速和Android标准,但是它具有大量样板代码,并且在将值拉出意图时(非强类型)需要硬编码的字符串作为参考。

可序列化 -接近零样板,但这是最慢的方法,并且在将值拉出意图(非强类型)时还需要硬编码的字符串。

事件总线 -零样本,最快的方法,并且不需要硬编码的字符串,但是它确实需要附加的依赖项(尽管通常是轻量级的〜40 KB)

我针对这三种方法(包括效率基准)进行了非常详细的比较。


4
链接到文章已失效。仍可在webarchive上找到:web.archive.org/web/20160917213123/http
//…

可惜的是,链接
断开

使用事件总线的问题是例如由于轮换而重新创建目标活动时。在这种情况下,目标Activity无法访问传递的对象,因为该对象是由较早的调用从总线上消耗的。
JuliuszJ

1
Parcelable是最快的,使用此生成器(parcelabler.com),您可以粘贴您的类,它可以为您生成代码。简单。
ByWaleed

1
@ByWaleed ...我绝对同意,我总是使用此网站,制作东西没有任何麻烦。但是,当我尝试使用由另一个Object组成的POJO时,我进行了很多失败的尝试。由于某种原因,它的输出并没有真正起作用。
Yo Apps

42

我发现了一种简单而优雅的方法:

  • 无包裹
  • 否可序列化
  • 无静电场
  • 无事件总线

方法一

第一次活动的代码:

    final Object objSent = new Object();
    final Bundle bundle = new Bundle();
    bundle.putBinder("object_value", new ObjectWrapperForBinder(objSent));
    startActivity(new Intent(this, SecondActivity.class).putExtras(bundle));        
    Log.d(TAG, "original object=" + objSent);

第二项活动的代码:

    final Object objReceived = ((ObjectWrapperForBinder)getIntent().getExtras().getBinder("object_value")).getData();
    Log.d(TAG, "received object=" + objReceived);

您会发现objSentobjReceived相同hashCode,因此它们是相同的。

但是为什么我们可以通过这种方式传递一个Java对象呢?

实际上,Android绑定器将为Java对象创建全局JNI引用,并在没有Java对象的引用时释放该全局JNI引用。活页夹会将这个全局JNI引用保存在Binder对象中。

*警告:除非两个活动在同一进程中运行,否则此方法仅适用,否则将在(ObjectWrapperForBinder)getIntent()。getExtras()。getBinder(“ object_value”)抛出ClassCastException *

类ObjectWrapperForBinder定义

public class ObjectWrapperForBinder extends Binder {

    private final Object mData;

    public ObjectWrapperForBinder(Object data) {
        mData = data;
    }

    public Object getData() {
        return mData;
    }
}

方法二

  • 对于发送者,
    1. 使用自定义本地方法将Java对象添加到JNI全局引用表(通过JNIEnv :: NewGlobalRef)
    2. 将返回整数(实际上是JNIEnv :: NewGlobalRef返回jobject,它是一个指针,我们可以安全地将其强制转换为int)放入您的Intent(通过Intent :: putExtra)
  • 给接收者
    1. 从Intent获取整数(通过Intent :: getInt)
    2. 使用自定义本机方法从JNI全局引用表还原Java对象(通过JNIEnv :: NewLocalRef)
    3. 从JNI全局引用表中删除项目(通过JNIEnv :: DeleteGlobalRef),

但是方法2有一个严重的问题,如果接收方无法还原Java对象(例如,在还原Java对象之前发生了一些异常,或者接收方Activity根本不存在),则Java对象将成为孤立或内存泄漏,方法1没有此问题,因为android绑定程序将处理此异常

方法3

要远程调用java对象,我们将创建一个数据协定/接口来描述java对象,我们将使用aidl文件

IDataContract.aidl

package com.example.objectwrapper;
interface IDataContract {
    int func1(String arg1);
    int func2(String arg1);
}

第一次活动的代码

    final IDataContract objSent = new IDataContract.Stub() {

        @Override
        public int func2(String arg1) throws RemoteException {
            // TODO Auto-generated method stub
            Log.d(TAG, "func2:: arg1=" + arg1);
            return 102;
        }

        @Override
        public int func1(String arg1) throws RemoteException {
            // TODO Auto-generated method stub
            Log.d(TAG, "func1:: arg1=" + arg1);
            return 101;
        }
    };
    final Bundle bundle = new Bundle();
    bundle.putBinder("object_value", objSent.asBinder());
    startActivity(new Intent(this, SecondActivity.class).putExtras(bundle));
    Log.d(TAG, "original object=" + objSent);

第二项活动的代码:

将AndroidManifest.xml中的android:process属性更改为非空进程名称,以确保第二个活动在另一个进程中运行

    final IDataContract objReceived = IDataContract.Stub.asInterface(getIntent().getExtras().getBinder("object_value"));
    try {
        Log.d(TAG, "received object=" + objReceived + ", func1()=" + objReceived.func1("test1") + ", func2()=" + objReceived.func2("test2"));
    } catch (RemoteException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

这样,即使两个活动在不同的进程中运行,我们也可以在它们之间传递接口,并远程调用该接口方法

方法4

方法3似乎还不够简单,因为我们必须实现一个aidl接口。如果您只是想做简单的任务而方法的返回值是不必要的,我们可以使用android.os.Messenger

第一次活动的代码(发送者):

public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";

    public static final int MSG_OP1 = 1;
    public static final int MSG_OP2 = 2;

    public static final String EXTRA_MESSENGER = "messenger";

    private final Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            Log.e(TAG, "handleMessage:: msg=" + msg);
            switch (msg.what) {
            case MSG_OP1:

                break;
            case MSG_OP2:
                break;

            default:

                break;
            }
            super.handleMessage(msg);
        }

    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startActivity(new Intent(this, SecondActivity.class).putExtra(EXTRA_MESSENGER, new Messenger(mHandler)));
    }
}

第二项活动的代码(接收者):

public class SecondActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        final Messenger messenger = getIntent().getParcelableExtra(MainActivity.EXTRA_MESSENGER);
        try {
            messenger.send(Message.obtain(null, MainActivity.MSG_OP1, 101, 1001, "10001"));
            messenger.send(Message.obtain(null, MainActivity.MSG_OP2, 102, 1002, "10002"));
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

所有Messenger.send将在Handler中异步并顺序执行。

实际上,android.os.Messenger也是一个辅助界面,如果您拥有android源代码,则可以找到一个名为IMessenger.aidl的文件

package android.os;

import android.os.Message;

/** @hide */
oneway interface IMessenger {
    void send(in Message msg);
}

抱歉,我也没有看到您的答案也有约束力,我觉得您的答案也很优雅。
SkidRunner

哇....这个人的第一种方法很棒.....当您有非常好用的大/大物体时
karan

我使用方法一。这样,您可以节省时间。谢谢;
ShweLiam

非常感谢ObjectWrapperForBinder方法,真的很有帮助!
Vladimir Tolstikov '19

40

您也可以将对象的数据写入临时String和int,然后将它们传递给活动。当然,通过这种方式,您可以传输数据,而不是对象本身。

但是,如果只想显示它们,而不用其他方法或类似方法使用对象,就足够了。我以相同的方式只显示了另一个活动中一个对象的数据。

String fName_temp   = yourObject.getFname();
String lName_temp   = yourObject.getLname();
String age_temp     = yourObject.getAge();
String address_temp = yourObject.getAddress();

Intent i = new Intent(this, ToClass.class);
i.putExtra("fname", fName_temp);
i.putExtra("lname", lName_temp);
i.putExtra("age", age_temp);
i.putExtra("address", address_temp);

startActivity(i);

您也可以直接传递它们而不是临时传递它们,但是我认为这样更清楚。另外,您可以将临时值设置为null,以便尽快由GarbageCollector清除它们。

祝好运!

附带说明:重写toString()而不是编写自己的打印方法。

如以下注释中所述,这是您如何在另一活动中取回数据的方式:

String fName = getIntent().getExtras().getInt("fname");

9
使用以下命令再次获取数据:String fName = getIntent()。getExtras()。getInt(“ fname”);
Alister

2
取回数据: Bundle extras = getIntent().getExtras(); String val = extras.getString("fname");
Eric Leschinski 2012年

1
对于大型POJO,这可能很快变得不可行。宁可乘坐公共汽车。请参阅下面的我的帖子。
史蒂文·马克·福特

正如我在回答中提到的那样,这是针对简单用例的,您不需要对象本身,而只需要它的某些值。对于复杂的用例来说,解决方案并不重要。
MJB,2014年

1
传递单个对象的好主意,但是我试图传递一个未知大小的对象数组。也许您的解决方案不是传递对象数组。
穆罕默德·萨奇布

25

我制作了一个包含临时对象的单例助手类。

public class IntentHelper {

    private static IntentHelper _instance;
    private Hashtable<String, Object> _hash;

    private IntentHelper() {
        _hash = new Hashtable<String, Object>();
    }

    private static IntentHelper getInstance() {
        if(_instance==null) {
            _instance = new IntentHelper();
        }
        return _instance;
    }

    public static void addObjectForKey(Object object, String key) {
        getInstance()._hash.put(key, object);
    }

    public static Object getObjectForKey(String key) {
        IntentHelper helper = getInstance();
        Object data = helper._hash.get(key);
        helper._hash.remove(key);
        helper = null;
        return data;
    }
}

不要将对象放在Intent中,而要使用IntentHelper:

IntentHelper.addObjectForKey(obj, "key");

在新的Activity中,您可以获取该对象:

Object obj = (Object) IntentHelper.getObjectForKey("key");

请记住,一旦加载,该对象将被删除以避免不必要的引用。


1
好主意!另外可能是您可以创建其他类ObjectContainer {Object,obj; 布尔永久性 ....}的想法是,如果您需要保持对象持久性并且在调用get时不删除它,则可以在add方法中传递一个布尔值。这将有助于保留一些全局对象。像可以是开放的蓝牙连接等
Umair

1
可爱,但不要重新发明轮子。总线模式优雅且功能强大。请参阅下面的我的帖子。
史蒂文·马克·福特

@StevenMarkFord,那么直到这一天总线模式仍然适用吗?我正在尝试使用类似于以下代码的代码来改进代码库:BookActivity.getInstance().recommendationResponse在活动之间访问数据:inRoomsActivity
Woppi

重新创建接收活动后(例如,在屏幕旋转时)obj变为null。为避免这种情况,obj应将其存放在某个地方以再次获得。实际上,Json解决方案将对象数据存储在Intent中。
萨尔瓦多

25

您可以通过两种方法访问其他类或Activity中的变量或对象。

A.数据库

B.共同的偏好。

C.对象序列化。

D.可以保存通用数据的类可以称为通用实用程序。这取决于你。

E.通过意图和可打包接口传递数据。

这取决于您的项目需求。

A. 数据库

SQLite是嵌入到Android中的开源数据库。SQLite支持标准的关系数据库功能,例如SQL语法,事务和准备好的语句。

讲解

B. 共同的偏好

假设您要存储用户名。因此,现在有两件事,一个用户名, value。

如何储存

 // Create object of SharedPreferences.
 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);

 //Now get Editor
 SharedPreferences.Editor editor = sharedPref.edit();

 //Put your value
 editor.putString("userName", "stackoverlow");

 //Commits your edits
 editor.commit();

使用putString(),putBoolean(),putInt(),putFloat()和putLong()可以保存所需的dtatype。

如何取得

SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
String userName = sharedPref.getString("userName", "Not Available");

http://developer.android.com/reference/android/content/SharedPreferences.html

C. 对象序列化

如果我们要保存对象状态以通过网络发送它,或者您也可以将其用于您的目的,则使用对象序列化。

使用Java bean并将其存储为他的领域之一,并为此使用getter和setter。

JavaBean是具有属性的Java类。将属性视为私有实例变量。由于它们是私有的,因此可以从类外部访问它们的唯一方法是通过类中的方法。更改属性值的方法称为setter方法,而检索属性值的方法称为getter方法。

public class VariableStorage implements Serializable  {

    private String inString;

    public String getInString() {
        return inString;
    }

    public void setInString(String inString) {
        this.inString = inString;
    }
}

使用以下命令在您的邮件方法中设置变量

VariableStorage variableStorage = new VariableStorage();
variableStorage.setInString(inString);

然后使用对象序列化对该对象进行序列化,并在其他类中对该对象进行反序列化。

在序列化中,对象可以表示为字节序列,其中包括对象的数据以及有关对象的类型和对象中存储的数据类型的信息。

将序列化对象写入文件后,可以从文件中读取并反序列化。即,表示对象及其数据的类型信息和字节可用于在内存中重新创建对象。

如果您要使用此教程,请参考:

D. 公用事业

您可以自己创建一个类,其中可以包含项目中经常需要的通用数据。

样品

public class CommonUtilities {

    public static String className = "CommonUtilities";

}

E. 通过意图传递数据

请参阅Android – Parcel数据教程,以使用Parcelable类在Activity之间进行传递,以了解此传递数据的选项。


22

创建您自己的类Customer,如下所示:

import import java.io.Serializable;
public class Customer implements Serializable
{
    private String name;
    private String city;

    public Customer()
    {

    }
    public Customer(String name, String city)
    {
        this.name= name;
        this.city=city;
    }
    public String getName() 
    {
        return name;
    }
    public void setName(String name) 
    {
        this.name = name;
    }
    public String getCity() 
    {
        return city;
    }
    public void setCity(String city) 
    {
        this.city= city;
    }

}

用你的onCreate()方法

@Override
protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_top);

    Customer cust=new Customer();
    cust.setName("abc");
    cust.setCity("xyz");

    Intent intent=new Intent(abc.this,xyz.class);
    intent.putExtra("bundle",cust);
    startActivity(intent); 
}

xyz activity课堂上,您需要使用以下代码:

Intent intent=getIntent();
Customer cust=(Customer)intent.getSerializableExtra("bundle");
textViewName.setText(cust.getName());
textViewCity.setText(cust.getCity());

..检查您的代码,您正在传递“捆绑”作为放置客户obj的键并从“类”获取..pls使用一个“类”或“捆绑”键..
AK Joshi

我遇到错误:Parcelable遇到IOException编写可序列化对象
Arul Mani,

15

最好的方法是在您的应用程序中有一个类(称为Control),该类将保存一个类型为“ Customer”(在您的情况下)的静态变量。在活动A中初始化变量。

例如:

Control.Customer = CustomerClass;

然后转到活动B并从Control类中获取它。不要忘记在使用变量后分配空值,否则会浪费内存。


4
@aez因为从设计的角度来看它是草率的,并且如果Intent处于另一个过程中,则将严重破坏。

7
将应用恢复到活动B时会遇到问题。由于Android可能会杀死该活动,因此该对象将无法保存。
Ryan R

15
public class MyClass implements Serializable{
    Here is your instance variable
}

现在,您要在startActivity中传递此类的对象。只需使用以下命令:

Bundle b = new Bundle();
b.putSerializable("name", myClassObject);
intent.putExtras(b);

这在这里有效,因为MyClass实现了Serializable


您能否解释或详细说明
Amitsharma

HomeworkData homeworkData = homeWorksList.get(position); Intent intent = new Intent(c,HomeWorkActivitydetail.class); Bundle b = new Bundle(); b.putSerializable(“ CompleteData”,homeworkData); intent.putExtras(b); c.startActivity(intent); 在添加对象时给了我一些添加对象元素的错误,我们不能通过它传递完整的对象
吗?

在homeworkData内部,我具有一些要添加的值
Amitsharma

12

如果选择使用Samuh描述的方式,请记住只能发送原始值。也就是说,可解析的值。因此,如果您的对象包含复杂的对象,这些对象将不会跟随。例如,诸如Bitmap,HashMap等的变量。这些难以通过意图传递。

一般来说,我会建议你发送基本数据类型的演员,如String,整型,布尔等。在你的情况将是:String fnameString lnameint age,和String address

我的看法:通过实现ContentProviderSDCard等,可以更好地共享更复杂的对象。也可以使用static变量,但这可能很快导致容易出错的代码...

但是,这只是我的主观意见。


8

我正在使用parcelable将数据从一项活动发送到另一项活动。这是我的代码,在我的项目中工作正常。

public class Channel implements Serializable, Parcelable {

    /**  */
    private static final long serialVersionUID = 4861597073026532544L;

    private String cid;
    private String uniqueID;
    private String name;
    private String logo;
    private String thumb;


    /**
     * @return The cid
     */
    public String getCid() {
        return cid;
    }

    /**
     * @param cid
     *     The cid to set
     */
    public void setCid(String cid) {
        this.cid = cid;
    }

    /**
     * @return The uniqueID
     */
    public String getUniqueID() {
        return uniqueID;
    }

    /**
     * @param uniqueID
     *     The uniqueID to set
     */
    public void setUniqueID(String uniqueID) {
        this.uniqueID = uniqueID;
    }

    /**
     * @return The name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name
     *            The name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the logo
     */
    public String getLogo() {
        return logo;
    }

    /**
     * @param logo
     *     The logo to set
     */
    public void setLogo(String logo) {
        this.logo = logo;
    }

    /**
     * @return the thumb
     */
    public String getThumb() {
        return thumb;
    }

    /**
     * @param thumb
     *     The thumb to set
     */
    public void setThumb(String thumb) {
        this.thumb = thumb;
    }


    public Channel(Parcel in) {
        super();
        readFromParcel(in);
    }

    public static final Parcelable.Creator<Channel> CREATOR = new Parcelable.Creator<Channel>() {
        public Channel createFromParcel(Parcel in) {
            return new Channel(in);
        }

        public Channel[] newArray(int size) {

            return new Channel[size];
        }
    };

    public void readFromParcel(Parcel in) {
        String[] result = new String[5];
        in.readStringArray(result);

        this.cid = result[0];
        this.uniqueID = result[1];
        this.name = result[2];
        this.logo = result[3];
        this.thumb = result[4];
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {

        dest.writeStringArray(new String[] { this.cid, this.uniqueID,
                this.name, this.logo, this.thumb});
    }
}

在activityA中像这样使用它:

Bundle bundle = new Bundle();
bundle.putParcelableArrayList("channel",(ArrayList<Channel>) channels);
Intent intent = new Intent(ActivityA.this,ActivityB.class);
intent.putExtras(bundle);
startActivity(intent);

在ActivityB中像这样使用它来获取数据:

Bundle getBundle = this.getIntent().getExtras();
List<Channel> channelsList = getBundle.getParcelableArrayList("channel");

7

您可以尝试使用该类。局限性是它不能在一个进程之外使用。

一项活动:

 final Object obj1 = new Object();
 final Intent in = new Intent();
 in.putExtra(EXTRA_TEST, new Sharable(obj1));

其他活动:

final Sharable s = in.getExtras().getParcelable(EXTRA_TEST);
final Object obj2 = s.obj();

public final class Sharable implements Parcelable {

    private Object mObject;

    public static final Parcelable.Creator < Sharable > CREATOR = new Parcelable.Creator < Sharable > () {
        public Sharable createFromParcel(Parcel in ) {
            return new Sharable( in );
        }


        @Override
        public Sharable[] newArray(int size) {
            return new Sharable[size];
        }
    };

    public Sharable(final Object obj) {
        mObject = obj;
    }

    public Sharable(Parcel in ) {
        readFromParcel( in );
    }

    Object obj() {
        return mObject;
    }


    @Override
    public int describeContents() {
        return 0;
    }


    @Override
    public void writeToParcel(final Parcel out, int flags) {
        final long val = SystemClock.elapsedRealtime();
        out.writeLong(val);
        put(val, mObject);
    }

    private void readFromParcel(final Parcel in ) {
        final long val = in .readLong();
        mObject = get(val);
    }

    /////

    private static final HashMap < Long, Object > sSharableMap = new HashMap < Long, Object > (3);

    synchronized private static void put(long key, final Object obj) {
        sSharableMap.put(key, obj);
    }

    synchronized private static Object get(long key) {
        return sSharableMap.remove(key);
    }
}

6

从该活动开始另一个活动,并通过Bundle Object传递参数

Intent intent = new Intent(getBaseContext(), YourActivity.class);
intent.putExtra("USER_NAME", "xyz@gmail.com");
startActivity(intent);

检索有关另一个活动(YourActivity)的数据

String s = getIntent().getStringExtra("USER_NAME");

对于简单的数据类型,这没关系。但是,如果您想在两次活动之间传递复杂的数据。您需要先对其进行序列化。

这里有员工模型

class Employee{
    private String empId;
    private int age;
    print Double salary;

    getters...
    setters...
}

您可以使用Google提供的Gson lib来序列化复杂数据,如下所示

String strEmp = new Gson().toJson(emp);
Intent intent = new Intent(getBaseContext(), YourActivity.class);
intent.putExtra("EMP", strEmp);
startActivity(intent);

Bundle bundle = getIntent().getExtras();
String empStr = bundle.getString("EMP");
            Gson gson = new Gson();
            Type type = new TypeToken<Employee>() {
            }.getType();
            Employee selectedEmp = gson.fromJson(empStr, type);

TypeToken <>已过时。有什么选择吗?
Ragavendra M

6

在另一个堆栈溢出问题中也讨论了此问题。请查看使用Serializable通过意图传递数据的解决方案。要点是关于使用Bundle对象存储内部必要数据的Intent

 Bundle bundle = new Bundle();

 bundle.putSerializable(key1, value1);
 bundle.putSerializable(key2, value2);
 bundle.putSerializable(key3, value3);

 intent.putExtras(bundle);

要提取值:

 Bundle bundle = new Bundle();

 for (String key : bundle.keySet()) {
 value = bundle.getSerializable(key));
 }

优点Serializable是它的简单性。但是,Parcelable如果您需要传输许多数据,则应考虑使用method,因为Parcelable它是专为Android设计的,并且比效率更高Serializable。您可以Parcelable使用以下方法创建类:

  1. 在线工具-parcelabler
  2. Android Studio的插件-Android可打包代码生成器

5

创建一个像bean类这样的类并实现Serializable接口。然后,我们可以将其传递给intent方法,例如:

intent.putExtra("class", BeanClass);

然后从其他活动中获取它,例如:

BeanClass cb = intent.getSerializableExtra("class");

5

在您的自定义类中创建两个方法,如下所示

public class Qabir {

    private int age;
    private String name;

    Qabir(){
    }

    Qabir(int age,String name){
        this.age=age; this.name=name;
    }   

    // method for sending object
    public String toJSON(){
        return "{age:" + age + ",name:\"" +name +"\"}";
    }

    // method for get back original object
    public void initilizeWithJSONString(String jsonString){

        JSONObject json;        
        try {
            json =new JSONObject(jsonString );
            age=json.getInt("age");
            name=json.getString("name");
        } catch (JSONException e) {
            e.printStackTrace();
        } 
    }
}

现在在您的发件人活动中执行以下操作

Qabir q= new Qabir(22,"KQ");    
Intent in=new Intent(this,SubActivity.class);
in.putExtra("obj", q.toJSON());
startActivity( in);

在您的接收器活动中

Qabir q =new Qabir();
q.initilizeWithJSONString(getIntent().getStringExtra("obj"));

3

是的,到目前为止,使用静态对象是使用自定义不可序列化对象的最简单方法。


是的,我想我实际上同意你的看法。static如果要继续putExtra()为每个要传递的属性调用是不切实际的,则使这些对象成为更好的解决方法。例如,现在,我要传递ArrayList包含对象的。我也可以static改用ArrayList 。
马修·奎罗斯

3

Android Activity对象可以销毁并重建。因此,您将需要使用另一种方法来查看它们-或它们创建的任何对象!-起来 也就是说,您可以将其作为静态类引用进行传递,但是随后对象句柄(Java称为这些“引用”,SmallTalk也是如此;但是它们不是C或汇编语言的引用)以后可能会无效,因为“功能” Android OE的定义是,任何Activity都可以在以后被歼灭和重建。

最初的问题是“如何在Android中将对象从一个活动传递到另一个活动”,没有人回答。可以肯定的是,您可以序列化(可序列化,可打包,到JSON或从JSON)并传递对象数据的副本,并可以创建一个具有相同数据的新对象。但它不会具有相同的引用/句柄。此外,许多其他人提到您可以将引用存储在静态存储中。除非Android决定onDestroy您的Activity,否则它将起作用。

因此,要真正解决原始问题,您将需要静态查找,并且每个对象在重新创建时都会更新其引用。例如,如果每个Android Activity的onCreate被调用,它将重新列出自身。您还可以查看某些人如何使用任务列表按名称搜索活动。(系统正在临时销毁该活动实例以节省空间。.getRunningTasks,任务列表实际上是每个活动的最新对象实例的专门列表)。

以供参考:

已停止:“该活动已被另一个活动完全遮盖(该活动现在处于“后台”。)停止的活动也仍然处于活动状态(“ 活动”对象保留在内存中,它维护所有状态和成员信息,但不保留)附加到窗口管理器。)但是,它不再对用户可见,当需要在其他地方存储时,系统可以将其杀死。”

“ onDestroy”系统正在临时销毁该活动实例以节省空间。

因此,消息总线是一个可行的解决方案。它基本上是“点”。而不是尝试引用对象;然后重新设计您的设计,以使用MessagePassing代替SequentialCode。指数级难以调试;但是您可以忽略这些对OperatingEnvironment的理解。实际上,每个对象方法的访问都被反转,因此调用者发布消息,并且对象本身定义了该消息的处理程序。很多代码,但是可以使其不受Android OE限制的影响而变得强大。

如果您想要的只是顶级Activity(由于到处都需要“ Context”,则是Android应用中的典型事物),那么只要调用它的onResume,就可以让每个Activity在静态全局空间中将其自身列为“ top”。然后,您的AlertDialog或任何需要上下文的东西都可以从那里获取它。而且,使用全局有点麻烦,但是可以简化在任何地方上下传递上下文的过程,并且可以肯定的是,当您使用MessageBus时,无论如何它都是全局的。


Otto具有能够在一个普通的旧Java应用程序中外部运行它的优点。因此,对开发人员和测试人员都有利,而不必与Android混淆。Otto具有很大的学习曲线,它所解决的大部分问题已经通过Android方式(本地广播等)或常规的app开发方法(您可以编写比Otto的全局查询简单得多的全局查询来解决,普通方法很多)对于通过代码进行矢量化/ F3以及逐步调试来说更容易实现)。
TimJowers2 2014年

2
  1. 我知道static很不好,但是似乎我们不得不在这里使用它。parceables / seriazables的问题在于两个活动具有相同对象的重复实例=浪费内存和CPU。

    public class IntentMailBox {
        static Queue<Object> content = new LinkedList<Object>();
    }

通话活动

IntentMailBox.content.add(level);
Intent intent = new Intent(LevelsActivity.this, LevelActivity.class);
startActivity(intent);

被调用的活动(请注意,当系统销毁并重新创建活动时,onCreate()onResume()可能会被多次调用)

if (IntentMailBox.content.size()>0)
    level = (Level) IntentMailBox.content.poll();
else
    // Here you reload what you have saved in onPause()
  1. 另一种方法是声明要在该类中传递的类的静态字段。它仅用于此目的。不要忘记在onCreate中它可以为null,因为您的应用程序包已由系统从内存中卸载并在以后重新加载。

  2. 请记住,您仍然需要处理活动生命周期,因此您可能希望将所有数据直接写到共享的首选项,这样就很难处理复杂的数据结构。


1

以上答案几乎都是正确的,但对于那些不理解这些答案的人,Android提供了功能强大的Intent类,借助它,您不仅可以在活动而且还可以在Android的其他组件之间共享数据(广泛接收器,提供内容服务,只要我们使用ContetnResolver类就可以了) )。在您的活动中,您可以建立意图

Intent intent = new Intent(context,SomeActivity.class);
intent.putExtra("key",value);
startActivity(intent);

在您的接待活动中,您有

public class SomeActivity extends AppCompactActivity {

    public void onCreate(...){
    ...
          SomeObject someObject = getIntent().getExtras().getParceable("key");
    }

}

您必须在对象上实现Parceable或Serializable接口才能在活动之间共享。很难在对象上实现Parcealbe 而不是Serializable接口,这就是android专门为此使用插件的原因。下载并使用它


0

我一直想知道为什么这不能像调用其他活动的方法那样简单。我最近写了一个实用程序库,它几乎像这样简单。您可以在这里查看(https://github.com/noxiouswinter/gnlib_android/wiki/gnlauncher)。

GNLauncher使从另一个Activity等向一个Activity发送对象/数据变得容易,就像在Activity中以所需数据作为参数调用一个函数一样容易。它引入了类型安全性,并消除了必须进行序列化,使用字符串键附加到意图并在另一端取消该意图的所有麻烦。

用法

定义一个接口,该接口包含您要在要启动的Activity上调用的方法。

public interface IPayload {
    public void sayHello(String name, int age);
}

在要启动的Activity上实现上述接口。活动准备就绪时,还要通知GNLauncher。

public class Activity_1 extends Activity implements IPayload {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //Notify GNLauncher when the Activity is ready. 
        GNLauncher.get().ping(this);
    }

    @Override
    public void sayHello(String name, int age) {
        Log.d("gnlib_test", "Hello " + name + "! \nYour age is: " + age);
    }
}

在另一个活动中,获取上述活动的代理,并使用所需参数调用任何方法。

public class Activity_2 extends Activity {
    public void onClick(View v) {
        ((IPayload)GNLauncher.get().getProxy(this, IPayload.class, Activity_1.class)).sayHello(name, age);
    }
}

将启动第一个活动,并使用所需参数调用该方法。

先决条件

请参阅https://github.com/noxiouswinter/gnlib_android/wiki#prerequisites,以获取有关如何添加依赖项的信息。


0

将对象从一个活动传递到另一个活动。

(1)源活动

Intent ii = new Intent(examreport_select.this,
                    BarChartActivity.class);

            ii.putExtra("IntentExamResultDetail",
                    (Serializable) your List<ArraList<String>> object here);
            startActivity(ii);

(2)目的地主动性

List<ArrayList<String>> aa = (List<ArrayList<String>>) getIntent()
            .getSerializableExtra("IntentExamResultDetail");

0

我曾经用Pacelable或Serializable设置要传输的对象,但是每当我向object(model)添加其他变量时,我都必须注册它。太方便了

在活动或片段之间转移对象非常容易。

Android DataCache


0

我们可以将对象从一个活动传递到另一个活动:

SupplierDetails poSuppliersDetails = new SupplierDetails();

内部poSuppliersDetails有一些价值。现在,我将此对象发送到目标活动:

Intent iPODetails = new Intent(ActivityOne.this, ActivityTwo.class);
iPODetails.putExtra("poSuppliersDetails", poSuppliersDetails);

如何在ACtivityTwo中获得此功能:

private SupplierDetails supplierDetails;
    supplierDetails =(SupplierDetails) getIntent().getSerializableExtra("poSuppliersDetails");


-1

大家好,我看到了很多不错的选择,但是我想知道为什么未使用Binding?

对我而言,传递对对象的引用似乎比对对象进行序列化和反消毒更为有效,但是我没有深入研究该问题是否在幕后发生。

创建活页夹非常简单...

public class MyBinder extends Binder {

    private Object myObject;

    public MyBinder(Object object) {
        myObject = object;
    }

    public Object getObject() {
        return myObject;
    }

}

创建可使用的包裹并不是那么糟糕。

public class MyParcelable implements Parcelable {

    private Object myObject;

    public MyParcelable() {
    }

    public MyParcelable(Parcel parcel) {
        myObject = ((MyBinder)parcel.readStrongBinder()).getObject();
    }

    public void setObject(Object object) {
        myObject = object;
    }

    public Object getObject() {
        return myObject;
    }

    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeStrongBinder(new MyBinder(myObject));
    }

    public int describeContents() {
        return myObject == null ? 0 : 1;
    }

    public static final Parcelable.Creator<MyParcelable> CREATOR = new Parcelable.Creator<MyParcelable>() {

        public MyParcelable createFromParcel(Parcel parcel) {
            return new MyParcelable(parcel);
        }

        public MyParcelable[] newArray(int length) {
            return new MyParcelable[length];
        }

    };
}

这种逻辑真的很酷,因为您实际上是在活动之间传递引用。

我建议检查null以及Binder的instanceof是MyBinder!

并实现这一点,您只需...

发送出去

Object myObject = "some object";
MyParcelable myParcelable = new MyParcelable();
myParcelable.setObject(myObject);

intent.putExtra("MyParcelable", myParcelable);

拿回来

myParcelable = (MyParcelable) getIntent().getExtras().getParcelable("MyParcelable");
myObject = myParcelable.getObject();

哎呀,有人可能会全都疯了,使这个傻瓜成为真正的仿制药。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.