ChatGPT解决这个技术问题 Extra ChatGPT

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

我正在尝试从一个 Activity 发送我的 customer 类的对象并将其显示在另一个 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<Any>它是可打包和可序列化的,无需对基础类型进行编组(序列化或打包):stackoverflow.com/a/64944753/3405387
为什么不只使用静态变量并从其他活动中访问它,而不在内存中重新创建它,并且对象的灭菌也可能会消耗资源。

G
GeneCode

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

实际代码:

在您的自定义模型/对象类中:

public class YourClass implements Serializable {

在使用自定义模型/类的其他类:

//To pass:
intent.putExtra("KEY_NAME", myObject);

myObject 的类型为“YourClass”。然后从另一个活动中检索,使用 getSerializableExtra 使用相同的键名获取对象。并且需要对 YourClass 进行类型转换:

// To retrieve object in second Activity
myObject = (YourClass) getIntent().getSerializableExtra("KEY_NAME");

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

class MainClass implements Serializable {
    
    public MainClass() {}

    public static class ChildClass implements Serializable {
         
        public ChildClass() {}
    }
}

@OD:在我的辩护中,我从来没有说过这是最好的选择; OP 只是要求提供替代方案,我建议了一个。不管怎么说,多谢拉。
为什么 Serializable 不是一个好的选择?这是一个众所周知的接口,人们的类很可能已经实现了它(例如,ArrayList 已经是可序列化的)。为什么你必须改变你的数据对象来添加额外的代码只是为了将它们从一个类传递到另一个类?这似乎是一个糟糕的设计。我可以想象在某种程度上可能会对性能产生一些影响,但我认为在 99% 的情况下,人们传递的是少量数据,他们不会在意。更简单、更便携有时也更好。
@Sander:那么这个答案(stackoverflow.com/questions/2139134/…)错了吗?他说 Parcelable IS 专门为此目的而设计(并且比 Serializable 快得多)。我是一个困惑。
Parcelable 可能有助于提高速度,但实施起来很复杂。如果你有 8 个对象需要在 Activity 之间传递,你会让每个对象都变成 Parcelable 吗?改用 Serializable 会更有意义。当您实现 Parcelable 时,您必须向类中添加大量代码,并以非常具体的方式对字段进行排序; Serializable 你没有。归根结底,我认为这取决于你通过了多少物体以及你想要做什么。
Serializable 是标准 Java 接口。您只需通过实现接口标记一个类 Serializable,Java 会在某些情况下自动序列化它。 Parcelable 是您自己实现序列化的 Android 特定接口。它的创建比 Serializable 更有效,并解决了默认 Java 序列化方案的一些问题
P
Peter Mortensen

用 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"); ] ... 是吗 ???
@MustafaGüven 但这样做我得到了classCastException: java.lang.Long。你能解释一下为什么吗?
与我的回答没有任何关系。你得到的是非常不同的东西。你能分享你的代码吗?
Serializable 对于大型 POJO 来说太慢了。使用总线是一种更好的模式。
为什么我必须为对象添加 (Serializable) 前缀?
k
kuzdu

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

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

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

在您的活动中,将对象转换为 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)

它是一种矫枉过正,gson 只是 json 的一种字符串序列化,最好实现 Serializable 或 Paracable 。
如果您可以使用处理它的库(gson),则无需在每个对象和每个项目中实现可序列化(浪费时间)。关于矫枉过正,那里有双核和四核手机,他们甚至可以按照这个答案的想法处理一个列表。
我还建议使用 gson,因为 gson 除了上述之外还可以序列化数组列表。
这很棒!就我而言,我正在使用一个对象没有实现可序列化或可打包的库。所以这是我唯一的选择afaik
这是“最佳”选项。有些类非常简单,你不需要通过实现可序列化来过度复杂化它们的实现
S
Suragch

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

将对象的字段转换为原始数据类型可能是一项繁重的工作。

使用可序列化是可以的,但它在 Android 平台上的性能效率不高。

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

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


如果我的对象包含嵌套的 Arraylist 怎么办?
也许好吧,但人们真的应该对“表现”持保留态度。如果这是以实现 Parcelable 为代价的,那么我宁愿让我的 POJO 类与 Android 无关并使用 Serializable
我不同意你应该使用 Parcelable。一个简单的 BUS 模式在运行时效率更高,并且节省了大量的开发时间。
根据这个基准 bitbucket.org/afrishman/androidserializationtest,Serializable 比 Parcelable 快得多。请停止分享这个 5 年前关于 Parcelable 的废话。
全局静态变量如何“不是好的软件工程实践”?您可以制作诸如单例缓存和/或数据网格之类的东西,然后传递 ID 或类似的东西。当您在 Java 中传递引用时,无论如何您都在使用全局静态变量,因为它们指向同一个对象。
A
Ads

