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

How to pass an object from one activity to another on Android

我正在尝试从一个Activity发送我的客户类的对象,并将其显示在另一个Activity中。

客户类的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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,然后在另一个Activity上显示数据。

我怎样才能做到这一点?


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

伪代码:

1
2
3
4
5
//To pass:
intent.putExtra("MyClass", obj);

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

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

1
2
3
4
5
6
7
8
9
class MainClass implements Serializable {

    public MainClass() {}

    public static class ChildClass implements Serializable {

        public ChildClass() {}
    }
}


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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活动的某个地方;

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

在Y活动中,我们得到了对象。

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

而已。


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

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


在调用活动时

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

在toClass.java中接收活动

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

请确保客户类实现parcelable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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();
    }


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

build.gradle中,将其添加到依赖项中

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

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

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

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

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

对于Kotlin来说,它是完全相同的

传递数据

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

接收数据

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


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

  • 实现Parcelable

  • 实现Serializable

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

  • Parcelable - 快速和Android标准,但它有很多样板代码,并且需要硬编码字符串以便在将值拉出意图时进行参考(非强类型)。

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

    事件总线 - 零样板,最快的方法,并且不需要硬编码字符串,但它确实需要额外的依赖性(尽管通常是轻量级的,~40&nbsp; KB)

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


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

    但是如果你只想显示它们,而不是在另一种方法或类似的东西中使用该对象,那就足够了。我这样做只是为了显示来自另一个活动中的一个对象的数据。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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);

    你也可以直接传递它们而不是temp ivars,但在我看来这种方式更清晰。此外,您可以将temp ivars设置为null,以便GarbageCollector更快地清除它们。

    祝好运!

    旁注:覆盖toString()而不是编写自己的print方法。

    如下面的评论中所述,这是您将数据恢复到另一个活动中的方式:

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


    我找到了一个简单的&amp;优雅的方法:

    • 没有可分辨
    • 没有可序列化
    • 没有静电场
    • 没有活动巴士

    方法1

    第一项活动的代码:

    1
    2
    3
    4
    5
        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);

    第二项活动的代码:

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

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

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

    实际上,android binder将为java对象创建全局JNI引用,并在没有此java对象的引用时释放此全局JNI引用。 binder将在Binder对象中保存此全局JNI引用。

    *注意:除非两个活动在同一个进程中运行,否则此方法只能工作,否则在(ObjectWrapperForBinder)getIntent()抛出ClassCastException。getExtras()。getBinder("object_value")*

    class ObjectWrapperForBinder defination

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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 binder会处理这个异常

    方法3

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

    IDataContract.aidl

    1
    2
    3
    4
    5
    package com.example.objectwrapper;
    interface IDataContract {
        int func1(String arg1);
        int func2(String arg1);
    }

    第一项活动的代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
        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属性更改为非空进程名称,以确保第二个活动在另一个进程中运行

    1
    2
    3
    4
    5
    6
    7
        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

    第一个活动的代码(发件人):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    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)));
        }
    }

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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的文件。

    1
    2
    3
    4
    5
    6
    7
    8
    package android.os;

    import android.os.Message;

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


    我创建了一个包含临时对象的单例辅助类。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    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:

    1
    IntentHelper.addObjectForKey(obj,"key");

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

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

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


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

    A.数据库

    B.共享偏好。

    C.对象序列化。

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

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

    这取决于您的项目需求。

    A.数据库

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

    教程

    B.共享偏好

    假设您要存储用户名。所以现在有两件事,一个关键用户名,价值值。

    如何存储

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     // 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。

    如何获取

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

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

    C.对象序列化

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

    使用Java bean并将其作为其中一个字段存储在其中,并使用getter和setter。

    JavaBeans是具有属性的Java类。考虑到
    属性作为私有实例变量。因为他们是私人的,唯一的方法
    可以通过类中的方法从类外部访问它们。更改属性值的方法称为setter方法,而检索属性值的方法称为getter方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class VariableStorage implements Serializable  {

        private String inString;

        public String getInString() {
            return inString;
        }

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

    使用在邮件方法中设置变量

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

    然后使用对象序列化来序列化此对象,并在其他类中反序列化此对象。

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

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

    如果你想要这个教程,请参考:

    • Java中的序列化(博客文章)

    • 在其他类中获取变量(Stack Overflow)

    D. CommonUtilities

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

    样品

    1
    2
    3
    4
    5
    public class CommonUtilities {

        public static String className ="CommonUtilities";

    }

    E.通过意图传递数据

    请参阅教程Android - Parcel数据,使用Parcelable类在活动之间传递此传递数据的选项。


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    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()方法中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @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类中,您需要使用以下代码:

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


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

    现在,您希望在startActivity中传递此类的对象。只需使用:

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

    这可以在这里工作,因为MyClass实现了Serializable


    最好的方法是在应用程序中创建一个类(称为Control),该类将包含"Customer"类型的静态变量(在您的情况下)。在Activity A中初始化变量。

    例如:

    1
    Control.Customer = CustomerClass;

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


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

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

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

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


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    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中使用它如下:

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

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

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

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

    一项活动:

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

    其他活动:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    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);
        }
    }

    另一个Stack Overflow问题也讨论了这个问题。请查看使用Serializable通过intent传递数据的解决方案。重点是使用Bundle对象在Intent中存储必要的数据。

    1
    2
    3
    4
    5
    6
    7
     Bundle bundle = new Bundle();

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

     intent.putExtras(bundle);

    提取值:

    1
    2
    3
    4
    5
     Bundle bundle = new Bundle();

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

    Serializable的优点是简单。但是,如果需要传输大量数据,则应考虑使用Parcelable方法,因为Parcelable是专为Android设计的,并且比Serializable更有效。您可以使用以下命令创建Parcelable类:

  • 一个在线工具 - parcelabler
  • 适用于Android Studio的插件 - Android Parcelable代码生成器

  • 从此活动启动另一个活动,并通过Bundle Object传递参数

    1
    2
    3
    Intent intent = new Intent(getBaseContext(), YourActivity.class);
    intent.putExtra("USER_NAME","[email protected]");
    startActivity(intent);

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

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

    对于简单类型的数据类型,这是可以的。
    但是如果你想在活动之间传递复杂的数据。你需要先将它序列化。

    这里我们有员工模型

    1
    2
    3
    4
    5
    6
    7
    8
    class Employee{
        private String empId;
        private int age;
        print Double salary;

        getters...
        setters...
    }

    您可以使用谷歌提供的Gson lib来序列化复杂数据
    像这样

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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);


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    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();
            }
        }
    }

    现在你的发件人活动就是这样的

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

    并在你的接收器活动

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


    克里特岛类像bean类,并实现Serializable接口。然后我们可以通过intent方法传递它,例如:

    1
    intent.putExtra("class", BeanClass);

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

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

    Android Activity对象可以被销毁和重构。因此,您需要使用另一种方法来查看它们 - 或者它们创建的任何对象! - 起来也就是说,您可以作为静态类引用传递,但随后对象句柄(Java称为"引用",就像SmallTalk一样;但它们不是C或汇编意义上的引用)以后可能会因为"功能"而无效Android OE的任何活动都可以被湮灭并在以后重组。

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

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

    以供参考:

    Stopped:
    "The activity is completely obscured by another activity (the activity is now in the"background"). A stopped activity is also still alive (the Activity object is retained in memory, it maintains all state and member information, but is not attached to the window manager). However, it is no longer visible to the user and it can be killed by the system when memory is needed elsewhere."

    onDestroy
    "system is temporarily destroying this instance of the activity to save space."

    因此,消息总线是一个可行的解决方案。它基本上是"平底船"。而不是尝试引用对象;然后,您重新设计您的设计以使用MessagePassing而不是SequentialCode。调试指数更难;但它可以让你忽略这些操作环境的理解。实际上,每个对象方法访问都被反转,因此调用者发布一个Message,并且该对象本身定义了该消息的处理程序。需要更多代码,但可以通过Android OE限制使其更加强大。

    如果您想要的只是顶级Activity(由于"Context"在任何地方都需要,Android应用程序中的典型事物),那么只要调用onResume,您就可以让每个Activity在静态全局空间中列为"top"。然后你的AlertDialog或任何需要上下文的东西都可以从那里抓住它。此外,使用全局有点令人讨厌,但可以简化在任何地方上下传递上下文,当然,当您使用MessageBus时,无论如何IT都是全局的。


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


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

    1
    2
    3
    public class IntentMailBox {
        static Queue<Object> content = new LinkedList<Object>();
    }
  • 呼叫活动

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

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

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

  • 请记住,您仍然需要处理活动生命周期,您可能希望将所有数据直接写入共享首选项,因为它具有复杂的数据结构。


  • 以上答案几乎都是正确的,但对于那些没有找到答案的人
    Android有强大的Intent类,在它的帮助下,你不仅可以在Android之间共享活动,还可以在Android的另一个组件之间共享数据(广播接收器,内容的服务提供我们使用ContetnResolver类没有Intent)。
    在您的活动中,您构建意图

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

    在你的接收活动中,你有

    1
    2
    3
    4
    5
    6
    7
    8
    public class SomeActivity extends AppCompactActivity {

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

    }

    您必须在对象上实现Parceable或Serializable接口,以便在活动之间共享。很难在对象上实现Parcealbe而不是Serializable接口,这就是为什么android特别为此设置了插件。下载并使用它


    将一项活动传递给另一项

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

    获取价值:

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

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

    1
    SupplierDetails poSuppliersDetails = new SupplierDetails();

    poSuppliersDetails里面我们有一些值。现在我将此对象发送到目标活动:

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

    如何在ACtivityTwo中获取此信息:

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

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

    GNLauncher将对象/数据从另一个Activity等发送到Activity,就像调用Activity中的一个函数一样简单,并将所需的数据作为参数。它引入了类型安全性并删除了必须序列化的所有任务,使用字符串键附加到intent并在另一端撤消它们。

    用法

    使用要在要启动的活动上调用的方法定义接口。

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

    在要启动的Activity上实现上面的接口。
    在活动准备好时也通知GNLauncher。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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 +"!
    Your age is:"
    + age);
        }
    }

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

    1
    2
    3
    4
    5
    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。


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

    (1)来源活动

    1
    2
    3
    4
    5
    6
    Intent ii = new Intent(examreport_select.this,
                        BarChartActivity.class);

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

    (2)目的地活动

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

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

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

    Android DataCache


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

    Passing a reference to an object just seems more efficient to me than serializing and desterilizing objects, but I have not done a deep dive to see if that is what is going on behind the scenes.

    创建一个Binder很简单......

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class MyBinder extends Binder {

        private Object myObject;

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

        public Object getObject() {
            return myObject;
        }

    }

    创建parcelable以使用它并不是那么糟糕的以太。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    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];
            }

        };
    }

    这个逻辑非常酷,因为您实际上是将一个引用从活动传递给活动。

    I would advise checking for nulls and if the instanceof Binder is MyBinder!

    并实现这一点你只是......

    发送它

    1
    2
    3
    4
    5
    Object myObject ="some object";
    MyParcelable myParcelable = new MyParcelable();
    myParcelable.setObject(myObject);

    intent.putExtra("MyParcelable", myParcelable);

    拿回来

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

    哎呀有人可能会疯狂,让这个吸盘成为真正的通用。


    正如评论中所提到的,这个答案打破了封装并紧密耦合组件,这很可能不是你想要的。最好的解决方案可能是让您的对象可以Parcelable或Serializable,正如其他响应所解释的那样。话虽如此,解决方案解决了这个问题。所以如果你知道你在做什么:

    使用具有静态字段的类:

    1
    2
    3
    public class Globals {
        public static Customer customer = new Customer();
    }

    在您可以使用的活动内:

    活动来自:

    1
    Globals.customer = myCustomerFromActivity;

    活动目标:

    1
    myCustomerTo = Globals.customer;

    这是传递活动信息的简便方法。