How to pass an object from one activity to another on Android - java
I am trying to work on sending an object of my customer class from one Activity and displaying it in another Activity.
The code for the customer class:
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;
}
}
I want to send its object from one Activity to another and then display the data on the other Activity.
How can I achieve that?
One option could be letting your custom class implement the Serializable interface and then you can pass object instances in the intent extra using the putExtra(Serializable..) variant of the Intent#putExtra() method.
Actual Code:
In Your Custom Model/Object Class:
public class YourClass implements Serializable {
At other class where using the Custom Model/Class:
//To pass:
intent.putExtra("KEY_NAME", myObject);
myObject is of type "YourClass".
Then to retrieve from another activity, use getSerializableExtra
get the object using same Key name. And typecast to YourClass is needed:
// To retrieve object in second Activity
myObject = (YourClass) getIntent().getSerializableExtra("KEY_NAME");
Note: Make sure each nested class of your main custom class has implemented Serializable interface to avoid any serialization exceptions. For example:
class MainClass implements Serializable {
public MainClass() {}
public static class ChildClass implements Serializable {
public ChildClass() {}
}
}
Implement your class with Serializable. Let's suppose that this is your entity class:
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;
}
We are sending the object called dene from X activity to Y activity. Somewhere in X activity;
Deneme dene = new Deneme(4,"Mustafa");
Intent i = new Intent(this, Y.class);
i.putExtra("sampleObject", dene);
startActivity(i);
In Y activity we are getting the object.
Intent i = getIntent();
Deneme dene = (Deneme)i.getSerializableExtra("sampleObject");
That's it.
Use gson to convert your object to JSON and pass it through intent. In the new Activity convert the JSON to an object.
In your build.gradle, add this to your dependencies
implementation 'com.google.code.gson:gson:2.8.4'
In your Activity, convert the object to json-string:
Gson gson = new Gson();
String myJson = gson.toJson(vp);
intent.putExtra("myjson", myjson);
In your receiving Activity, convert the json-string back to the original object:
Gson gson = new Gson();
YourObject ob = gson.fromJson(getIntent().getStringExtra("myjson"), YourObject.class);
For Kotlin it's quite the same
Pass the data
val gson = Gson()
val intent = Intent(this, YourActivity::class.java)
intent.putExtra("identifier", gson.toJson(your_object))
startActivity(intent)
Receive the data
val gson = Gson()
val yourObject = gson.fromJson<YourObject>(intent.getStringExtra("identifier"), YourObject::class.java)
Using global static variables is not good software engineering practice.
Converting an object's fields into primitive data types can be a hectic job.
Using serializable is OK, but it's not performance-efficient on the Android platform.
Parcelable is specifically designed for Android and you should use it. Here is a simple example: Passing custom objects between Android activities
You can generate Parcelable code for you class using this site.
While calling an activity
Intent intent = new Intent(fromClass.this,toClass.class).putExtra("myCustomerObj",customerObj);
In toClass.java receive the activity by
Customer customerObjInToClass = getIntent().getExtras().getParcelable("myCustomerObj");
Please make sure that customer class implements 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();
}
In my experience there are three main solutions, each with its disadvantages and advantages:
Implementing Parcelable
Implementing Serializable
Using a light-weight event bus library of some sort (for example, Greenrobot's EventBus or Square's Otto)
Parcelable - fast and Android standard, but it has lots of boilerplate code and requires hard-coded strings for reference when pulling values out the intent (non-strongly typed).
Serializable - close to zero boilerplate, but it is the slowest approach and also requires hard-coded strings when pulling values out the intent (non-strongly typed).
Event Bus - zero boilerplate, fastest approach, and does not require hard-coded strings, but it does require an additional dependency (although usually lightweight, ~40 KB)
I posted a very detailed comparison of these three approaches, including efficiency benchmarks.
I found a simple & elegant method:
NO Parcelable
NO Serializable
NO Static Field
No Event Bus
Method 1
Code for the first activity:
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);
Code for the second activity:
final Object objReceived = ((ObjectWrapperForBinder)getIntent().getExtras().getBinder("object_value")).getData();
Log.d(TAG, "received object=" + objReceived);
you will find objSent & objReceived have the same hashCode, so they are identical.
But why can we pass a java object in this way?
Actually, android binder will create global JNI reference for java object and release this global JNI reference when there are no reference for this java object. binder will save this global JNI reference in the Binder object.
*CAUTION: this method ONLY work unless the two activities run in the same process, otherwise throw ClassCastException at (ObjectWrapperForBinder)getIntent().getExtras().getBinder("object_value") *
class ObjectWrapperForBinder defination
public class ObjectWrapperForBinder extends Binder {
private final Object mData;
public ObjectWrapperForBinder(Object data) {
mData = data;
}
public Object getData() {
return mData;
}
}
Method 2
for the sender,
use custom native method to add your java object to JNI global reference table(via JNIEnv::NewGlobalRef)
put the return integer (actually, JNIEnv::NewGlobalRef return jobject, which is a pointer, we can cast it to int safely) to your Intent(via Intent::putExtra)
for the receiver
get integer from Intent(via Intent::getInt)
use custom native method to restore your java object from JNI global reference table (via JNIEnv::NewLocalRef)
remove item from JNI global reference table(via
JNIEnv::DeleteGlobalRef),
But Method 2 has a little but serious issue, if the receiver fail to restore the java object (for example, some exception happen before restore the java object, or the receiver Activity does not exist at all), then the java object will become an orphan or memory leak,
Method 1 don't have this issue, because android binder will handle this exception
Method 3
To invoke the java object remotely, we will create a data contract/interface to describe the java object, we will use the aidl file
IDataContract.aidl
package com.example.objectwrapper;
interface IDataContract {
int func1(String arg1);
int func2(String arg1);
}
Code for the first activity
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);
Code for the second activity:
change the android:process attribute in AndroidManifest.xml to a non-empty process name to make sure the second activity run in another 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();
}
In this way, we can pass an interface between two activities even though they run in different process, and call the interface method remotely
Method 4
method 3 seem not simple enough because we must implement an aidl interface.
If you just want to do simple task and the method return value is unnecessary, we can use android.os.Messenger
Code for the first activity( sender):
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)));
}
}
Code for the second activity ( receiver ):
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();
}
}
}
All the Messenger.send will execute in a Handler asynchronously and sequentially.
Actually, android.os.Messenger is also an aidl interface, if you have the android source code, you can find a file named IMessenger.aidl
package android.os;
import android.os.Message;
/** #hide */
oneway interface IMessenger {
void send(in Message msg);
}
You could also write the object's data into temporary Strings and ints, and pass them to the activity. Of course that way, you get the data transported, but not the object itself.
But if you just want to display them, and not use the object in another method or something like that, it should be enough. I did it the same way to just display data from one object in another activity.
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);
You could also pass them in directly instead of the temp ivars, but this way it's clearer, in my opinion. Additionally, you can set the temp ivars to null so that they get cleaned by the GarbageCollector sooner.
Good luck!
On a side note: override toString() instead of writing your own print method.
As mentioned in the comments below, this is how you get your data back in another activity:
String fName = getIntent().getExtras().getInt("fname");
I made a singleton helper class that holds temporary objects.
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;
}
}
Instead of putting your objects within Intent, use IntentHelper:
IntentHelper.addObjectForKey(obj, "key");
Inside your new Activity, you can get the object:
Object obj = (Object) IntentHelper.getObjectForKey("key");
Bear in mind that once loaded, the object is removed to avoid unnecessary references.
There are a couple of ways by which you can access variables or objects in other classes or Activity.
A. Database
B. Shared preferences.
C. Object serialization.
D. A class which can hold common data can be named as Common Utilities. It depends on you.
E. Passing data through Intents and Parcelable Interface.
It depends upon your project needs.
A. Database
SQLite is an open source database which is embedded into Android. SQLite supports standard relational database features like SQL syntax, transactions and prepared statements.
Tutorials
B. Shared preferences
Suppose you want to store username. So there will now be two things, a key username, value value.
How to store
// 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();
Using putString(), putBoolean(), putInt(), putFloat(), and putLong() you can save your desired dtatype.
How to fetch
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
String userName = sharedPref.getString("userName", "Not Available");
http://developer.android.com/reference/android/content/SharedPreferences.html
C. Object serialization
Object serlization is used if we want to save an object state to send it over a network or you can use it for your purpose also.
Use Java beans and store in it as one of his fields and use getters and setter for that.
JavaBeans are Java classes that have properties. Think of
properties as private instance variables. Since they're private, the only way
they can be accessed from outside of their class is through methods in the class. The methods that change a property's value are called setter methods, and the methods that retrieve a property's value are called getter methods.
public class VariableStorage implements Serializable {
private String inString;
public String getInString() {
return inString;
}
public void setInString(String inString) {
this.inString = inString;
}
}
Set the variable in your mail method by using
VariableStorage variableStorage = new VariableStorage();
variableStorage.setInString(inString);
Then use object serialzation to serialize this object and in your other class deserialize this object.
In serialization an object can be represented as a sequence of bytes that includes the object's data as well as information about the object's type and the types of data stored in the object.
After a serialized object has been written into a file, it can be read from the file and deserialized. That is, the type information and bytes that represent the object and its data can be used to recreate the object in memory.
If you want tutorial for this refer to:
Serialization in Java (blog post)
Get variable in other classes (Stack Overflow)
D. CommonUtilities
You can make a class by yourself which can contain common data which you frequently need in your project.
Sample
public class CommonUtilities {
public static String className = "CommonUtilities";
}
E. Passing data through intents
Please refer the tutorial Android – Parcel data to pass between Activities using Parcelable classes for this option of passing data.
Create your own class Customer as follows:
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;
}
}
In your onCreate() method
#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);
}
In xyz activity class you need to use the following code:
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
}
Now you want to pass the object of this class in startActivity. Simply use this:
Bundle b = new Bundle();
b.putSerializable("name", myClassObject);
intent.putExtras(b);
This works here because MyClass implements Serializable.
The best way is to have a class (call it Control) in your application that will hold a static variable of type 'Customer' (in your case). Initialize the variable in your Activity A.
For example:
Control.Customer = CustomerClass;
Then go to Activity B and fetch it from Control class. Don't forget to assign a null after using the variable, otherwise memory will be wasted.
If you choose use the way Samuh describes, remember that only primitive values can be sent. That is, values that are parcable. So, if your object contains complex objects these will not follow. For example, variables like Bitmap, HashMap etc... These are tricky to pass by the intent.
In general I would advice you to send only primitive datatypes as extras, like String, int, boolean etc. In your case it would be: String fname, String lname, int age, and String address.
My opinion: More complex objects are better shared by implementing a ContentProvider, SDCard, etc. It's also possible to use a static variable, but this may fastly lead to error-prone code...
But again, it's just my subjective opinion.
I am using parcelable to send data from one activity to another acivity. Here is my code that works fine in my project.
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});
}
}
In activityA use it like this:
Bundle bundle = new Bundle();
bundle.putParcelableArrayList("channel",(ArrayList<Channel>) channels);
Intent intent = new Intent(ActivityA.this,ActivityB.class);
intent.putExtras(bundle);
startActivity(intent);
In ActivityB use it like this to get data:
Bundle getBundle = this.getIntent().getExtras();
List<Channel> channelsList = getBundle.getParcelableArrayList("channel");
You can try to use that class. The limitation is that it can't be used outside of one process.
One activity:
final Object obj1 = new Object();
final Intent in = new Intent();
in.putExtra(EXTRA_TEST, new Sharable(obj1));
Other activity:
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);
}
}
This question is also discussed in another Stack Overflow question. Please have a look at a solution to Passing data through intent using Serializable. The main point is about using Bundle object which stores the necessary data inside Intent.
Bundle bundle = new Bundle();
bundle.putSerializable(key1, value1);
bundle.putSerializable(key2, value2);
bundle.putSerializable(key3, value3);
intent.putExtras(bundle);
To extract values:
Bundle bundle = new Bundle();
for (String key : bundle.keySet()) {
value = bundle.getSerializable(key));
}
Advantage of Serializable is its simplicity. However, you should consider using Parcelable method if you need many data to be transferred, because Parcelable is specifically designed for Android and it is more efficient than Serializable. You can create Parcelable class using:
an online tool - parcelabler
a plugin for Android Studio - Android Parcelable code generator
Start another activity from this activity and pass parameters via Bundle Object
Intent intent = new Intent(getBaseContext(), YourActivity.class);
intent.putExtra("USER_NAME", "xyz#gmail.com");
startActivity(intent);
Retrieve data on another activity (YourActivity)
String s = getIntent().getStringExtra("USER_NAME");
This is ok for a simple kind of data type.
But if u want to pass complex data in between activities. U need to serialize it first.
Here we have Employee Model
class Employee{
private String empId;
private int age;
print Double salary;
getters...
setters...
}
You can use Gson lib provided by google to serialize the complex data
like this
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);
Crete a class like bean class and implement the Serializable interface. Then we can pass it through the intent method, for example:
intent.putExtra("class", BeanClass);
Then get it from the other activity, for example:
BeanClass cb = intent.getSerializableExtra("class");
Create two methods in your custom Class like this
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();
}
}
}
Now in your sender Activity do like this
Qabir q= new Qabir(22,"KQ");
Intent in=new Intent(this,SubActivity.class);
in.putExtra("obj", q.toJSON());
startActivity( in);
And in your receiver Activity
Qabir q =new Qabir();
q.initilizeWithJSONString(getIntent().getStringExtra("obj"));
Android Activity objects can be destroyed and reconstituted. So, you will need to use another approach to look them - or any object they create!!! - up. That is, you could pass as static class reference but then the object handle (Java calls these "references", as does SmallTalk; but they are not references in the sense of C or assembly) will be possibly invalid later because a "feature" of Android OE is any Activity can be annihilated and reconstituted later.
The original question asked "How to pass object from one activity to another in Android" and nobody has answered that. For sure, you can serialized (Serializable, Parcelable, to/from JSON) and pass a copy of the object's data and a new object having the same data could be created; but it will NOT have the same references/handles. Also, many others mentioned you can store the reference in a static store. And that will work unless Android decides to onDestroy your Activity.
So, to really solve the original question you would need a static lookup plus each object will update its reference when/if it is recreated. E.g. each Android Activity would relist itself if its onCreate is called. You can also see how some people use the task list to search out an Activity by name. (system is temporarily destroying this instance of the activity to save space..getRunningTasks, the task list is effectively a specialized listing of the most recent object instance of each Activity).
For reference:
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."
So, the Message Bus is a workable solution. It basically "punts". Rather than try to have references to objects; then you re-architect your design to use MessagePassing instead of SequentialCode. Exponentially harder to debug; but it lets you ignore these sort of OperatingEnvironment understandings. Effectively, each object method access is inverted so the caller posts a Message and the object itself defines a handler for that message. Lots more code but can make it robust with the Android OE restrictions.
If all you want is the top Activity (typical thing in Android apps due to "Context" being needed everywhere), then you can just have each Activity lists itself as "top" in the static global space whenever its onResume is called. Then your AlertDialog or whatever which needs a context can just grab it from there. Also, its a bit yucky to use a global but can simplifying passing a Context up and down everywhere and, for sure, when you use a MessageBus then IT IS global anyways.
Yeah, using a static object is by far the easiest way of doing this with custom non-serialisable objects.
I know that static is bad, but it seems that we're forced to use it here. The problem with parceables/seriazables is that the two activities have duplicate instances of the same object = waste of memory and 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);
Called activity (note that onCreate() and onResume() may be called multiple times when the system destroys and recreates activities)
if (IntentMailBox.content.size()>0)
level = (Level) IntentMailBox.content.poll();
else
// Here you reload what you have saved in onPause()
Another way is to declare a static field of the class that you want to pass in that very class. It will serve only for this purpose. Don't forget that it can be null in onCreate, because your app package has been unloaded from memory by system and reloaded later.
Bearing in mind that you still need to handle activity lifecycle, you may want to write all the data straight to shared preferences, painful with complex data structures as it is.
Create your custom class like this:
public class Test implements 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);
}
Send data using Intent like this:
Before starting your activity must set some data
Intent intent = new Intent(context, PostDetailsActivity.class);
intent.putExtra("data", (Parcelable) test);
((context)).startActivity(intent);
Get data from intent like this:
Test test = (Test) getIntent().getParcelableExtra("data");
The above answers are almost all correct but for those who don't understand those answers
Android has a powerful class Intent with help of it you share data between not only activity but other components of Android (broadcast receiver, services for content provided we use ContetnResolver class no Intent).
In your activity you build intent
Intent intent = new Intent(context,SomeActivity.class);
intent.putExtra("key",value);
startActivity(intent);
In your receiving activity, you have
public class SomeActivity extends AppCompactActivity {
public void onCreate(...){
...
SomeObject someObject = getIntent().getExtras().getParceable("key");
}
}
You have to implement Parceable or Serializable interface on your object in order to share between activities. It is hard to implement Parcealbe rather than Serializable interface on the object that's why android has plugins, especially for this. Download it and use it.
I had always wondered why this can't be as simple as calling into a method of the other activity. I recently wrote a utility library that makes it almost as simple as that. You can check it out here(https://github.com/noxiouswinter/gnlib_android/wiki/gnlauncher).
GNLauncher makes sending objects/data to an Activity from another Activity etc as easy as calling a function in tha Activity with the required data as parameters. It introduces type safety and removes all the hastles of having to serialize, attaching to the intent using string keys and undoing the same at the other end.
Usage
Define an interface with the methods you want to call on the Activity to launch.
public interface IPayload {
public void sayHello(String name, int age);
}
Implement the above interface on the Activity to launch into.
Also notify GNLauncher when the activity is ready.
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);
}
}
In the other Activity, get a proxy to the above Activity and call any method with the desired parameters.
public class Activity_2 extends Activity {
public void onClick(View v) {
((IPayload)GNLauncher.get().getProxy(this, IPayload.class, Activity_1.class)).sayHello(name, age);
}
}
The first activity will be launched and the method called into with the required parameters.
Prerequisites
Please refer to https://github.com/noxiouswinter/gnlib_android/wiki#prerequisites for information on how to add the dependencies.
Pass object from one activity to another activity.
(1) source activity
Intent ii = new Intent(examreport_select.this,
BarChartActivity.class);
ii.putExtra("IntentExamResultDetail",
(Serializable) your List<ArraList<String>> object here);
startActivity(ii);
(2) destination acitivity
List<ArrayList<String>> aa = (List<ArrayList<String>>) getIntent()
.getSerializableExtra("IntentExamResultDetail");
I used to set object with Pacelable or Serializable to transfer, but whenever I add other variables to object(model), I have to register it all. It's so nconvenient.
It's super easy to transfer object between activities or fragments.
Android DataCache
We can pass the object from one activity to another activity:
SupplierDetails poSuppliersDetails = new SupplierDetails();
Inside poSuppliersDetails we have some values. Now I am sending this object to target activity:
Intent iPODetails = new Intent(ActivityOne.this, ActivityTwo.class);
iPODetails.putExtra("poSuppliersDetails", poSuppliersDetails);
How to get this in ACtivityTwo:
private SupplierDetails supplierDetails;
supplierDetails =(SupplierDetails) getIntent().getSerializableExtra("poSuppliersDetails");
Pass one activity to another:
startActivity(new Intent(getBaseContext(),GetActivity.class).putExtra("passingkey","passingvalue"));
Get values:
String myvalue= getIntent().getExtras("passingkey");
Related
What is Parcelable in android
public static final Parcelable.Creator<MyParcelable> CREATOR = new Parcelable.Creator<MyParcelable>() { public MyParcelable createFromParcel(Parcel in) { return new MyParcelable(in); } public MyParcelable[] newArray(int size) { return new MyParcelable[size]; } }; private MyParcelable(Parcel in) { mData = in.readInt(); } } During my Android course, the instructor used this block of code and they didn't quite explained this. How can I interpret this code? I tried reading the documentation but I failed to interpret.
This concept is called Parcelable A Parcelable is the Android implementation of the Java Serializable. It assumes a certain structure and way of processing it. This way a Parcelable can be processed relatively fast, compared to the standard Java serialization. To allow your custom object to be parsed to another component they need to implement the android.os.Parcelable interface. It must also provide a static final method called CREATOR which must implement the Parcelable.Creator interface. The code you have written will be your model class. You can use Parcelable in Activity like : intent.putExtra("student", new Student("1")); //size which you are storing And to get this object : Bundle data = getIntent().getExtras(); Student student = (Student) data.getParcelable("student"); Here Student is a model class name. replace this with yours. In simple terms Parcelable is used to send a whole object of a model class to another page. In your code this is in the model and it is storing int value size to Parcelable object to send and retrieve in other activity. Reference : Tutorial 1 Tutorial 2 Tutorial 3
--> Parcelable in Android The Bundle object which is used to pass data to Android components is a key/value store for specialized objects. It is similar to a Map but can only contain these specialized objects You can place the following objects types into a Bundle: String primitives Serializable Parcelable If you need to pass your customer objects via a Bundle, you should implement the Parcelable interface. --> Implementing Parcelable You can create a POJO class for this, but you need to add some extra code to make it Parcelable. Have a look at the implementation. public class Student implements Parcelable{ private String id; private String name; private String grade; // Constructor public Student(String id, String name, String grade){ this.id = id; this.name = name; this.grade = grade; } // Getter and setter methods ......... ......... // Parcelling part public Student(Parcel in){ String[] data = new String[3]; in.readStringArray(data); this.id = data[0]; this.name = data[1]; this.grade = data[2]; } #override public int describeContents(){ return 0; } #Override public void writeToParcel(Parcel dest, int flags) { dest.writeStringArray(new String[] {this.id, this.name, this.grade}); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public Student createFromParcel(Parcel in) { return new Student(in); } public Student[] newArray(int size) { return new Student[size]; } }; } Once you have created this class, you can easily pass objects of this class through the Intent like this, and recover this object in the target activity. intent.putExtra("student", new Student("1","Mike","6")); Here, the student is the key which you would require to unparcel the data from the bundle. Bundle data = getIntent().getExtras(); Student student = data.getParcelable("student"); This example shows only String types. But, you can parcel any kind of data you want. Try it out.
Android setters and getters for ssh app [duplicate]
I am trying to work on sending an object of my customer class from one Activity and displaying it in another Activity. The code for the customer class: 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; } } I want to send its object from one Activity to another and then display the data on the other Activity. How can I achieve that?
One option could be letting your custom class implement the Serializable interface and then you can pass object instances in the intent extra using the putExtra(Serializable..) variant of the Intent#putExtra() method. Actual Code: In Your Custom Model/Object Class: public class YourClass implements Serializable { At other class where using the Custom Model/Class: //To pass: intent.putExtra("KEY_NAME", myObject); myObject is of type "YourClass". Then to retrieve from another activity, use getSerializableExtra get the object using same Key name. And typecast to YourClass is needed: // To retrieve object in second Activity myObject = (YourClass) getIntent().getSerializableExtra("KEY_NAME"); Note: Make sure each nested class of your main custom class has implemented Serializable interface to avoid any serialization exceptions. For example: class MainClass implements Serializable { public MainClass() {} public static class ChildClass implements Serializable { public ChildClass() {} } }
Implement your class with Serializable. Let's suppose that this is your entity class: 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; } We are sending the object called dene from X activity to Y activity. Somewhere in X activity; Deneme dene = new Deneme(4,"Mustafa"); Intent i = new Intent(this, Y.class); i.putExtra("sampleObject", dene); startActivity(i); In Y activity we are getting the object. Intent i = getIntent(); Deneme dene = (Deneme)i.getSerializableExtra("sampleObject"); That's it.
Use gson to convert your object to JSON and pass it through intent. In the new Activity convert the JSON to an object. In your build.gradle, add this to your dependencies implementation 'com.google.code.gson:gson:2.8.4' In your Activity, convert the object to json-string: Gson gson = new Gson(); String myJson = gson.toJson(vp); intent.putExtra("myjson", myjson); In your receiving Activity, convert the json-string back to the original object: Gson gson = new Gson(); YourObject ob = gson.fromJson(getIntent().getStringExtra("myjson"), YourObject.class); For Kotlin it's quite the same Pass the data val gson = Gson() val intent = Intent(this, YourActivity::class.java) intent.putExtra("identifier", gson.toJson(your_object)) startActivity(intent) Receive the data val gson = Gson() val yourObject = gson.fromJson<YourObject>(intent.getStringExtra("identifier"), YourObject::class.java)
Using global static variables is not good software engineering practice. Converting an object's fields into primitive data types can be a hectic job. Using serializable is OK, but it's not performance-efficient on the Android platform. Parcelable is specifically designed for Android and you should use it. Here is a simple example: Passing custom objects between Android activities You can generate Parcelable code for you class using this site.
While calling an activity Intent intent = new Intent(fromClass.this,toClass.class).putExtra("myCustomerObj",customerObj); In toClass.java receive the activity by Customer customerObjInToClass = getIntent().getExtras().getParcelable("myCustomerObj"); Please make sure that customer class implements 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(); }
In my experience there are three main solutions, each with its disadvantages and advantages: Implementing Parcelable Implementing Serializable Using a light-weight event bus library of some sort (for example, Greenrobot's EventBus or Square's Otto) Parcelable - fast and Android standard, but it has lots of boilerplate code and requires hard-coded strings for reference when pulling values out the intent (non-strongly typed). Serializable - close to zero boilerplate, but it is the slowest approach and also requires hard-coded strings when pulling values out the intent (non-strongly typed). Event Bus - zero boilerplate, fastest approach, and does not require hard-coded strings, but it does require an additional dependency (although usually lightweight, ~40 KB) I posted a very detailed comparison of these three approaches, including efficiency benchmarks.
I found a simple & elegant method: NO Parcelable NO Serializable NO Static Field No Event Bus Method 1 Code for the first activity: 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); Code for the second activity: final Object objReceived = ((ObjectWrapperForBinder)getIntent().getExtras().getBinder("object_value")).getData(); Log.d(TAG, "received object=" + objReceived); you will find objSent & objReceived have the same hashCode, so they are identical. But why can we pass a java object in this way? Actually, android binder will create global JNI reference for java object and release this global JNI reference when there are no reference for this java object. binder will save this global JNI reference in the Binder object. *CAUTION: this method ONLY work unless the two activities run in the same process, otherwise throw ClassCastException at (ObjectWrapperForBinder)getIntent().getExtras().getBinder("object_value") * class ObjectWrapperForBinder defination public class ObjectWrapperForBinder extends Binder { private final Object mData; public ObjectWrapperForBinder(Object data) { mData = data; } public Object getData() { return mData; } } Method 2 for the sender, use custom native method to add your java object to JNI global reference table(via JNIEnv::NewGlobalRef) put the return integer (actually, JNIEnv::NewGlobalRef return jobject, which is a pointer, we can cast it to int safely) to your Intent(via Intent::putExtra) for the receiver get integer from Intent(via Intent::getInt) use custom native method to restore your java object from JNI global reference table (via JNIEnv::NewLocalRef) remove item from JNI global reference table(via JNIEnv::DeleteGlobalRef), But Method 2 has a little but serious issue, if the receiver fail to restore the java object (for example, some exception happen before restore the java object, or the receiver Activity does not exist at all), then the java object will become an orphan or memory leak, Method 1 don't have this issue, because android binder will handle this exception Method 3 To invoke the java object remotely, we will create a data contract/interface to describe the java object, we will use the aidl file IDataContract.aidl package com.example.objectwrapper; interface IDataContract { int func1(String arg1); int func2(String arg1); } Code for the first activity 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); Code for the second activity: change the android:process attribute in AndroidManifest.xml to a non-empty process name to make sure the second activity run in another 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(); } In this way, we can pass an interface between two activities even though they run in different process, and call the interface method remotely Method 4 method 3 seem not simple enough because we must implement an aidl interface. If you just want to do simple task and the method return value is unnecessary, we can use android.os.Messenger Code for the first activity( sender): 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))); } } Code for the second activity ( receiver ): 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(); } } } All the Messenger.send will execute in a Handler asynchronously and sequentially. Actually, android.os.Messenger is also an aidl interface, if you have the android source code, you can find a file named IMessenger.aidl package android.os; import android.os.Message; /** #hide */ oneway interface IMessenger { void send(in Message msg); }
You could also write the object's data into temporary Strings and ints, and pass them to the activity. Of course that way, you get the data transported, but not the object itself. But if you just want to display them, and not use the object in another method or something like that, it should be enough. I did it the same way to just display data from one object in another activity. 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); You could also pass them in directly instead of the temp ivars, but this way it's clearer, in my opinion. Additionally, you can set the temp ivars to null so that they get cleaned by the GarbageCollector sooner. Good luck! On a side note: override toString() instead of writing your own print method. As mentioned in the comments below, this is how you get your data back in another activity: String fName = getIntent().getExtras().getInt("fname");
I made a singleton helper class that holds temporary objects. 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; } } Instead of putting your objects within Intent, use IntentHelper: IntentHelper.addObjectForKey(obj, "key"); Inside your new Activity, you can get the object: Object obj = (Object) IntentHelper.getObjectForKey("key"); Bear in mind that once loaded, the object is removed to avoid unnecessary references.
There are a couple of ways by which you can access variables or objects in other classes or Activity. A. Database B. Shared preferences. C. Object serialization. D. A class which can hold common data can be named as Common Utilities. It depends on you. E. Passing data through Intents and Parcelable Interface. It depends upon your project needs. A. Database SQLite is an open source database which is embedded into Android. SQLite supports standard relational database features like SQL syntax, transactions and prepared statements. Tutorials B. Shared preferences Suppose you want to store username. So there will now be two things, a key username, value value. How to store // 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(); Using putString(), putBoolean(), putInt(), putFloat(), and putLong() you can save your desired dtatype. How to fetch SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); String userName = sharedPref.getString("userName", "Not Available"); http://developer.android.com/reference/android/content/SharedPreferences.html C. Object serialization Object serlization is used if we want to save an object state to send it over a network or you can use it for your purpose also. Use Java beans and store in it as one of his fields and use getters and setter for that. JavaBeans are Java classes that have properties. Think of properties as private instance variables. Since they're private, the only way they can be accessed from outside of their class is through methods in the class. The methods that change a property's value are called setter methods, and the methods that retrieve a property's value are called getter methods. public class VariableStorage implements Serializable { private String inString; public String getInString() { return inString; } public void setInString(String inString) { this.inString = inString; } } Set the variable in your mail method by using VariableStorage variableStorage = new VariableStorage(); variableStorage.setInString(inString); Then use object serialzation to serialize this object and in your other class deserialize this object. In serialization an object can be represented as a sequence of bytes that includes the object's data as well as information about the object's type and the types of data stored in the object. After a serialized object has been written into a file, it can be read from the file and deserialized. That is, the type information and bytes that represent the object and its data can be used to recreate the object in memory. If you want tutorial for this refer to: Serialization in Java (blog post) Get variable in other classes (Stack Overflow) D. CommonUtilities You can make a class by yourself which can contain common data which you frequently need in your project. Sample public class CommonUtilities { public static String className = "CommonUtilities"; } E. Passing data through intents Please refer the tutorial Android – Parcel data to pass between Activities using Parcelable classes for this option of passing data.
Create your own class Customer as follows: 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; } } In your onCreate() method #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); } In xyz activity class you need to use the following code: 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 } Now you want to pass the object of this class in startActivity. Simply use this: Bundle b = new Bundle(); b.putSerializable("name", myClassObject); intent.putExtras(b); This works here because MyClass implements Serializable.
The best way is to have a class (call it Control) in your application that will hold a static variable of type 'Customer' (in your case). Initialize the variable in your Activity A. For example: Control.Customer = CustomerClass; Then go to Activity B and fetch it from Control class. Don't forget to assign a null after using the variable, otherwise memory will be wasted.
If you choose use the way Samuh describes, remember that only primitive values can be sent. That is, values that are parcable. So, if your object contains complex objects these will not follow. For example, variables like Bitmap, HashMap etc... These are tricky to pass by the intent. In general I would advice you to send only primitive datatypes as extras, like String, int, boolean etc. In your case it would be: String fname, String lname, int age, and String address. My opinion: More complex objects are better shared by implementing a ContentProvider, SDCard, etc. It's also possible to use a static variable, but this may fastly lead to error-prone code... But again, it's just my subjective opinion.
I am using parcelable to send data from one activity to another acivity. Here is my code that works fine in my project. 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}); } } In activityA use it like this: Bundle bundle = new Bundle(); bundle.putParcelableArrayList("channel",(ArrayList<Channel>) channels); Intent intent = new Intent(ActivityA.this,ActivityB.class); intent.putExtras(bundle); startActivity(intent); In ActivityB use it like this to get data: Bundle getBundle = this.getIntent().getExtras(); List<Channel> channelsList = getBundle.getParcelableArrayList("channel");
You can try to use that class. The limitation is that it can't be used outside of one process. One activity: final Object obj1 = new Object(); final Intent in = new Intent(); in.putExtra(EXTRA_TEST, new Sharable(obj1)); Other activity: 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); } }
This question is also discussed in another Stack Overflow question. Please have a look at a solution to Passing data through intent using Serializable. The main point is about using Bundle object which stores the necessary data inside Intent. Bundle bundle = new Bundle(); bundle.putSerializable(key1, value1); bundle.putSerializable(key2, value2); bundle.putSerializable(key3, value3); intent.putExtras(bundle); To extract values: Bundle bundle = new Bundle(); for (String key : bundle.keySet()) { value = bundle.getSerializable(key)); } Advantage of Serializable is its simplicity. However, you should consider using Parcelable method if you need many data to be transferred, because Parcelable is specifically designed for Android and it is more efficient than Serializable. You can create Parcelable class using: an online tool - parcelabler a plugin for Android Studio - Android Parcelable code generator
Start another activity from this activity and pass parameters via Bundle Object Intent intent = new Intent(getBaseContext(), YourActivity.class); intent.putExtra("USER_NAME", "xyz#gmail.com"); startActivity(intent); Retrieve data on another activity (YourActivity) String s = getIntent().getStringExtra("USER_NAME"); This is ok for a simple kind of data type. But if u want to pass complex data in between activities. U need to serialize it first. Here we have Employee Model class Employee{ private String empId; private int age; print Double salary; getters... setters... } You can use Gson lib provided by google to serialize the complex data like this 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);
Crete a class like bean class and implement the Serializable interface. Then we can pass it through the intent method, for example: intent.putExtra("class", BeanClass); Then get it from the other activity, for example: BeanClass cb = intent.getSerializableExtra("class");
Create two methods in your custom Class like this 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(); } } } Now in your sender Activity do like this Qabir q= new Qabir(22,"KQ"); Intent in=new Intent(this,SubActivity.class); in.putExtra("obj", q.toJSON()); startActivity( in); And in your receiver Activity Qabir q =new Qabir(); q.initilizeWithJSONString(getIntent().getStringExtra("obj"));
Android Activity objects can be destroyed and reconstituted. So, you will need to use another approach to look them - or any object they create!!! - up. That is, you could pass as static class reference but then the object handle (Java calls these "references", as does SmallTalk; but they are not references in the sense of C or assembly) will be possibly invalid later because a "feature" of Android OE is any Activity can be annihilated and reconstituted later. The original question asked "How to pass object from one activity to another in Android" and nobody has answered that. For sure, you can serialized (Serializable, Parcelable, to/from JSON) and pass a copy of the object's data and a new object having the same data could be created; but it will NOT have the same references/handles. Also, many others mentioned you can store the reference in a static store. And that will work unless Android decides to onDestroy your Activity. So, to really solve the original question you would need a static lookup plus each object will update its reference when/if it is recreated. E.g. each Android Activity would relist itself if its onCreate is called. You can also see how some people use the task list to search out an Activity by name. (system is temporarily destroying this instance of the activity to save space..getRunningTasks, the task list is effectively a specialized listing of the most recent object instance of each Activity). For reference: 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." So, the Message Bus is a workable solution. It basically "punts". Rather than try to have references to objects; then you re-architect your design to use MessagePassing instead of SequentialCode. Exponentially harder to debug; but it lets you ignore these sort of OperatingEnvironment understandings. Effectively, each object method access is inverted so the caller posts a Message and the object itself defines a handler for that message. Lots more code but can make it robust with the Android OE restrictions. If all you want is the top Activity (typical thing in Android apps due to "Context" being needed everywhere), then you can just have each Activity lists itself as "top" in the static global space whenever its onResume is called. Then your AlertDialog or whatever which needs a context can just grab it from there. Also, its a bit yucky to use a global but can simplifying passing a Context up and down everywhere and, for sure, when you use a MessageBus then IT IS global anyways.
Yeah, using a static object is by far the easiest way of doing this with custom non-serialisable objects.
I know that static is bad, but it seems that we're forced to use it here. The problem with parceables/seriazables is that the two activities have duplicate instances of the same object = waste of memory and 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); Called activity (note that onCreate() and onResume() may be called multiple times when the system destroys and recreates activities) if (IntentMailBox.content.size()>0) level = (Level) IntentMailBox.content.poll(); else // Here you reload what you have saved in onPause() Another way is to declare a static field of the class that you want to pass in that very class. It will serve only for this purpose. Don't forget that it can be null in onCreate, because your app package has been unloaded from memory by system and reloaded later. Bearing in mind that you still need to handle activity lifecycle, you may want to write all the data straight to shared preferences, painful with complex data structures as it is.
Create your custom class like this: public class Test implements 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); } Send data using Intent like this: Before starting your activity must set some data Intent intent = new Intent(context, PostDetailsActivity.class); intent.putExtra("data", (Parcelable) test); ((context)).startActivity(intent); Get data from intent like this: Test test = (Test) getIntent().getParcelableExtra("data");
The above answers are almost all correct but for those who don't understand those answers Android has a powerful class Intent with help of it you share data between not only activity but other components of Android (broadcast receiver, services for content provided we use ContetnResolver class no Intent). In your activity you build intent Intent intent = new Intent(context,SomeActivity.class); intent.putExtra("key",value); startActivity(intent); In your receiving activity, you have public class SomeActivity extends AppCompactActivity { public void onCreate(...){ ... SomeObject someObject = getIntent().getExtras().getParceable("key"); } } You have to implement Parceable or Serializable interface on your object in order to share between activities. It is hard to implement Parcealbe rather than Serializable interface on the object that's why android has plugins, especially for this. Download it and use it.
I had always wondered why this can't be as simple as calling into a method of the other activity. I recently wrote a utility library that makes it almost as simple as that. You can check it out here(https://github.com/noxiouswinter/gnlib_android/wiki/gnlauncher). GNLauncher makes sending objects/data to an Activity from another Activity etc as easy as calling a function in tha Activity with the required data as parameters. It introduces type safety and removes all the hastles of having to serialize, attaching to the intent using string keys and undoing the same at the other end. Usage Define an interface with the methods you want to call on the Activity to launch. public interface IPayload { public void sayHello(String name, int age); } Implement the above interface on the Activity to launch into. Also notify GNLauncher when the activity is ready. 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); } } In the other Activity, get a proxy to the above Activity and call any method with the desired parameters. public class Activity_2 extends Activity { public void onClick(View v) { ((IPayload)GNLauncher.get().getProxy(this, IPayload.class, Activity_1.class)).sayHello(name, age); } } The first activity will be launched and the method called into with the required parameters. Prerequisites Please refer to https://github.com/noxiouswinter/gnlib_android/wiki#prerequisites for information on how to add the dependencies.
Pass object from one activity to another activity. (1) source activity Intent ii = new Intent(examreport_select.this, BarChartActivity.class); ii.putExtra("IntentExamResultDetail", (Serializable) your List<ArraList<String>> object here); startActivity(ii); (2) destination acitivity List<ArrayList<String>> aa = (List<ArrayList<String>>) getIntent() .getSerializableExtra("IntentExamResultDetail");
I used to set object with Pacelable or Serializable to transfer, but whenever I add other variables to object(model), I have to register it all. It's so nconvenient. It's super easy to transfer object between activities or fragments. Android DataCache
We can pass the object from one activity to another activity: SupplierDetails poSuppliersDetails = new SupplierDetails(); Inside poSuppliersDetails we have some values. Now I am sending this object to target activity: Intent iPODetails = new Intent(ActivityOne.this, ActivityTwo.class); iPODetails.putExtra("poSuppliersDetails", poSuppliersDetails); How to get this in ACtivityTwo: private SupplierDetails supplierDetails; supplierDetails =(SupplierDetails) getIntent().getSerializableExtra("poSuppliersDetails");
Pass one activity to another: startActivity(new Intent(getBaseContext(),GetActivity.class).putExtra("passingkey","passingvalue")); Get values: String myvalue= getIntent().getExtras("passingkey");
Java , Android: ClassCastException after Intent [duplicate]
This question already has answers here: Cannot pass custom Object in an Intent: The Method Put Extra is Ambiguous for the type Intent (5 answers) Closed 7 years ago. I have the class Playlist public class Playlist extends ArrayList<Track> implements Serializable { String module; String name, playlistId; public Playlist(String name) { super(); this.name = name; } ... } and I try to give it to a Intent with: ... Intent intent = new Intent(this, PlaylistActivity.class); intent.putExtra("playlist", Modul.loaded[id].getPlaylist(pId)); //Return Playlist startActivity(intent); And when I try to get the Playlist with: Intent intent = getIntent(); playlist = (Playlist) intent.getSerializableExtra("playlist"); And here I get this error: Caused by: java.lang.ClassCastException: java.util.ArrayList cannot be cast to com.timia2109.nukla.Playlist But it must be a Playlist, because I create it as a Playlist and I don't will cast it to a Serializable with the Intent. I don't find a solution on the Internet, but I don't found anything. Or is there a way to do that: PlaylistActivity pa = new PlaylistActivity(); pa.setPlaylist( playlist ); //And now start this Activity Thanks!
There was an old bug related to this that is now marked as obsolete. I don't know if it is still an issue. The simplest solution though is of course to manually handle the (re)creation of your object Ideally start by changing your implementation to Parcelable something like the following which is similar to something I've used in the past public static class Playlist extends ArrayList<Track> implements Parcelable { String module; String name, playlistId; public Playlist(String name) { super(); this.name = name; } protected Playlist(Parcel in) { module = in.readString(); name = in.readString(); playlistId = in.readString(); //this line you might need to tweak & error handle, I've jsut written this from memory super.addAll( (Collection<? extends Track>) Arrays.asList( in.readParcelableArray(Track.class.getClassLoader() )) ); } #Override public int describeContents() { return 0; } #Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(module); dest.writeString(name); dest.writeString(playlistId); dest.writeParcelableArray(toArray(new Track[size()]), flags); } public static final Creator<Playlist> CREATOR = new Creator<Playlist>() { #Override public Playlist createFromParcel(Parcel in) { return new Playlist(in); } #Override public Playlist[] newArray(int size) { return new Playlist[size]; } }; } The reasons for preferring parcelable are explained well here Your receiving activity should handle a parcelable better. Whether you decide to make your object Parcelable or not you can handle the recreation yourself like follows public static class Playlist ... { public Playlist(ArrayList<Track> arrList) { super( arrList ); } .... } and using Intent intent = getIntent(); ArrayList<Track> arrList = (ArrayList<Track>) intent.getSerializableExtra("playlist"); playlist = new Playlist(arrList); You'll just need to modify it for those extra two fields you have and be aware that when you try to write it to an intent it might complain about generics, so simply manually cast to parcelable/serializable when you set the extra: intent.putExtra("playlist", (Parcelable) Modul.loaded[id].getPlaylist(pId));
ORMLite : Internal DAO object is null
I'm using ORMLite, trying to use the ForeignCollectionKey but I got the following error : Internal DAO object is null. LazyCollections cannot be used if they have been deserialized. I've my object named Zone : public class Zone implements Serializable { private static final long serialVersionUID = 1L; public static final String ZONE_ID = "id"; public static final String ZONE_PARENT_ID = "parentZoneId"; #DatabaseField(generatedId=true) private int id; #DatabaseField() String name; #DatabaseField(foreign=true, foreignAutoRefresh = true) Zone parentZone; #ForeignCollectionField(foreignFieldName = "parentZone", eager = true) private ForeignCollection<Zone> zoneChild; public Zone() { // TODO Auto-generated constructor stub } public ForeignCollection<Zone> getZoneChild() { return zoneChild; } public void setZoneChild(ForeignCollection<Zone> zoneChild) { this.zoneChild = zoneChild; } public String getName() { return name; } public void setName(String name) { this.name = name; } In a class i'm doing a recursive method to get all my zone child objects : public void getZone(Zone zone, Dao<Zone, Integer> tempZoneDao){ ZoneListEntity zoneEntity = new ZoneListEntity(); zoneEntity.setName(zone.getName()); zoneEntity.setNiveau(0); zoneEntity.setZone(zone); mainZoneList.add(zoneEntity); List<Zone> childList = new ArrayList<Zone>(zone.getZoneChild()); //set rootZone's children as ZoneListEntity for(Zone currentZone : childList){ ZoneListEntity zoneGroup = new ZoneListEntity(); zoneGroup.setName(currentZone.getName()); zoneGroup.setZone(currentZone); System.out.println("Zone : "+currentZone.getName()); getZone(currentZone, tempZoneDao); } } When i'm entering for the first time in my getZone, everything going well. Then when I loop in getZone the application crashes trying to access to the child zone : List<Zone> childList = new ArrayList<Zone>(zone.getZoneChild()); Do you have any ideas ? Is my model construction right ? Thanks
Do you have any ideas ? Is my model construction right ? Thanks So the exception message is trying to explain what is going on. I'm not sure how it can be improved. Internal DAO object is null. LazyCollections cannot be used if they have been deserialized. You are trying to access zoneChild which is a ForeignCollection that has been deserialized. Since it has been deserialized all of the underlying database configurations and connections could not be reestablished. I guess this can happen when it stored in an Android Bundle? I'm not sure if this is the only case. If you need to get the Zone children you are going to have to either call dao.refresh() on the entity after you deserialize it or do the query yourself by doing the zoneDao.
I solved this problem like Gray suggested: pass the primary key attribute in the Bundle and then obtain the object again from the database in the destination Activity: Example: Let's suppose I want to pass a Person object and that I've declared Person.name as: #DatabaseField (columnName ="name") private String name; Then: ActivityA Intent intent = new Intent(ActivityA.this, ActivityB.class); Bundle bundle = new Bundle(); bundle.putString("NAME" Person.getName()); intent.putExtras(bundle); ActivityB String name = getIntent().getExtras().getString("NAME")); Person p = getHelper().getPersonDao().queryForEq("name", name); And there you are, your Collection will be refreshed.
How to pass custom object in Bundle?
I am trying to pass my own custom object into a bundle: Bundle b = new Bundle(); STMessage message = (STMessage)a.getAdapter().getItem(position); b.putObject("message",message); I get the error: The method putObject(String, Object) is undefined for the type Bundle
One way is to have your custom object implement the Parcelable interface and use Bundle.putParcelable/Bundle.getParcelable
Model Class package com.sam.bundleobjectpass; import java.io.Serializable; /** * Created by Samir on 31.8.2016. */ public class Model implements Serializable { private String name; private String surName; private int age; public Model(String name, String surName, int age) { this.name = name; this.surName = surName; this.age = age; } public String getName() { return name; } public String getSurName() { return surName; } public int getAge() { return age; } } MainActivity public class MainActivity extends AppCompatActivity { #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Model model = new Model("Sam", "Sami",32); Intent i = new Intent(MainActivity.this, ReceiverActivity.class); i.putExtra("Editing", model); // sending our object. In Kotlin is the same startActivity(i); } } ReceiverActivity public class ReceiverActivity extends Activity { TextView txt_name; TextView txt_surname; TextView txt_age; #Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.second); txt_name = (TextView)findViewById(R.id.txt_name); txt_surname = (TextView)findViewById(R.id.txt_surname); txt_age = (TextView)findViewById(R.id.txt_age); // receiving our object Model model = (Model) getIntent().getSerializableExtra("Editing"); txt_name.setText(model.getName()); txt_surname.setText(model.getSurName()); txt_age.setText(""+model.getAge()); } } // Kotlin val model: ProgramModel? = intent.getSerializableExtra("Editing") as ProgramModel? model?.let { // means if not null or empty txt_act_daily_topic.text = it.title }
Since using Parsable is designed for high performance IPC transport as mentioned in some of the comments, I tried using a different approach. My approach uses GSON library by google. Example public class Person{ private String name; private int age; // Getter and Setters omitted } You can have a method in utility class that returns Gson instance, this is for the sake of clean code and organisation. I will use GsonBuilder incase someone what to register custom adapter. public class Utils { private static Gson gson; public static Gson getGsonParser() { if(null == gson) { GsonBuilder builder = new GsonBuilder(); gson = builder.create(); } return gson; } } Moment of truth! PUT Bundle args = new Bundle(); String personJsonString = Utils.getGsonParser().toJson(person); args.putString(PERSON_KEY, personJsonString); GET Bundle args = getArguments(); String personJsonString = args.getString(PERSON_KEY); Person person= Utils.getGsonParser().fromJson(personJsonString, Person.class); Currently I don't know the performance limitation of this approach. But it works just fine
Make your custom object Parcelable or Serializable then use putParcelable or putSerializable. Depending on the complexity of your object one or other may be easier.
As Ryan stated. Also if you only want to pass one object on a soft kill consider using onRetainConfigurationInstance and getLastNonConfigurationInstance to pass the serializable object. The entire object tree must be serializable. If you are passing the object via an intent, consider refactoring the object code to a Parceable code later, once the architecture has stabilized. Finally, consider using the fully qualified name of the class when storing the object into the Bundle as in: inPWState= (PasswordState) getIntent().getSerializableExtra("jalcomputing.confusetext.PasswordState"); Hope that helps. JAL
It's work if you make your object class as Serializable class your_data_class implements Serializable