调用活动时

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

在 toClass.java 中通过以下方式接收活动

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

请确保客户类实现 parcelable

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

阿达文,我有一个问题。创建第一个 Intent 类时,传入 fromClass.this 作为第一个参数。有没有办法在接收活动类中检索这个对象?
Miliu, fromClass fr = (fromClass) getParent();这是你需要的吗?
Adhava,我实际上是这样做的,但 fr 为空。知道为什么吗?
miliu,请分享您的异常跟踪,以便我们进行调查。
Parcelable 有很多不必要的样板代码,坦率地说是浪费时间。而是使用公共汽车。请看我下面的帖子。
E
Emad

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

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

Parcelable - 快速且符合 Android 标准,但它包含大量样板代码,并且在将值拉出意图(非强类型)时需要硬编码字符串以供参考。

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

Event Bus - 零样板,最快的方法,并且不需要硬编码字符串,但它确实需要额外的依赖项(尽管通常是轻量级的,~40 KB)

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


该文章的链接已失效。仍可在网络存档中找到:web.archive.org/web/20160917213123/http://…
可惜链接失效了:(
事件总线的使用问题是当目标 Activity 由于旋转而重新创建时。在这种情况下,目标 Activity 无法访问传递的对象,因为该对象已被较早的调用从总线消耗。
Parcelable 是最快的,使用此生成器 (parcelabler.com),您可以粘贴您的类,它可以为您生成代码。简单的。
@ByWaleed ...我绝对同意,我总是使用这个网站,制作东西没有任何麻烦。但是,当我尝试使用由另一个对象组成的 POJO 时,我有很多不成功的尝试。由于某种原因,它的输出并没有真正起作用。
Y
Yessy

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

没有可包裹的

没有可序列化的

无静态场

没有事件总线

方法一

第一个活动的代码:

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

你会发现 objSent & objReceived 具有相同的 hashCode,因此它们是相同的。

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

实际上,android binder 会为 java 对象创建全局 JNI 引用,并在该 java 对象没有引用时释放这个全局 JNI 引用。 binder 会将这个全局 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;
    }
}

方法二

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

使用自定义本机方法将您的 java 对象添加到 JNI 全局引用表(通过 JNIEnv::NewGlobalRef)

将返回整数(实际上是 JNIEnv::NewGlobalRef 返回 jobject,它是一个指针,我们可以安全地将其转换为 int)到您的 Intent(通过 Intent::putExtra)

对于接收者从 Intent 获取整数(通过 Intent::getInt)使用自定义本地方法从 JNI 全局引用表(通过 JNIEnv::NewLocalRef)中恢复您的 java 对象从 JNI 全局引用表中删除项目(通过 JNIEnv::DeleteGlobalRef),

从 Intent 获取整数(通过 Intent::getInt)

使用自定义本机方法从 JNI 全局引用表中恢复您的 java 对象(通过 JNIEnv::NewLocalRef)

从 JNI 全局引用表中删除项目(通过 JNIEnv::DeleteGlobalRef),

但是方法2有个小问题,如果receiver恢复java对象失败(比如恢复java对象之前发生异常,或者receiver Activity根本不存在),那么java对象就会变成一个orphan or memory leak, Method 1没有这个问题,因为android binder会处理这个异常

方法三

要远程调用 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();
    }

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

方法四

方法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也是一个aidl接口,如果你有android源码的话,可以找到一个名为IMessenger.aidl的文件

package android.os;

import android.os.Message;

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

抱歉,我没有看到您的回答也有约束力,我觉得您的回答也很优雅。
哇......这个人的第一种方法很棒......当你有非常大/更大尺寸的物体时效果很好
非常感谢 ObjectWrapperForBinder 方法,真的很有帮助!
这种方法真的很棒:简单明了。我只需要在运行时检查 API 级别,因为 putBinder 需要 18 级。我已经完成了类似 (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) 的操作,它就像一个魅力。我正在使用方法1。
P
Peter Mortensen

您还可以将对象的数据写入临时字符串和整数,并将它们传递给活动。当然,通过这种方式,您可以传输数据,但不能传输对象本身。

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

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,以便垃圾收集器更快地清理它们。

