我正在尝试从一个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上显示数据。

我该如何实现?

评论

可能您应该根据大众意见来更改接受的答案。

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

我创建了一个包装器TrackedReference ,该包装器可打包且可序列化,而无需对基础类型进行封送处理(序列化或打包):stackoverflow.com/a/64944753/3405387

为什么不只使用静态变量并从其他活动访问它,而不在内存中重新创建它,并且对象的消灭可能会消耗资源。

#1 楼

一种选择是让您的自定义类实现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() {}
    }
}


评论


@OD:在我的辩护中,我从未说过这是最好的选择。 OP只是问其他选择,我建议了一个。无论如何谢谢。

– Samuh
2011年5月9日21:09

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

–内特
2011年8月21日在23:48

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

– Slauma
2011年10月2日,16:26

打包可能有利于提高速度,但实现起来很复杂。如果您需要在活动之间传递8个对象,该怎么办?改为使用Serializable。当您实现Parcelable时,您必须向该类添加大量代码,并以非常特定的方式对字段进行排序。您不可以序列化。最终,我认为这取决于您传递的对象数和尝试执行的操作。

–BlackHatSamurai
2012年8月14日在2:41



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

– Gaurav Arora
2012年12月6日7:41



#2 楼

使用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");


就是这样。

评论


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

– JibW
2012年2月21日15:39



@MustafaGüven但是我这样做却得到了classCastException:java.lang.Long。你能解释为什么吗?

– Shajeel Afzal
2013年6月17日19:06



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

–穆斯塔法·古文(MustafaGüven)
13年6月18日在13:18

对于大型POJO,可序列化太慢。使用总线是一种更好的方式。

–史蒂芬·马克·福特(Steven Mark Ford)
14年7月24日在23:35

为什么我必须在对象之前加上前缀(可序列化)?

–阿尔斯通
2014-09-24 9:53



#3 楼


使用全局静态变量不是良好的软件工程实践。

将对象的字段转换为原始数据类型可能会很忙。
使用serializable可以,但是在Android平台上性能不高。

Parcelable是专为Android设计的,您应该使用它。这是一个简单的示例:在Android活动之间传递自定义对象


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

评论


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

– aNdRO博士
2014年3月27日13:26

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

–VH-NZZ
14年5月13日在10:43

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

–史蒂芬·马克·福特(Steven Mark Ford)
2014年7月24日在23:27

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

–重新
15年3月29日在18:54

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

–断线
16年2月26日在8:05

#4 楼

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

build.gradle中,将其添加到依赖项中。将对象转换为json-string:

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


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

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


对于Kotlin来说完全一样

传递数据

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


接收数据

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


评论


gson有点过分,只是对json进行字符串序列化的一种,更好地实现Serializable或Paracable。

–詹姆斯·罗伊特(James Roeiter)
2013年12月22日18:30



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

–射手
15年1月22日在14:03

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

– nurgasemetey
2015年2月9日在11:02

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

–乍得宾厄姆
16年4月16日在20:42

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

– Ojonugwa Jude Ochalifu
17年8月9日在12:11

#5 楼

在调用活动时

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作为第一个参数传入。有没有办法在接收活动类中检索此对象?

– newman
2011-09-10 21:28

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

–广告
2011-09-12 8:23

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

– newman
2011-09-25 3:08

miliu,请与我们分享您的例外情况跟踪,以便我们进行调查。

–广告
2011-09-26 8:06



Parcelable具有许多不必要的样板代码,坦率地说是浪费时间。宁可乘坐公共汽车。请参阅下面的我的帖子。

–史蒂芬·马克·福特(Steven Mark Ford)
2014年7月24日23:30

#6 楼

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


实现Parcelable
实现Serializable
使用轻量级的事件总线库排序(例如Greenrobot的EventBus或Square的Otto)

