I am utilizing the follow class, which I have as an object:
http://pastebin.com/rKmtbDgF
And I am trying to pass it across using:
Intent booklist = new Intent(getBaseContext(), BookList.class);
Bundle bundle = new Bundle();
bundle.putParcelable("imageManager", (Parcelable) im);
booklist.putExtras(bundle);
booklist.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(booklist);
And I am trying to receive it using:
ImageManager im = (ImageManager) getIntent().getExtras().getParcelable("imageManager");
I am getting the following error:
java.lang.ClassCastException: com.example.example.ImageManager
Easiest Way to do this is to implement Serializeable ..
import java.io.Serializable;
#SuppressWarnings("serial")
public class Student implements Serializable {
public Student(int age, String name){
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
private int age;
private String name;
}
Sending object from Activity A to Activity B
Student student = new Student (18,"Zar E Ahmer");
Intent i = new Intent(this, B.class);
i.putExtra("studentObject", student);
startActivity(i);
Getting Object in Activity B.
Intent i = getIntent();
Student student = (Student)i.getSerializableExtra("studentObject");
go here, and paste your class structure.it will create parcelable class for you and then you can easily pass your object around activities.
Try the following post.
How can I make my custom objects Parcelable?
The problem is that the ImageManager is not a parable Object. So that's giving the cast error.
If the imageManager is yours you should make the class implement Pracabale like the url above sais.
EDIT:
Above should be the right way of doing Parceables,
But in your case i really would say you shouldn't pass the ImageManager between different activities. Because the context that your using in the ImageManager class will be disposed.. And you'll certainly get an error.
So why don't you make a new instance of the class instead and only pass the Bitmap in to it (After transferring the bitmap and other not context related information with the bundle off course.)
Related
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.
I have a provider that takes a decent number of properties. For example:
public MyProvider(
byte[] image,
String firstName,
String nickName,
String lastName,
String hairColor,
String favoriteFood,
String favoriteColor,
String cityBorn,
String stateBorn,
long favoriteNumber,
int age,
String nameOfFather,
String nameOfMother,
String nameOfBestFriend
)
I do know that I can get the value of each property, and set each individual one as an extra, like so:
Intent myIntent = new Intent(firstActivity.this, secondActivity.class);
myIntent.putExtra("firstName", myProvider.getFirstName().toString());
myIntent.putExtra("nickName", myProvider.getNickName().toString());
...
firstActivity.this.startActivity(myIntent);
I would like to just pass the entire provider as an extra, and then be able to get the provider in the next activity. I know it's possible to do such a thing in Swift, but I am not sure how to do so in Java for Android Studio.
What I am hoping to be able to do is something like the following:
MyProvider newPerson = new MyProvider(image, firstName, nickName, lastName, hairColor, favoriteFood, favoriteColor, cityBorn, stateBorn, favoriteNumber, age, nameOfFather, nameOfMother, nameOfBestFriend);
intent.putExtra(newPerson);
But it seems like a provider cannot be passed like this (or possibly at all?).
Alternative Attempt:
I also attempted passing it as data like a URI (see here), but .setData is specifically for URIs.
Is there such a way to pass the entire provider as an extra, and then be able to get the provider in the next activity?
Thanks in advance.
EDIT
I have implemented Parcelable as #NabinBhandari and #JuanCruzSoler suggested, but it is causing the following error:
Cannot resolve constructor 'MyProvider(byte[], java.lang.String, long)'
when I call:
MyApartmentsProvider newApartment = new MyApartmentsProvider(image, firstName, favoriteNumber);
My updated MyProvider.java is as follows:
(note: I cut out some variables for the time being to make the example easier to work with)
import android.os.Parcel;
import android.os.Parcelable;
public class MyProvider implements Parcelable {
/////////////////////////
// Initializers
byte[] image;
String firstName;
long favoriteNumber;
// End of [Initializers]
/////////////////////////
/////////////////////////
// Getters
public byte[] getImage() {
return image;
}
public String getFirstName() {
return firstName;
}
public long getFavoriteNumber() {
return favoriteNumber;
}
// End of [Getters]
/////////////////////////
/////////////////////////
// Setters
public void setImage(byte[] image) {
this.image = image;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setFavoriteNumber(long favoriteNumber) {
this.favoriteNumber = favoriteNumber;
}
// End of [Setters]
/////////////////////////
public MyProvider() {
super();
}
public MyProvider(Parcel parcel) {
image = new byte[parcel.readInt()];
parcel.readByteArray(image);
this.firstName = parcel.readString();
this.favoriteNumber = parcel.readLong();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(image.length);
parcel.writeByteArray(image);
parcel.writeString(this.firstName);
parcel.writeLong(this.favoriteNumber);
}
public static final Creator<MyProvider> CREATOR=new Creator<MyProvider>() {
#Override
public MyProvider createFromParcel(Parcel parcel) {
return new MyProvider(parcel);
}
#Override
public MyProvider[] newArray(int i) {
return new MyProvider[i];
}
};
}
Make your Provider class implement the interface Serializable or Parcelable.
Parcelable is faster but Serializable is easier to implement.
To send:
intent.putExtra(KEY, yourObj);
To receive:
Provider provider = (Provider) getIntent().getSerializableExtra(KEY);
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));
Well, i was trying to pass arraylist of objects from one activity to another. I have 2 constructors in the class Student.
If, i use, Serializable than the code is like below:
#SuppressWarnings("serial")
public class Student implements Serializable
{
private int studentdID;
private String studentName;
private String studentDept;
public Student(){}
public Student(String name, String dpt)
{ this.studentName = name;
this.studentDept = dpt;}
public Student(int id, String name, String dpt)
{ this.studentdID = id;
this.studentName = name;
this.studentDept = dpt; }
public int getstudentdID() { return studentdID; }
public void setstudentdID(int studentdID) {this.studentdID = studentdID;}
public String getstudentName() { return studentName;}
public void setstudentName(String studentName) {this.studentName = studentName;}
public String getstudentDept() { return studentDept; }
public void setstudentDept(String studentDept) { this.studentDept = studentDept;}
}
But the problem i am facing is that how am i going to do this with parcelable? How am i going to set the values of the variables in class-like i did with Serializable? I mean separately using 2 constructors-one without ID another without the ID?
Did you read how Parcelable works?
You need only one constrcutor for parcelable to read what you pass to it, and Parcelable interface will add a method writeToParcel where you put the data to save.
It's not an automatic process like Serializable, everything is up to you.
The constructor which Parcelable will use will accept only one argument Parcel where you will find some methods like read*(KEY) to read back values.
And in writeToParcel you will write in the Parcel (the argument of the method) the values you want pass to pass with write*(KEY, VALUE).
Parcelable don't care about your constructors or fields.
P.S You will need a CREATOR too. Read some tutorial online to know more about it if you need.
Marco's answer explains why Parcelable doesn't automatically decide what constructor to use - it can't.
However, there is a way around this. Use Parcel.dataAvail(), which
Returns the amount of data remaining to be read from the parcel. That
is, dataSize()-dataPosition().
For example,
public Student(){}
public Student(String name, String dpt)
{
this.studentName = name;
this.studentDept = dpt;}
public Student(int id, String name, String dpt)
{ this.studentdID = id;
this.studentName = name;
this.studentDept = dpt;
}
public Student(Parcel in) {
name = in.readString();
dpt = in.readString();
if(in.dataAvail() > 0) // is there data left to read?
id = in.readInt();
}
^ The above constructor will allow for the necessary variables to be instantiated correctly. Also, you define writeToParcel() something like:
public void writeToParcel(Parcel out) {
out.writeString(name);
out.writeString(dpt);
//0 is the default value of id if you didn't initialize it like
// in the first constructor. If it isn't 0, that means it was initialized.
if(id != 0)
out.writeInt(id);
}
Of course, you'll need to define your CREATOR like so:
public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {
public Student createFromParcel(Parcel in) {
return new Student(in);
}
public Student[] newArray(int size) {
return new Student[size];
}
};
#u3l solution is not required..how many constructors are there it doesn't matter.
simple it works go as normal implementation.
I mean no special care is required when multiple constructors present in parcelable.
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