祝你好运!

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

正如下面的评论中提到的,这是您在另一个活动中获取数据的方式:

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

使用以下命令再次取回数据: String fName = getIntent().getExtras().getInt("fname");
要取回数据:Bundle extras = getIntent().getExtras(); String val = extras.getString("fname");
对于大型 POJO,这很快就会变得不可行。而是使用公共汽车。请看我下面的帖子。
正如我在回答中提到的那样,这适用于不需要对象本身的简单用例,而只需要它的一些值。成为复杂用例的解决方案并不重要。
传递单个对象是个好主意,但我试图传递一个未知大小的对象数组。也许您的解决方案不是用于传递对象数组。
R
Roger Sanoli

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

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

在您的新活动中,您可以获取对象:

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

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


好主意!另外可能你可以创建一个额外的类 ObjectContainer { Object, obj;布尔永久; ....} 想法是,如果您需要保持对象持久性并且在我们调用 get 时不要删除,您可以在 add 方法中传递一个布尔值。这将有助于保留一些全局对象。比如可能是一个开放的蓝牙连接等。
可爱但不要重新发明轮子。总线图案优雅,功能更强大。请看我下面的帖子。
@StevenMarkFord 那么巴士模式直到今天仍然适用吗?我正在尝试使用类似这样的代码来改进代码库,以访问活动之间的数据:RoomsActivity 中的 BookActivity.getInstance().recommendationResponse
当重新创建接收活动时(例如在屏幕旋转时)obj 变为 null。为避免这种情况,应将 obj 存储在某个地方以便再次获取它。事实上,Json 解决方案将对象数据存储在 Intent 中。
C
Community

有几种方法可以访问其他类或 Activity 中的变量或对象。

A. 数据库

B. 共享偏好。

C. 对象序列化。

D. 可以保存公共数据的类可以命名为Common Utilities。这取决于你。

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

这取决于您的项目需求。

A. 数据库

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

Tutorials

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(),您可以保存所需的数据类型。

如何获取

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。

JavaBeans 是具有属性的 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 – Parcel data to pass between Activities using Parcelable classes,了解此传递数据的选项。


Y
Yo Apps

创建您自己的类 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());

..检查您的代码,您将“bundle”作为放置 cust obj 的键并从“class”获取 ..请使用“class”或“bundle”中的一个键..
我面临错误:Parcelable 遇到 IOException 写入可序列化对象
P
Peter Mortensen
public class MyClass implements Serializable{
    Here is your instance variable
}

现在你想在 startActivity 中传递这个类的对象。只需使用这个:

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

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


你能解释一下或详细说明吗
HomeworkData homeworkData = homeWorksList.get(position); Intent intent = new Intent(c, HomeWorkActivitydetail.class);捆绑 b = 新捆绑(); b.putSerializable("CompleteData", homeworkData);意图.putExtras(b); c.startActivity(intent);在添加对象时给我一些添加对象元素的错误我们不能用这个传递完整的对象吗
在 homeworkData 我有一些值,这些是要添加的
P
Peter Mortensen

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

例如:

Control.Customer = CustomerClass;

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


@aez 因为从设计的角度来看它是草率的,如果 Intent 曾经在另一个进程中,它会严重破坏。
将应用程序恢复到 Activity B 时会遇到问题。由于 Activity 可以被 Android 杀死并且对象不会被保存。
P
Peter Mortensen

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

一般来说,我建议您只发送原始数据类型作为附加值,例如字符串、整数、布尔值等。在您的情况下,它将是:String fnameString lnameint ageString address

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

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


P
Peter Mortensen

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

P
Peter Mortensen

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

一项活动:

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

D
DroidNinja

从此活动开始另一个活动并通过捆绑对象传递参数

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...
}

您可以使用谷歌提供的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);

A
Ayaz Alifov

这个问题也在另一个 Stack Overflow 问题中进行了讨论。请查看a solution to Passing data through intent using 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 代码生成器


P
Peter Mortensen

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

intent.putExtra("class", BeanClass);

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

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

k
kartikmaji

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

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

C
Community

Android Activity 对象可以被销毁和重构。因此,您将需要使用另一种方法来查看它们 - 或它们创建的任何对象!!! - 向上。也就是说,您可以作为静态类引用传递,但是对象句柄(Java 调用这些“引用”,SmallTalk 也是如此;但它们不是 C 或程序集意义上的引用)稍后可能会无效,因为“特性” Android OE 是任何 Activity 都可以在以后消灭和重组。

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

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