可拆分-快速和Android标准,但是它具有大量样板代码,并且在提取值时需要硬编码的字符串以供参考(非

可序列化-接近零样板,但这是最慢的方法,并且在将值拉出意图时(非强类型)还需要使用硬编码的字符串。
<事件总线-零样本,最快的方法,并且不需要硬编码的字符串,但是它确实需要附加的依赖项(尽管通常是轻量级的,大约40 KB)

我发布了非常详细的比较这三种方法,包括效率基准。

评论



链接断开很遗憾:(

–莫克
17年6月28日在19:04

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

–朱利兹(JuliuszJ)
18年2月6日在10:03

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


19年4月16日在10:36

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

– Yos Apps
19年6月19日在15:48

#7 楼

我找到了一种简单而优雅的方法:


否可拆分
否可序列化
没有静态字段
没有事件总线

方法1

第一个活动的代码:

    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”)*

class ObjectWrapperForBinder定义

public class ObjectWrapperForBinder extends Binder {

    private final Object mData;

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

    public Object getData() {
        return mData;
    }
}


方法2



对于发送方,


使用自定义本机方法将Java对象添加到JNI全局引用表中(通过JNIEnv :: NewGlobalRef)
输入返回整数(实际上是JNIEnv :: NewGlobalRef返回jobject,它是一个指针,我们可以将其安全地转换为int)到您的Intent(通过Intent :: putExtra)


用于接收者


从Intent中获取整数(通过Intent :: getInt)
使用自定义本机方法从JNI全局引用表还原Java对象(通过JNIEnv :: NewLocalRef)
从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
16年7月13日在19:57

哇....这个人的第一种方法很棒.....当您有非常大/更大的对象时,它可以很好地工作

–卡兰
19年4月17日在10:32



非常感谢ObjectWrapperForBinder方法,真的很有帮助!

–弗拉基米尔·托尔斯蒂科夫(Vladimir Tolstikov)
19年12月10日在16:05

这种方法确实非常出色:轻巧而直接。我只需要在运行时检查API级别,因为putBinder需要达到18级。我已经完成了类似的工作(android.os.Build.VERSION.SDK_INT> = Build.VERSION_CODES.JELLY_BEAN_MR2),它的工作原理很吸引人。我正在使用方法1。

–Gauthier
7月10日下午16:34

#8 楼

您也可以将对象的数据写入临时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");


评论


使用以下字符串再次获取数据:String fName = getIntent()。getExtras()。getInt(“ fname”);

– Alister
2010-10-30 5:17



取回数据:捆绑包= getIntent()。getExtras();字符串val = extras.getString(“ fname”);

–埃里克·莱斯钦斯基(Eric Leschinski)
2012年1月1日1:00



对于大型POJO,这可能很快变得不可行。宁可乘坐公共汽车。请参阅下面的我的帖子。

–史蒂芬·马克·福特(Steven Mark Ford)
2014年7月24日23:31



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

– MJB
2014年7月31日在11:54

传递单个对象的好主意,但是我试图传递一个未知大小的对象数组。也许您的解决方案不是传递对象数组。

–穆罕默德·萨奇布(Muhammad Saqib)
15年8月26日在9:33

#9 楼

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

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");


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

评论


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

– Umair
2012-09-26 5:59



可爱,但不要重新发明轮子。总线模式优雅且功能强大。请参阅下面的我的帖子。

–史蒂芬·马克·福特(Steven Mark Ford)
14年7月24日在23:34

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

– Woppi
17年12月20日在12:32

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

–萨尔瓦多
18年8月7日在13:46

#10 楼

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

A.数据库

B。共享的首选项。

C.对象序列化。

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

E.通过Intent和Parcelable接口传递数据。

这取决于您的项目需求。

A.数据库

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

教程

B。共享的首选项

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

如何存储
 // 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);


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

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

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

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


Java中的序列化(博客文章)
获取其他类中的变量(堆栈溢出)

D。 CommonUtilities

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

示例


public class CommonUtilities {

    public static String className = "CommonUtilities";

}


E.通过意图传递数据

有关传递数据的选项,请参考教程Android –包裹数据以使用Parcelable类在活动之间传递。

#11 楼

创建自己的类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
2014年11月21日下午6:18

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

– Arul Mani
19 Mar 29 '19在9:52

#12 楼

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

Control.Customer = CustomerClass;


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

评论


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

–user166390
2013年1月15日在3:22



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

– Ryan R
13年1月18日在17:39

#13 楼

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


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

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


之所以可以在这里使用,是因为MyClass实现了Serializable

评论


你能解释或详细说明吗

–阿米沙玛
16 Sep 30'7:05

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);在添加对象时给了我一些添加对象元素的错误,我们不能以此传递完整的对象

–阿米沙玛
16-09-30在7:07

在homeworkData内部我有一些值要添加

–阿米沙玛
16-09-30在7:08

#14 楼

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

一般而言,我建议您仅发送原始数据类型作为额外内容,例如String,int,boolean等在您的情况下,它将是:String fnameString lnameint ageString address

我的观点:通过实现ContentProvider,SDCard等,可以更好地共享更复杂的对象。变量,但这可能会很快导致易于出错的代码...

但是,这再次是我的主观意见。

#15 楼

我正在使用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");


#16 楼

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

一个活动:

 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);
    }
}


#17 楼

从此活动开始另一个活动,并通过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 <>已过时。还有什么?

–拉加文德拉M
18年2月26日在9:18

#18 楼

在另一个堆栈溢出问题中也讨论了此问题。请查看使用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方法,因为Parcelable是专门为Android设计的,并且比Serializable更有效。您可以使用以下工具创建Parcelable类:


在线工具-parcelabler

Android Studio插件-Android Parcelable代码生成器


#19 楼

创建一个类似于bean类的类并实现Serializable接口。然后我们可以通过intent方法传递它,例如:

intent.putExtra("class", BeanClass);


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

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


#20 楼

在您的自定义类中创建两个这样的方法

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"));


