繁体   English   中英

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

[英]How to pass an object from one activity to another on Android

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

我怎样才能做到这一点?

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

伪代码

//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() {}
    }
}

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

就是这样。

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

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

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

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

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

在您的接收 Activity 中,将 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)
  • 使用全局静态变量不是好的软件工程实践。
  • 将对象的字段转换为原始数据类型可能是一项繁忙的工作
  • 使用可序列化是可以的,但它在 Android 平台上的性能效率不高
  • Parcelable 是专为 Android 设计的,您应该使用它。 下面是一个简单的例子: 在 Android Activity 之间传递自定义对象

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

在调用活动时

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

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

  1. 实现 Parcelable

  2. 实现可序列化

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

Parcelable - 快速且符合 Android 标准,但它有很多样板代码,并且在从意图中提取值(非强类型)时需要硬编码字符串以供参考。

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

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

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

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

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

方法一

第一个活动的代码:

    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 binder 会为 java 对象创建全局 JNI 引用,并在没有此 java 对象的引用时释放此全局 JNI 引用。 binder 将在 Binder 对象中保存这个全局 JNI 引用。

*注意:除非两个活动在同一进程中运行,否则此方法仅适用,否则在 (ObjectWrapperForBinder)getIntent().getExtras().getBinder("object_value") 处抛出 ClassCastException *

类 ObjectWrapperForBinder 定义

public class ObjectWrapperForBinder extends Binder {

    private final Object mData;

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

    public Object getData() {
        return mData;
    }
}

方法二

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

但是方法二有一个小但严重的问题,如果接收方无法恢复java对象(例如,在恢复java对象之前发生了一些异常,或者接收方Activity根本不存在),那么java对象就会变成一个orphan或者内存泄漏,方法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();
    }

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

方法四

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

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

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

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

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

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

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

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

A. 数据库

B. 共享偏好。

C. 对象序列化。

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

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

如何获取

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

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

C.对象序列化

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

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

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

public class VariableStorage implements Serializable  {

    private String inString;

    public String getInString() {
        return inString;
    }

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

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

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

然后使用对象序列化来序列化这个对象,并在你的其他类中反序列化这个对象。

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

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

如果您需要此教程,请参阅:

D.公用事业

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

样本

public class CommonUtilities {

    public static String className = "CommonUtilities";

}

E.通过意图传递数据

请参阅教程Android – 使用 Parcelable 类在活动之间传递包裹数据以了解此传递数据的选项。

创建您自己的类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());
public class MyClass implements Serializable{
    Here is your instance variable
}

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

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

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

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

例如:

Control.Customer = CustomerClass;

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

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

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

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

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

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

在活动A中使用它像这样:

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

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

一项活动:

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

这个问题也在另一个 Stack Overflow 问题中讨论过。 请查看使用 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类:

  1. 一个在线工具——parcelabler
  2. Android Studio 插件 - Android Parcelable 代码生成器

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

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 库来序列化这样的复杂数据

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

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

intent.putExtra("class", BeanClass);

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

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

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

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

现在在您的发件人 Activity 中这样做

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

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

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

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

以供参考:

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

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

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

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

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

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

调用活动

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

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

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

  2. 请记住,您仍然需要处理活动生命周期,您可能希望将所有数据直接写入共享首选项,这对于复杂的数据结构来说很痛苦。

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

以上答案几乎全部正确,但对于那些不理解这些答案的人来说,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 专门为此提供插件的原因。下载并使用它

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

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

用法

定义一个接口,其中包含要在要启动的 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

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

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

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

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

安卓数据缓存

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

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

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

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

获取值:

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

不可能序列化任何类型的对象。 例如,您不能序列化携带代码而不是数据的委托方法或接口。 因此,我编写了一个“Box”类,您可以使用它来传递任何类型的数据而无需 Serialization

1- 用于将数据用于意图用途:

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

2- 从 Intent 中检索数据:

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

3-为了在使用后删除数据,将此方法添加到您的活动中:

@Override
protected void onDestroy() {
    Box.Remove(getIntent());
    super.onDestroy();
}

4- 并将此代码添加到您的项目中:

package ir.namirasoft.Utility;

import android.content.Intent;

import java.util.HashMap;
import java.util.Vector;

public class Box {
    // Number
    private static int Number = 1;

    public static int NextNumber() {
        return Number++;
    }