以供参考:

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

因此,消息总线是一个可行的解决方案。它基本上是“平底船”。而不是尝试引用对象;然后您重新设计您的设计以使用 MessagePassing 而不是 SequentialCode。指数级地难以调试;但它让你忽略这些操作环境的理解。实际上,每个对象方法的访问都是反向的,因此调用者发布了一条消息,并且对象本身为该消息定义了一个处理程序。更多代码,但可以使其在 Android OE 限制下变得健壮。

如果您想要的只是顶级活动(Android 应用程序中的典型事情,因为到处都需要“上下文”),那么只要调用 onResume,您就可以让每个活动在静态全局空间中将自己列为“顶级”。然后您的 AlertDialog 或任何需要上下文的东西都可以从那里获取它。此外,使用全局有点讨厌,但可以简化在任何地方上下传递上下文,并且可以肯定的是,当您使用 MessageBus 时,无论如何它都是全局的。


Otto 有能力在一个普通的旧 Java 应用程序中从外部运行它。因此,对开发和测试很有用,而不必与 Android 混为一谈。 Otto 有很大的学习曲线,它解决的大部分问题已经通过 Android 方式(本地广播等)或普通的应用程序开发方法解决(你可以编写比 Otto 的全局查找更简单的全局查找,普通方法很多更容易通过代码进行矢量/F3 和单步调试)。
a
alistair

是的,使用静态对象是迄今为止使用自定义不可序列化对象执行此操作的最简单方法。


是的,我想我实际上同意你的看法。如果为您想要传递的每个属性继续调用 putExtra() 根本不切实际,那么将这些对象设为 static 是更好的解决方法。例如,现在,我想传递一个包含对象的 ArrayList。我不妨让我的 ArrayList static 代替。
P
Peter Mortensen

我知道静态是不好的,但似乎我们不得不在这里使用它。 parceables/seriazables 的问题在于这两个活动具有相同对象的重复实例 = 浪费内存和 CPU。公共类 IntentMailBox { static Queue 内容 = new LinkedList(); }

通话活动

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

被调用的activity(注意onCreate()和onResume()在系统销毁和重新创建activity时可能会被调用多次)

if (IntentMailBox.content.size()>0)
    level = (Level) IntentMailBox.content.poll();
else
    // Here you reload what you have saved in onPause()

另一种方法是声明要在该类中传递的类的静态字段。它将仅用于此目的。不要忘记在onCreate中它可以为null,因为你的应用包已经被系统从内存中卸载并在稍后重新加载。请记住,您仍然需要处理活动生命周期,您可能希望将所有数据直接写入共享首选项,这对于复杂的数据结构来说很痛苦。


d
dara

以上答案几乎都是正确的,但对于那些不理解这些答案的人来说,Android 有强大的类 Intent 借助它,您不仅可以在活动之间共享数据,还可以在 Android 的其他组件之间共享数据(广播接收器,内容服务提供我们使用 ContetnResolver 类没有 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 有专门为此而设计的插件。下载并使用它


S
Subhajit Roy

像这样创建您的自定义类:

公共类测试实现 Parcelable { 字符串消息;

protected Test(Parcel in) {
    message = in.readString();
}

public static final Creator<Test> CREATOR = new Creator<Test>() {
    @Override
    public Test createFromParcel(Parcel in) {
        return new Test(in);
    }

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

public String getMessage() {
    return message;
}

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

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(message);
}

像这样使用 Intent 发送数据:在开始你的活动之前必须设置一些数据

Intent intent = new Intent(context, PostDetailsActivity.class);
                intent.putExtra("data", (Parcelable) test);
                ((context)).startActivity(intent);

从这样的意图中获取数据:

Test test = (Test) getIntent().getParcelableExtra("data");

请使用 Parcelable,它通过进程边界的速度比 Serializable 快大约 10 倍。
谢谢您的支持。我了解它并升级它。
j
jinais

我一直想知道为什么这不能像调用其他活动的方法那么简单。我最近编写了一个实用程序库,使它几乎就这么简单。您可以在此处查看 (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);
    }
}

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

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


J
Jayesh Kalkani

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

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

k
kimkevin

我曾经使用 Pacelable 或 Serializable 设置对象以进行传输,但是每当我将其他变量添加到对象(模型)时,我都必须将其全部注册。太不方便了

在活动或片段之间传输对象非常容易。

Android DataCache


P
Peter Mortensen

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

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

h
hering

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

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

获取值:

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