#21 楼

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

评论


是的,我想我实际上同意你的看法。如果要为要传递的每个属性连续调用putExtra()根本不切实际,则使这些对象为静态是更好的解决方法。例如,现在,我想传递一个包含对象的ArrayList。我也可以将ArrayList设为静态。

–MLQ
11年8月18日在6:21

#22 楼

Android Activity对象可以销毁并重建。因此,您将需要使用另一种方法来查看它们-或它们创建的任何对象! -起来也就是说,您可以将其作为静态类引用进行传递,但是对象句柄(Java称为这些“引用”,SmallTalk也是如此;但它们不是C或汇编语言的引用)以后可能会无效,因为“功能” Android OE的任何Activity都可以在以后被消灭和重建。
最初的问题是“如何在Android中将对象从一个活动传递到另一个活动”,没有人回答。可以肯定的是,您可以序列化(可序列化,可打包,到JSON或从JSON)并传递对象数据的副本,并可以创建具有相同数据的新对象。但它不会具有相同的引用/句柄。此外,许多其他人提到您可以将引用存储在静态存储中。除非Android决定onDestroy您的Activity,否则此方法将起作用。
因此,要真正解决最初的问题,您需要静态查找,而且每个对象都会在创建/重新创建引用时更新其引用。例如。如果调用其onCreate,则每个Android Activity都会重新列出自身。您还可以查看某些人如何使用任务列表按名称搜索“活动”。 (系统正在临时销毁该活动实例以节省空间。.getRunningTasks,任务列表实际上是每个活动的最新对象实例的专门列表)。
作为参考:

Stopped:
“该活动已被另一个活动完全遮盖(该活动现在位于“后台”)。停止的活动也仍然存在(活动对象保留在内存中,它维护所有状态和成员信息,但未附加到窗口管理器上。)但是,它不再对用户可见,并且在其他地方需要内存时可以被系统杀死。“
onDestroy
”系统是暂时的销毁该活动实例以节省空间。“

因此,消息总线是一种可行的解决方案。它基本上是“点”。而不是尝试引用对象;然后您可以重新设计设计,以使用MessagePassing而不是SequentialCode。指数级难以调试;但是您可以忽略这些对OperatingEnvironment的理解。实际上,每个对象方法的访问都被反转,因此调用者发布消息,并且对象本身定义了该消息的处理程序。更多代码,但可以使其不受Android OE限制的影响而变得强大。
如果您想要的只是顶级Activity(由于到处都需要“ Context”,则是Android应用中的典型事物),那么您只需拥有每个Activity列表每当调用其onResume时,其自身就为静态全局空间中的“顶部”。然后,您的AlertDialog或任何需要上下文的东西都可以从那里获取它。同样,使用全局变量有点麻烦,但是可以简化在任何地方上下传递上下文的过程,并且可以肯定的是,当您使用MessageBus时,无论如何它都是全局的。

评论


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

– TimJowers2
2014年9月8日15:24



#23 楼



我知道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()



另一种方法是声明要在该类中传递的类的静态字段。它仅用于此目的。不要忘记在onCreate中它可以为null,因为您的应用包已由系统从内存中卸载并在以后重新加载。
请记住,您仍然需要处理活动生命周期,因此您可能需要编写所有数据直指共享首选项,却难以处理复杂的数据结构。


#24 楼

以上答案几乎都是正确的,但对于那些不理解这些答案的人来说,
Android具有强大的Intent类,借助它,您不仅可以在活动而且还可以在Android的其他组件之间共享数据(Broadcasr接收器,提供内容供我们使用ContetnResolver类没有Intent)。
在您的活动中建立intent

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专门为此使用插件的原因。下载并使用它

#25 楼

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

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

用法

定义接口使用您要调用的Activity来启动的方法。

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


在上述Activity上实现上述接口以启动。
当活动已准备就绪。

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。

#26 楼

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

(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");


#27 楼

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

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

Android DataCache

#28 楼

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

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");


#29 楼

将一项活动传递给另一项活动:

startActivity(new Intent(getBaseContext(),GetActivity.class).putExtra("passingkey","passingvalue"));


获取值:

String myvalue= getIntent().getExtras("passingkey");


#30 楼

序列化任何类型的对象都是不可能的。例如,您不能序列化承载代码而不是数据的委托方法或接口。
所以我写了一个'Box'类,您可以使用它传递任何类型的数据而无需序列化。

1-用于将数据放入意图中使用:

Intent I = new Intent(this, YourActivity.class);
CustomClass Date = new CustomClass();
Box.Add(I, "Name", Data);


2-用于从意图中获取数据:

CustomClass Data = Box.Get(getIntent(), "Name");


3-要在使用后删除数据,请将此方法添加到您的活动中: >
@Override
protected void onDestroy() {
    Box.Remove(getIntent());
    super.onDestroy();
}


** Box类是线程安全的。