Here's what inside Player.class
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by pietsteph on 15/09/17.
*/
public class Player implements Parcelable{
String name;
int score;
protected Player(Parcel in) {
name = in.readString();
score = in.readInt();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(score);
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<Player> CREATOR = new Creator<Player>() {
#Override
public Player createFromParcel(Parcel in) {
return new Player(in);
}
#Override
public Player[] newArray(int size) {
return new Player[size];
}
};
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public Player(String name) {
this.name = name;
this.score = 0;
}
}
In the MainActivity.class, I make my custom object as an array with size = 2 (2 player) and put it in intent.
Player players[] = new Player[2];
players[0] = new Player(name1);
players[1] = new Player(name2);
Intent intent = new Intent(getApplicationContext(), TurnActivity.class);
intent.putExtra(PLAYER_KEY, players);
startActivity(intent);
Want to get my intent in TurnActivity.class, tried getParcelableExtra.
Intent intent = getIntent();
Player players[] = intent.getParcelableExtra(MainActivity.PLAYER_KEY);
But it gave me an error
Error:(28, 59) error: incompatible types: inferred type does not conform to upper bound(s)inferred: INT#1
upper bound(s): Player[],Parcelable
where INT#1 is an intersection type:
INT#1 extends Player[],Parcelable
Even tried getParcelableArrayExtra and gave me a red line says Incompatible type.
This is a problem with Java 8. You probably need to do something like this:
Intent intent = getIntent();
Parcelable parcelable[] = intent.getParcelableArrayExtra(MainActivity.PLAYER_KEY);
Now, when you use it, you need to cast it to its proper type. Something like this:
Player player = (Player)parcelable[0];
Implements
Parcalable
interface with
Player
class
I used
Android Parcelable code generator plugin
to do this task.
then you will be able to save your custom objects array in intents.
I use to do something like this
public void moveToNext(ArrayList images){
Intent mainIntent = new Intent(SplashScreen.this,MainActivity.class);
//add data to parcalable
mainIntent.putParcelableArrayListExtra("data",images);
startActivity(mainIntent);
finish();
}
//while getting data
ArrayList v =
getIntent().getParcelableArrayListExtra("data");
Related
I have an ArrayList of custom FlightData objects within the intent. I load the intent and get the arraylist as null, and the foreach loop also forces me to use Object as type.
Saving arraylist into intent:
intent.putParcelableArrayListExtra("FlightDataList", (ArrayList<? extends Parcelable>) flightDataList);
Loading of intent:
Intent intent = getIntent();
LinearLayout layout_datasheet = findViewById(R.id.layout_datasheet);
List flightDataList = intent.getParcelableArrayListExtra("FlightDataList");
if (flightDataList == null){
Log.d("flightDataList_size", "FlightDataList is null"); // this fires
}
assert flightDataList != null;
for (Object data : flightDataList){
data = (FlightData) data; // items in list are of type FlightData
TextView tv = new TextView(this);
tv.setText(data.toString());
layout_datasheet.addView(tv);
}
My custom class' parcelable functions (x,y,time, has getters-setters):
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeDouble(x);
dest.writeDouble(y);
dest.writeDouble(time);
}
public static final Creator<FlightData> CREATOR = new Creator<FlightData>() {
#Override
public FlightData createFromParcel(Parcel in) {
return new FlightData(in);
}
#Override
public FlightData[] newArray(int size) {
return new FlightData[size];
}
};
1.First Implement Parceable in your FlightData object model / pojo / class
2.val flightDataList= ArrayList<FlightData>()
3.val args = Bundle()
4.args.putParcelableArrayList("FlightDataList", flightDataList)
5.intent.putExtra(args)
Then to get list
val flightDataList = context.getIntent().getExtras().getParcelableArrayList("FlightDataList")
I doubt that you have implemented Parcable in FlightData
https://medium.com/techmacademy/how-to-implement-and-use-a-parcelable-class-in-android-part-1-28cca73fc2d1
It should work. The only thing that I am missing in your example is the constructor. It could explain the null your are getting.
Try adding this constructor for FlightData
public FlightData(Parcel in) {
x = in.readDouble();
y = in.readDouble();
time = in.readDouble();
}
did you try creating a datastructure that implements parcelable?
public class flightDataList implements Parcelable{
String dataThingyString;
int dataThingyInt;
public flightDataList(String dataThingyString, int dataThingyInt){
this.dataThingyString = dataThingyString;
this.dataThingyInt = dataThingyInt;
}
public flightDataList(Parcle in){
this.dataThingyString = in.readString();
this.dataThingyInt = in.readInt();
}
#Override
public void writeToParcel(Parcel dest, int flags){
dest.writeString(dataThingyString);
dest.writeInt(dataThingyInt);
}
public static final Creator<flightDataList> CREATOR = new Creator<flightDataList>(){
#Override
public flightDataList createFromParcel(Parcel source){
return new flightDataList(source);
}
#Override
public flightDataList[] newArray(int size){
return new flightDataList[size];
}
}
public void setdataThingyString(String stringData){
this.dataThingyString = stringData;
}
public void setdataThingyInt(int intData){
this.dataThingyInt = intData;
}
public String getdataThingyString(){
return dataThingyString;
}
public int getdataThingyInt(){
return dataThingyInt;
}
#Override
public int describeContents(){
return 0;
}
}
I have two Activities, A and B. I am trying to send object from Activity A, to Activity B. When in Activity A, I can see that my List contains two items, but when I retrieve it in Activity B, the List contains 7000000+ records.
Here is my Assessment class, that implements Parcelable, and contains an ArrayList<Photo> which should be parcelable as well.
Assessment POJO:
public class Assessment extends BaseObservable implements Parcelable {
public Assessment(){
}
#SerializedName("Vehicle")
private String vehicle;
#SerializedName("Photos")
private List<Photo> photos;
#Bindable
public String getVehicle() {
return vehicle;
}
public void setVehicle(String vehicle) {
this.vehicle = vehicle;
notifyPropertyChanged(BR.vehicle);
}
public List<Photo> getPhotos() {
return photos;
}
public void setPhotos(List<Photo> photos) {
this.photos = photos;
}
protected Assessment(Parcel in) {
vehicle = in.readString();
photos = new ArrayList<Photo>();
in.readTypedList(photos, Photo.CREATOR);
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(vehicle);
dest.writeTypedList(photos);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<Assessment> CREATOR = new Parcelable.Creator<Assessment>() {
#Override
public Assessment createFromParcel(Parcel in) {
return new Assessment(in);
}
#Override
public Assessment[] newArray(int size) {
return new Assessment[size];
}
};
}
Photo POJO:
public class Photo implements Parcelable {
public Photo(){
}
#SerializedName("PhotoPath")
private String photoPath;
public String getPhotoPath() {
return photoPath;
}
public void setPhotoPath(String photoPath) {
this.photoPath = photoPath;
}
#SerializedName("Base64PhotoString")
private String photoBase64String;
public String getPhotoBase64String() {
return photoBase64String;
}
public void setPhotoBase64String(String photoBase64String) {
this.photoBase64String = photoBase64String;
}
protected Photo(Parcel in) {
photoPath = in.readString();
photoBase64String = in.readString();
}
//region parelable
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(photoPath);
dest.writeString(photoBase64String);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<Photo> CREATOR = new Parcelable.Creator<Photo>() {
#Override
public Photo createFromParcel(Parcel in) {
return new Photo(in);
}
#Override
public Photo[] newArray(int size) {
return new Photo[size];
}
};
//endregion
}
Here is how I send the object via Intent from Activity A, to Activity B:
public void OnAdapterItemClicked(View view){
Intent activityIntent = new Intent(this, com.example.andrewkp.gaassessing.DisplayAssessment.class);
Assessment extraAssessment = getAssessmentFromCollection(view); //extraAssessment.getPhotos().size() == 2
activityIntent.putExtra("assessment", extraAssessment);
startActivity(activityIntent);
}
And here is how I read the Parcelable object in Activity B:
assessment = getIntent().getExtras().getParcelable("assessment");
I have looked at the following article, and I follow exactly what they do, but my photos list does not persist through to Activity B:
When I debug the readTypedList method in Parcel class, I can see that it adds 7000000+ records to my ArrayList, but never removes them. Why is this behavior happening?
You are able to put up to 1MB of data in a Bundle encapsulated inside Intent.
You will get bunch of errors when sending PhotoBase64String in Bundle.
However, in order to overcome this issue, I would suggest path/URI of your photo to your second activity. Then in your second activity, read photo from that path, and perform your desired operation.
I have an object called Order which I want to pass between activities. Currently I am using Parcelable to do so.
public class Order implements Parcelable {
private String email;
private Long timestamp;
private List<OrderItem> items;
public Order() { }
private Order(Parcel in) {
email = in.readString();
timestamp = in.readLong();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(email);
if (timestamp == null) {
dest.writeByte((byte) 0);
} else {
dest.writeByte((byte) 1);
dest.writeLong(timestamp);
}
dest.writeTypedList(items);
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<Order> CREATOR = new Creator<Order>() {
#Override
public Order createFromParcel(Parcel in) {
return new Order(in);
}
#Override
public Order[] newArray(int size) {
return new Order[size];
}
};
// Getters
...
}
The items field is a List of OrderItem objects which implement the Parcelable interface.
public class OrderItem implements Parcelable {
private String orderedClothingId;
private int quantity;
public OrderItem() { }
public OrderItem(String orderedClothingId, int quantity) {
this.orderedClothingId = orderedClothingId;
this.quantity = quantity;
}
private OrderItem(Parcel in) {
orderedClothingId = in.readString();
quantity = in.readInt();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(orderedClothingId);
dest.writeInt(quantity);
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<OrderItem> CREATOR = new Creator<OrderItem>() {
#Override
public OrderItem createFromParcel(Parcel in) {
return new OrderItem(in);
}
#Override
public OrderItem[] newArray(int size) {
return new OrderItem[size];
}
};
}
Now to pass an Order object called order from one activity to another I do the following:
Intent intent = new Intent(mContext, ActivityTwo.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(ORDER_DETAIL_INTENT_EXTRA_KEY, order);
mContext.startActivity(intent);
In ActivityTwo I collect the Order object like so:
Bundle data = getIntent().getExtras();
assert data != null;
mOrder = data.getParcelable(ORDER_DETAIL_INTENT_EXTRA_KEY);
However, when I log the items field contained in the Order object in ActivityTwo it is null. How do I pass the original non-null Order object between activities without the items list being null?
First you miss to read the array back with dest = in.readTypedList(emptyList, CREATOR);
But second and more important, you need to write/read the same ammount of arguments, since you have a if in your writeToParcel you need the same when reading:
private Order(Parcel in) {
email = in.readString();
if(in.readByte() == 1)
timestamp = in.readLong(); //here to skip just like the writeToParcel
in.readTypedList(items = new ArrayList<OrderItem>(), OrderItem.CREATOR);
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(email);
if (timestamp == null) {
dest.writeByte((byte) 0);
} else {
dest.writeByte((byte) 1);
dest.writeLong(timestamp);
}
dest.writeTypedList(items);
}
From first glance it looks like you are passing different different keys within your parcelable
ORDER_DETAIL_INTENT_EXTRA_KEY in the first and CLOTHING_ADMIN_DETAIL_INTENT_EXTRA_KEY in the 2nd. They should both be the same, so pick which one.
Also you can use getIntent().getParcelableExtra() instead of having to use a Bundle
I'm attempting to make an app, and at this point in the app I'm launching an activity, and adding some parcelable extras to the activity. However, with the addition of my extras, the intent will not start the activity. Commenting the putExtra line allows it to function. There is no error to speak of, and the application simply loops and allows the use of the previous activity again.
The problem code lies here:
//puzOut is a Puzzle object (code below)
intent intent = new Intent(ChooseActivity.this, GameActivity.class);
intent.putExtra("puzzle", puzOut); // <- prevents activity starting
startActivity(intent);
The data in putExtra is an object from my app, Puzzle. Below is the code for that, including the Parcelling code.
public class Puzzle implements Parcelable{
private String Name;
private String pictureSet;
private Fruit_Tile[] fruitArray;
int rows;
int columns;
public Puzzle(String puzzleId, String picSet, Fruit_Tile[] array, int rowCount, int columnCount)
{
Name = puzzleId;
pictureSet = picSet;
fruitArray = array;
rows = rowCount;
columns = columnCount;
}
private Puzzle(Parcel in) {
Name = in.readString();
pictureSet = in.readString();
Parcelable[] parcelableArray = in.readParcelableArray(Fruit_Tile.class.getClassLoader());
//Fruit_Tile[] results = null;
if(parcelableArray != null)
{
fruitArray = Arrays.copyOf(parcelableArray, parcelableArray.length, Fruit_Tile[].class);
}
rows = in.readInt();
columns = in.readInt();
}
public String getName()
{
return Name;
}
public String getPictureSet()
{
return pictureSet;
}
public Fruit_Tile[] getFruitArray()
{
return fruitArray;
}
public int getRows()
{
return rows;
}
public int getColumns()
{
return columns;
}
#Override
public void writeToParcel(Parcel out, int flags){
out.writeString(Name);
out.writeString(pictureSet);
out.writeParcelableArray(fruitArray, flags);
out.writeInt(rows);
out.writeInt(columns);
}
public static final Parcelable.Creator<Puzzle> CREATOR = new Parcelable.Creator<Puzzle>(){
public Puzzle createFromParcel(Parcel in) {
return new Puzzle(in);
}
public Puzzle[] newArray(int size) {
return new Puzzle[size];
}
};
#Override
public int describeContents()
{
return 0;
}
}
The puzzle object uses another object, Fruit_Tile, which I have also tried to make parcellable. Below is the code for that.
public class Fruit_Tile implements Parcelable
{
private Bitmap fruit;
private int x_Position;
private int y_Position;
public Fruit_Tile(Bitmap fruitInput, int x, int y)
{
fruit = fruitInput;
x_Position = x;
y_Position = y;
}
private Fruit_Tile(Parcel in)
{
fruit = Bitmap.CREATOR.createFromParcel(in);
x_Position = in.readInt();
y_Position = in.readInt();
}
public Bitmap getImage()
{
return fruit;
}
public void setImage(Bitmap input)
{
fruit = input;
}
public int getX_Position()
{
return x_Position;
}
public int getY_Position()
{
return y_Position;
}
public void setX_Position(int x) { x_Position = x; }
public void setY_Position(int y) { y_Position = y; }
public int describeContents()
{
return 0;
}
#Override
public void writeToParcel(Parcel out, int flags)
{
fruit.writeToParcel(out, flags);
out.writeInt(x_Position);
out.writeInt(y_Position);
}
public static final Parcelable.Creator<Fruit_Tile> CREATOR = new Parcelable.Creator<Fruit_Tile>(){
public Fruit_Tile createFromParcel(Parcel in){
return new Fruit_Tile(in);
}
public Fruit_Tile[] newArray(int size){
return new Fruit_Tile[size];
}
};
}
When I debug and step, following the line
startActivity(intent);
if I step continually, the program eventually returns to the Looper.java code and loops. I can then access the UI again of the first activity, and start the whole process again.
Why is my activity not starting with this putExtra line? There are no errors to speak of (that I have been able to find).
To reiterate, if the putExtra is commented out, the activity will launch.
I'd really appreciate some help!
It happens when you try to write null value in the parcel. In the following code snippet if the Name String is null it will cause activity launching issue.
out.writeString(Name);
So the solution is, either set default value of the class data members at the time of declaration. like
String Name = "";
Or at the time of writing to parcel add a check if its null then don't write it in parcel. Like
if (Name != null) {
out.writeString(Name);
}
I've been searching for a simple example of this with no luck.
In my android application I have two activities:
1. The main activity which is launched at startup
2. A second activity which is launched by pressing a button on the main activty.
When the second activity is finished (by pressing a button) I want it to send back an ArrayList of type MyObject to the main activity and close itself, which the main activity can then do whatever with it. How would I go about achieving this? I have been trying a few things but it is crashing my application when I start the second activity.
When the user presses button to launch second activity:
Intent i = new Intent(MainActivity.this, secondactivity.class);
startActivityForResult(i, 1);
The array which is bundled back after pressing a button on the second activity:
Intent intent= getIntent();
Bundle b = new Bundle();
b.putParcelableArrayList("myarraylist", mylist);
intent.putExtras(b);
setResult(RESULT_OK, intent);
finish();
And finally a listener on the main activity (although I'm not sure of 100% when this code launches...)
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode==RESULT_OK && requestCode==1){
Bundle extras = data.getExtras();
final ArrayList<MyObject> mylist = extras.getParcelableArrayList("myarraylist");
Toast.makeText(MainActivity.this, mylist.get(0).getName(), Toast.LENGTH_SHORT).show();
}
}
Any ideas where I am going wrong? The onActivityResult() seems to be crashing my application.
EDIT: Class with parcelable methods:
import android.os.Parcel;
import android.os.Parcelable;
public class Plan implements Parcelable{
private String name;
private String id;
public Plan(){
}
public Plan createFromParcel(Parcel in) {
Plan plan = new Plan();
plan.setId(in.readString());
plan.setName(in.readString());
return plan;
}
public Plan(String name, String id){
this.name = name;
this.id = id;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public String getId(){
return id;
}
public void setId(String id){
this.id = id;
}
public String toString(){
return "Plan ID: " + id + " Plan Name: " + name;
}
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(name);
}
public static final Parcelable.Creator<Plan> CREATOR
= new Parcelable.Creator<Plan>() {
public Plan createFromParcel(Parcel in) {
return new Plan();
}
#Override
public Plan[] newArray(int size) {
// TODO Auto-generated method stub
return new Plan[size];
}
};
}
After the second activity finished, onactivityresult is called, but nothing displays inside the toast, its blank. any ideas? I'm guessing my class is still messed up...
EDIT: got it to work
I had the method that Peter supplied in the wrong place. It should be inside creator, like this:
public static final Parcelable.Creator<Plan> CREATOR
= new Parcelable.Creator<Plan>() {
public Plan createFromParcel(Parcel in) {
Plan plan = new Plan();
plan.setId(in.readString());
plan.setName(in.readString());
return plan;
}
and not out on its own.
Many thanks to Peter! Hope this helps someone else.
Your class MyObject must implement Parcelable in order to be serialized/deserialized by Android when put inside Bundle.
Update:
The method name is createFromParcel. And actually you have to create your object Plan from data in the parcel:
public Plan createFromParcel(Parcel in) {
Plan plan = new Plan();
plan.setId(in.readString());
plan.setName(in.readString());
return plan;
}