    //
    private static String _Intent_Identifier = "_Intent_Identifier";
    private static HashMap<Integer, Vector<Integer>> DeleteList = new HashMap<Integer, Vector<Integer>>();
    private static HashMap<Integer, HashMap<String, Object>> ObjectList = new HashMap<Integer, HashMap<String, Object>>();

    public static int GetIntent_Identifier(Intent I) {
        int Intent_Identifier = I.getIntExtra(_Intent_Identifier, 0);
        if (Intent_Identifier == 0)
            I.putExtra(_Intent_Identifier, Intent_Identifier = NextNumber());
        return Intent_Identifier;
    }

    public static void Add(Intent I, String Name, Object O) {
        int Intent_Identifier = GetIntent_Identifier(I);
        synchronized (ObjectList) {
            if (!ObjectList.containsKey(Intent_Identifier))
                ObjectList.put(Intent_Identifier, new HashMap<String, Object>());
            ObjectList.get(Intent_Identifier).put(Name, O);
        }
    }

    public static <T> T Get(Intent I, String Name) {
        int Intent_Identifier = GetIntent_Identifier(I);
        synchronized (DeleteList) {
            DeleteList.remove(Intent_Identifier);
        }
        return (T) ObjectList.get(Intent_Identifier).get(Name);
    }

    public static void Remove(final Intent I) {
        final int Intent_Identifier = GetIntent_Identifier(I);
        final int ThreadID = NextNumber();
        synchronized (DeleteList) {
            if (!DeleteList.containsKey(Intent_Identifier))
                DeleteList.put(Intent_Identifier, new Vector<Integer>());
            DeleteList.get(Intent_Identifier).add(ThreadID);
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(60 * 1000);
                } catch (InterruptedException e) {
                }
                synchronized (DeleteList) {
                    if (DeleteList.containsKey(Intent_Identifier))
                        if (DeleteList.get(Intent_Identifier).contains(ThreadID))
                            synchronized (ObjectList) {
                                ObjectList.remove(Intent_Identifier);
                            }
                }
            }
        }).start();
    }
}

** Box 类是线程安全的。

我写了一个叫做intentparser的库

使用起来真的很容易将它添加到您的项目gradle中

allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

将此添加到您的应用程序gradle


dependencies {
            implementation 'com.github.lau1944:intentparser:v$currentVersion'
    }

使用扩展方法 putObject 传递对象

val testModel = TestModel(
            text = "hello world",
            isSuccess = false,
            testNum = 1,
            textModelSec = TextModelSec("second model")
)
startActivity(
     Intent(this, ActivityTest::class.java).apply {
          this.putObject(testModel)
     }
) 

从上一个活动中获取对象


val testModel = intent.getObject(TestModel::class.java)

在 Android 中,有多种方法可以将对象从一个 Activity 传递到另一个 Activity。 但是它们都没有直接选项来简单地通过 Intent 或 Bundle 传递对象。 您需要做的就是解码对象,作为字符串传递,在 NextActivity 中编码 示例如下:

Intent i = new Intent(this, nextActivity.class);
i.putExtra("fname", customer.getFirstName());
i.putExtra("lname", customer.getLastName());
i.putExtra("address", customer.getAddress());

startActivity(i);

第二种方法非常简单,使用可以从所有活动轻松访问的静态对象

第三,最后但并非最不重要的一点是,您可以将对象存储到某个常量 Java 文件中,然后从任何活动中读取该对象值。

希望它能回答您的问题并解决问题。 如果我的回答对您有用,请不要犹豫点 :)

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

对我来说,传递对对象的引用似乎比对对象进行序列化和灭菌更有效,但是我没有深入研究该问题是否在幕后发生。

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

public class MyBinder extends Binder {

    private Object myObject;

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

    public Object getObject() {
        return myObject;
    }

}

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

public class MyParcelable implements Parcelable {

    private Object myObject;

    public MyParcelable() {
    }

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

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

    public Object getObject() {
        return myObject;
    }

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

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

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

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

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

    };
}

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

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

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

发送出去

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

intent.putExtra("MyParcelable", myParcelable);

拿回来

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

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

像这样创建自定义类:

公共类测试实现 Parcelable { String message;

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,正如其他回复所解释的那样。 话虽如此,解决方案解决了问题。 因此,如果您知道自己在做什么:

使用带有静态字段的类:

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

在您可以使用的活动中:

活动自:

Globals.customer = myCustomerFromActivity;

活动目标:

myCustomerTo = Globals.customer;

这是一种为活动传递信息的简单方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM