如何在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上显示数据。

我怎样才能做到这一点?

829800 次浏览

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

实际代码

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

public class YourClass implements Serializable {

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

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

myObject的类型是“YourClass”。然后要从另一个活动中检索,请使用getSerializableExtra使用相同的Key名称获取对象。需要将类型转换为YourClass:

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

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

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

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

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

我的观点:通过实现内容提供者SDCard等来更好地共享更复杂的对象,也可以使用静态变量,但这可能会迅速导致容易出错的代码…

再一次,这只是我的主观看法。

您还可以将对象的数据写入临时Strings和int,并将它们传递给活动。当然,这样一来,您可以传输数据,而不是对象本身。

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

String fName_temp   = yourObject.getFname();String lName_temp   = yourObject.getLname();String age_temp     = yourObject.getAge();String address_temp = yourObject.getAddress();
Intent i = new Intent(this, ToClass.class);i.putExtra("fname", fName_temp);i.putExtra("lname", lName_temp);i.putExtra("age", age_temp);i.putExtra("address", address_temp);
startActivity(i);

您也可以直接传递它们而不是临时ivars,但在我看来,这种方式更清晰。此外,您可以将临时ivars设置为null,以便它们更快地被垃圾收集器清理。

祝你好运!

附带说明:重写toString()而不是编写自己的print方法。

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

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

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

例如:

Control.Customer = CustomerClass;

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

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

在调用活动时

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

在toClass.java接受活动

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

请确保客户类实现可包裹

public class Customer implements Parcelable {
private String firstName, lastName, address;int age;
/* all your getter and setter methods */
public Customer(Parcel in ) {readFromParcel( in );}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {public LeadData createFromParcel(Parcel in ) {return new Customer( in );}
public Customer[] newArray(int size) {return new Customer[size];}};

@Overridepublic 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。话虽如此,该解决方案解决了问题。所以如果你知道自己在做什么:

使用带有静态字段的类:

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

在您可以使用的活动中:

活动来自:

Globals.customer = myCustomerFromActivity;

活动目标:

myCustomerTo = Globals.customer;

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

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

一项活动:

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

@Overridepublic 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;}

@Overridepublic int describeContents() {return 0;}

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

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

import java.io.Serializable;
@SuppressWarnings("serial") //With this annotation we are going to hide compiler warningspublic 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");

就这样了。

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

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

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

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

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

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

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

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

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

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

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

Calling activity

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中可以为空,因为你的应用程序包已被系统从内存中卸载并稍后重新加载。

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

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

A.数据库

B.共同的偏好。

C.对象序列化。

一个可以保存公共数据的类可以被命名为通用工具。这取决于你。

通过意图和可包装的接口传递数据。

这取决于您的项目需求。

A.数据库

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

教程

B.共享偏好

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

如何存储

 // Create object of SharedPreferences.SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
//Now get EditorSharedPreferences.Editor editor = sharedPref.edit();
//Put your valueeditor.putString("userName", "stackoverlow");
//Commits your editseditor.commit();

使用putString()、putBoolean()、put Int()、putFloat()和putLong(),您可以保存所需的dtatype。

如何获取

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

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

C.对象序列化

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

使用Javabean并将其存储为他的字段之一,并为此使用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;}}

使用以下命令在mail方法中设置变量

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

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

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

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

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

D.常用工具

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

样本

public class CommonUtilities {
public static String className = "CommonUtilities";
}

E.通过意图传递数据

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

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

在actiityA中,像这样使用它:

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

使用gson将您的对象转换为JSON并将其传递给意图。在新的活动中将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);

对于静态编程语言来说,这是完全一样的

把数据传过来

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)

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

  1. 实现Parcelable

  2. 实现可序列化

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

可包裹的-快速和Android标准,但它有很多样板代码,并且在提取意图(非强类型)值时需要硬编码字符串作为参考。

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

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

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

创建自己的类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()方法中

@Overrideprotected 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());

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

intent.putExtra("class", BeanClass);

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

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

Android活动对象可以被销毁和重建。因此,你需要使用另一种方法来查找它们-或它们创建的任何对象!!!-up。也就是说,你可以作为静态类引用传递,但随后对象句柄(Java调用这些“引用”,SmallTalk也是如此;但它们不是C或汇编意义上的引用)稍后可能会无效,因为Android OE的一个“功能”是任何活动都可以稍后被消灭和重建。

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

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

供参考:

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

销毁"系统暂时是活动的销毁此实例以节省空间。"

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

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

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

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

用法

定义一个接口,其中包含要调用活动以启动的方法。

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

在要启动的活动上实现上述接口。当活动准备就绪时也通知GNLauncher。

public class Activity_1 extends Activity implements IPayload {
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//Notify GNLauncher when the Activity is ready.GNLauncher.get().ping(this);}
@Overridepublic void sayHello(String name, int age) {Log.d("gnlib_test", "Hello " + name + "! \nYour age is: " + age);}}

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

public class Activity_2 extends Activity {public void onClick(View v) {((IPayload)GNLauncher.get().getProxy(this, IPayload.class, Activity_1.class)).sayHello(name, age);}}

将启动第一个活动并使用所需的参数调用该方法。

先决条件

