我正在尝试从一个 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
上显示数据。
我怎样才能做到这一点?
一种选择是让您的自定义类实现 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() {}
}
}
用 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");
而已。
classCastException: java.lang.Long
。你能解释一下为什么吗?
(Serializable)
前缀?
使用 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)
使用全局静态变量不是好的软件工程实践。
将对象的字段转换为原始数据类型可能是一项繁重的工作。
使用可序列化是可以的,但它在 Android 平台上的性能效率不高。
Parcelable 是专为 Android 设计的,你应该使用它。这是一个简单的示例:在 Android 活动之间传递自定义对象
您可以使用此 site 为您的班级生成 Parcelable 代码。
Parcelable
为代价的,那么我宁愿让我的 POJO 类与 Android 无关并使用 Serializable
。
调用活动时
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();
}
根据我的经验,有三种主要的解决方案,每种都有其缺点和优点:
实现 Parcelable 实现 Serializable 使用某种轻量级事件总线库(例如,Greenrobot 的 EventBus 或 Square 的 Otto)
Parcelable - 快速且符合 Android 标准,但它包含大量样板代码,并且在将值拉出意图(非强类型)时需要硬编码字符串以供参考。
Serializable - 接近于零样板,但它是最慢的方法,并且在将值拉出意图(非强类型)时还需要硬编码字符串。
Event Bus - 零样板,最快的方法,并且不需要硬编码字符串,但它确实需要额外的依赖项(尽管通常是轻量级的,~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);
你会发现 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);
}
您还可以将对象的数据写入临时字符串和整数,并将它们传递给活动。当然,通过这种方式,您可以传输数据,但不能传输对象本身。
但是,如果您只想显示它们,而不是在其他方法或类似方法中使用该对象,那应该就足够了。我以同样的方式在另一个活动中显示来自一个对象的数据。
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");
Bundle extras = getIntent().getExtras();
String val = extras.getString("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");
请记住,一旦加载,对象就会被删除以避免不必要的引用。
RoomsActivity
中的 BookActivity.getInstance().recommendationResponse
obj
变为 null
。为避免这种情况,应将 obj
存储在某个地方以便再次获取它。事实上,Json 解决方案将对象数据存储在 Intent 中。
有几种方法可以访问其他类或 Activity 中的变量或对象。
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。
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,了解此传递数据的选项。
创建您自己的类 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),该类将包含一个“客户”类型的静态变量(在您的情况下)。初始化活动 A 中的变量。
例如:
Control.Customer = CustomerClass;
然后转到活动 B 并从 Control 类中获取它。使用变量后不要忘记赋值null,否则会浪费内存。
如果您选择使用 Samuh 描述的方式,请记住只能发送原始值。也就是说,可分析的值。因此,如果您的对象包含复杂对象,则这些对象将不会跟随。例如,Bitmap、HashMap 等变量......这些很难通过意图传递。
一般来说,我建议您只发送原始数据类型作为附加值,例如字符串、整数、布尔值等。在您的情况下,它将是:String fname
、String lname
、int age
和 String address
。
我的观点:通过实现 ContentProvider、SDCard 等可以更好地共享更复杂的对象。也可以使用静态变量,但这可能会很快导致容易出错的代码......
但同样,这只是我的主观意见。
我正在使用 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");
您可以尝试使用该类。限制是它不能在一个进程之外使用。
一项活动:
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);
}
}
从此活动开始另一个活动并通过捆绑对象传递参数
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);
这个问题也在另一个 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 代码生成器
创建一个类似于 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();
}
}
}
现在在您的发件人活动中这样做
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 您的 Activity,否则这将起作用。
因此,要真正解决最初的问题,您需要一个静态查找加上每个对象将在/如果重新创建时更新其引用。例如,如果调用了 onCreate,每个 Android Activity 都会重新列出自己。您还可以看到一些人如何使用任务列表按名称搜索 Activity。 (系统暂时销毁该活动实例以节省空间..getRunningTasks,任务列表实际上是每个活动的最新对象实例的专门列表)。
以供参考:
已停止:“该活动完全被另一个活动遮挡(活动现在在“后台”中)。一个停止的活动也仍然活着(活动对象保留在内存中,它维护所有状态和成员信息,但不是附加到窗口管理器)。但是,它不再对用户可见,并且当其他地方需要内存时,它可以被系统杀死。” onDestroy “系统正在临时销毁该活动实例以节省空间。”
因此,消息总线是一个可行的解决方案。它基本上是“平底船”。而不是尝试引用对象;然后您重新设计您的设计以使用 MessagePassing 而不是 SequentialCode。指数级地难以调试;但它让你忽略这些操作环境的理解。实际上,每个对象方法的访问都是反向的,因此调用者发布了一条消息,并且对象本身为该消息定义了一个处理程序。更多代码,但可以使其在 Android OE 限制下变得健壮。
如果您想要的只是顶级活动(Android 应用程序中的典型事情,因为到处都需要“上下文”),那么只要调用 onResume,您就可以让每个活动在静态全局空间中将自己列为“顶级”。然后您的 AlertDialog 或任何需要上下文的东西都可以从那里获取它。此外,使用全局有点讨厌,但可以简化在任何地方上下传递上下文,并且可以肯定的是,当您使用 MessageBus 时,无论如何它都是全局的。
是的,使用静态对象是迄今为止使用自定义不可序列化对象执行此操作的最简单方法。
putExtra()
根本不切实际,那么将这些对象设为 static
是更好的解决方法。例如,现在,我想传递一个包含对象的 ArrayList
。我不妨让我的 ArrayList static
代替。
我知道静态是不好的,但似乎我们不得不在这里使用它。 parceables/seriazables 的问题在于这两个活动具有相同对象的重复实例 = 浪费内存和 CPU。公共类 IntentMailBox { static Queue
通话活动
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,因为你的应用包已经被系统从内存中卸载并在稍后重新加载。请记住,您仍然需要处理活动生命周期,您可能希望将所有数据直接写入共享首选项,这对于复杂的数据结构来说很痛苦。
以上答案几乎都是正确的,但对于那些不理解这些答案的人来说,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 有专门为此而设计的插件。下载并使用它
像这样创建您的自定义类:
公共类测试实现 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 倍。
我一直想知道为什么这不能像调用其他活动的方法那么简单。我最近编写了一个实用程序库,使它几乎就这么简单。您可以在此处查看 (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。
将对象从一个活动传递到另一个活动。
(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");
不定期副业成功案例分享
Parcelable
IS 专门为此目的而设计(并且比Serializable
快得多)。我是一个困惑。Parcelable
可能有助于提高速度,但实施起来很复杂。如果你有 8 个对象需要在 Activity 之间传递,你会让每个对象都变成Parcelable
吗?改用Serializable
会更有意义。当您实现Parcelable
时,您必须向类中添加大量代码,并以非常具体的方式对字段进行排序;Serializable
你没有。归根结底,我认为这取决于你通过了多少物体以及你想要做什么。Serializable
是标准 Java 接口。您只需通过实现接口标记一个类 Serializable,Java 会在某些情况下自动序列化它。Parcelable
是您自己实现序列化的 Android 特定接口。它的创建比 Serializable 更有效,并解决了默认 Java 序列化方案的一些问题