有关如何添加依赖项的信息,请参阅https://github.com/noxiouswinter/gnlib_android/wiki#prerequisites

这个问题也在另一个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代码生成器

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

public class Qabir {
private int age;private String name;
Qabir(){}
Qabir(int age,String name){this.age=age; this.name=name;}
// method for sending objectpublic String toJSON(){return "{age:" + age + ",name:\"" +name +"\"}";}
// method for get back original objectpublic 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"));

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

(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设置对象来传输,但是每当我向对象(模型)添加其他变量时,我都必须注册它。太不方便了。

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

Android DataCache

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

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

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

  • 不可包裹
  • 不可序列化
  • 无静态字段
  • 无事件总线

方法1

第一个活动的代码:

    final Object objSent = new Object();final Bundle bundle = new Bundle();bundle.putBinder("object_value", new ObjectWrapperForBinder(objSent));startActivity(new Intent(this, SecondActivity.class).putExtras(bundle));Log.d(TAG, "original object=" + objSent);

第二个活动的代码:

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

你会发现objSentobjReceived有相同的hashCode,所以它们是相同的。

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

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

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

类对象WrapperForBinder定义

public class ObjectWrapperForBinder extends Binder {
private final Object mData;
public ObjectWrapperForBinder(Object data) {mData = data;}
public Object getData() {return mData;}}

方法2

  • 对于发送者,
    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),

但是方法2有一个小而严重的问题,如果接收者无法恢复java对象(例如,在恢复java对象之前发生了一些异常,或者接收者的活动根本不存在),那么java对象将成为孤儿或内存泄漏,方法1没有这个问题,因为android binder会处理这个异常

方法3

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

IDataContract.aidl

package com.example.objectwrapper;interface IDataContract {int func1(String arg1);int func2(String arg1);}

第一个活动的代码

    final IDataContract objSent = new IDataContract.Stub() {
@Overridepublic int func2(String arg1) throws RemoteException {// TODO Auto-generated method stubLog.d(TAG, "func2:: arg1=" + arg1);return 102;}
@Overridepublic int func1(String arg1) throws RemoteException {// TODO Auto-generated method stubLog.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 blocke.printStackTrace();}

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

方法4

方法3似乎不够简单,因为我们必须实现一个aidl接口。如果你只是想做简单的任务,方法返回值是不必要的,我们可以使用android.os.Messenger

第一个活动(发送方)的代码:

public class MainActivity extends Activity {private static final String TAG = "MainActivity";
public static final int MSG_OP1 = 1;public static final int MSG_OP2 = 2;
public static final String EXTRA_MESSENGER = "messenger";
private final Handler mHandler = new Handler() {
@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubLog.e(TAG, "handleMessage:: msg=" + msg);switch (msg.what) {case MSG_OP1:
break;case MSG_OP2:break;
default:
break;}super.handleMessage(msg);}
};@Overrideprotected 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 {
@Overrideprotected 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 blocke.printStackTrace();}
}}

所有Messenger.send将在处理程序中异步和顺序执行。

其实android.os.Messenger也是一个aidl界面,如果你有android的源代码,可以找到一个名为IMessenger.aidl的文件

package android.os;
import android.os.Message;
/** @hide */oneway interface IMessenger {void send(in Message msg);}

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

传递对对象的引用对我来说似乎比序列化和取消对象的安全性更有效,但我还没有深入研究这是否是幕后发生的事情。

创建绑定器很简单…

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

这个逻辑真的很酷,因为你实际上是在将引用从一个活动传递到另一个活动。

我建议检查空值以及Binder的instance是否为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();

见鬼,有人可能会发疯,让这个傻瓜成为真正的仿制药。

上面的答案几乎都是正确的,但对于那些不理解这些答案的人来说Android有一个强大的类意图与它的帮助下,你不仅活动之间共享数据,但Android的其他组件(广播接收器,内容提供的服务,我们使用ContetnResolver类没有意图)。在你的活动中,你建立了意图

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而不是可序列化接口,这就是为什么android有插件,尤其是在这方面。下载并使用它。

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

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

获取值:

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

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

Intent intent = new Intent(getBaseContext(), YourActivity.class);intent.putExtra("USER_NAME", "xyz@gmail.com");startActivity(intent);

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

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

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

这里我们有员工模型

class Employee{private String empId;private int age;print Double salary;    
getters...setters...}

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

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

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-使用后删除数据,将此方法添加到您的活动中:

@Overrideprotected 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 {// Numberprivate 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() {@Overridepublic 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类是线程安全的。

我写了一个名为意图解析器的库

很容易使用将其添加到您的项目gradle

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

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

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

使用扩展方法传递对象put Object

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中,有很多方法可以将对象从一个活动传递到另一个活动。但它们都没有直接选择通过意图或捆绑包传递对象。你需要做的就是解码对象,通行证作为字符串,编码在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);

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

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

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

public class Test implements Parcelable {String message;
protected Test(Parcel in) {message = in.readString();}
public static final Creator<Test> CREATOR = new Creator<Test>() {@Overridepublic Test createFromParcel(Parcel in) {return new Test(in);}
@Overridepublic Test[] newArray(int size) {return new Test[size];}};
public String getMessage() {return message;}
@Overridepublic int describeContents() {return 0;}
@Overridepublic 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");