NullPointerException when I try to read a Vector passed through Intent - java

I'm trying to use Parcelable classes to give a Stack from an activity to another. In order to do this I defined MyStack and MyVector3 in the following way. This is then included in a Model class.
Model class
public class Model implements Parcelable{
public List<MyStack> surfaces;
public Info info;
public Model (){}
public Model(List<MyStack> surf){
surfaces = surf;
}
public void setInfo(Info i){
info=i;
}
public Info getInfo(){
return info;
}
public List<MyStack> getSurfaces(){
return this.surfaces;
}
public int numSurfaces(){
return surfaces.size();
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeTypedList(surfaces);
//Parcelable infoP = ((Parcelable) info);
//out.writeParcelable(infoP, 0);
}
public static final Parcelable.Creator<Model> CREATOR
= new Parcelable.Creator<Model>() {
public Model createFromParcel(Parcel in) {
return new Model(in);
}
public Model[] newArray(int size) {
return new Model[size];
}
};
private Model(Parcel in) {
surfaces = new ArrayList<MyStack>();
in.readTypedList(surfaces, MyStack.CREATOR);
//info = in.readParcelable(Info.class.getClassLoader());
}
public class Info{
String title;
String descr;
public Info(String t, String d){
title=t;
descr=d;
}
public Info(String t){
title=t;
}
public void setDescr(String d){
descr=d;
}
}
}
MyStack class
public class MyStack implements Parcelable {
public Stack<MyVector3> stack;
public MyStack(MyStack ms){
this.stack=ms.stack;
}
public MyStack(Stack s){
stack= s;
}
public Stack getStack(){
return this.stack;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeTypedList(stack);
}
public static final Parcelable.Creator<MyStack> CREATOR
= new Parcelable.Creator<MyStack>() {
public MyStack createFromParcel(Parcel in) {
return new MyStack(in);
}
public MyStack[] newArray(int size) {
return new MyStack[size];
}
};
private MyStack(Parcel in) {
stack= new Stack<MyVector3>();
in.readTypedList(stack, MyVector3.CREATOR);
}
}
MyVector3 class
public class MyVector3 extends Vector3 implements Parcelable {
public Vector3 vector;
public MyVector3(Vector3 v){
vector=v;
}
public MyVector3(double x, double y, double z){
vector= new Vector3(x,y,z);
}
public Vector3 getVector(){
return this.vector;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeDoubleArray(new double[]{
this.x,
this.y,
this.z});
}
public static final Parcelable.Creator<MyVector3> CREATOR
= new Parcelable.Creator<MyVector3>() {
public MyVector3 createFromParcel(Parcel in) {
return new MyVector3(in);
}
public MyVector3[] newArray(int size) {
return new MyVector3[size];
}
};
private MyVector3(Parcel in) {
double[] data = new double[3];
in.readDoubleArray(data);
this.x= data[0];
this.y= data[1];
this.z= data[2];
}
}
This is the intent creation, where the model is well populated and I get all values correctly from Logs
Model model= new Model(surfaces);
Intent intent = new Intent(this, EditorPresenter.class);
intent.putExtra("model", model);
startActivity(intent);
And where I use it
Intent intent = getIntent();
model= intent.getParcelableExtra("model");
MyStack[] sf = model.surfaces.toArray(new MyStack[model.numSurfaces()]);
//surf = new Stack();
surf = new Stack[model.numSurfaces()];
Log.i(TAG, "ss="+Integer.toString(sf.length)); //expected value
for(int s=0; s<sf.length; s++) {
Log.i(TAG, "s="+Integer.toString(s)); //expected value
Stack st= new Stack();
Log.i(TAG, "vv="+Integer.toString(sf[s].getStack().size())); //expected value
for(int v=0; v<sf[s].getStack().size(); v++) {
Log.i(TAG, "v="+Integer.toString(v) +sf[s].stack.elementAt(v).getVector().toString()); //NullPointerException
MyVector3 mv = (MyVector3) sf[s].stack.elementAt(v);
if(mv!=null) st.add(mv.getVector());
}
surf[s]=st;
}
But I get a NullPointerException anytime I try to read/write a Vector3 value.
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String org.rajawali3d.math.vector.Vector3.toString()' on a null object reference
The problem is probably in Parcelable classes, til I get a wrong model back from the intent (number of faces and vertices expected are right, vector values are probably null). Any help is really appreciated.

you are not instantiating your Vector object, after reading from parcelable. Change
private MyVector3(Parcel in) {
double[] data = new double[3];
in.readDoubleArray(data);
this.x= data[0];
this.y= data[1];
this.z= data[2];
}
with
private MyVector3(Parcel in) {
double[] data = new double[3];
in.readDoubleArray(data);
this.x= data[0];
this.y= data[1];
this.z= data[2];
vector = new Vector3(x,y,z);
}

You can generate Parcelable classes from your code using this tool http://www.parcelabler.com/ and try again with new generated classes.

Related

How do I iterate through an ArrayList of custom objects from Intent and add them into LinearLayout?

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

How to move data with an Android Parcelable?

I'm making a game, and I need to move a custom Object. To do that, I'm using a Parcelable to move data.
However, I'm having problems moving the data, and I don't know why.
This is Parcelable class:
public class Character implements Parcelable {
public static int day;
public static int now_food;
public static int now_water;
public static int use_food;
public static int use_water;
public static int health;
public static String name;
public static char status; // d = 병걸림, n = 정상
public static char status_live; //w = 죽음 l = 생존
public static String status_water ; // t = 목마름 v = 매우 목마름
public static String status_food ; // h = 배고픔 v = 매우 배고픔
public Character() {
}
public Character(Parcel in) {
}
public Character(int use_food, int use_water, int health, String name, char status) {
this.status = status;
this.use_food = use_food;
this.use_water = use_water;
this.health = health;
this.name = name;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(use_food);
dest.writeInt(use_water);
dest.writeInt(health);
dest.writeString(name);
}
public void readFromParcel(Parcel in) {
use_food = in.readInt();
use_water = in.readInt();
health = in.readInt();
name = in.readString();
}
public static final Creator<Character> CREATOR = new Creator<Character>() {
#Override
public Character createFromParcel(Parcel in) {
return new Character(in);
}
#Override
public Character[] newArray(int size) {
return new Character[size];
}
};
#Override
public int describeContents() {
return 0;
}
}
Here's my main code:
character1.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), Character1_Activity.class);
intent.putExtra("ch1info", ch1);
startActivity(intent);
}
});
I move this object with button's click event.
Finally, this is the Activity that wants to get object.
Bundle bundle = getIntent().getExtras();
final Character ch1 = bundle.getParcelable("ch1info");
TextView get_water = (TextView) findViewById(R.id.water_stat);
get_water.setText(ch1.Check_water(ch1));
Why doesn't my code work, and how can I fix it?
you need to move your code inside readFromParcel to public Character(Parcel in)
you can simply delete readFromParcel method, its useless.
updated constructor would be will be:
public Character(Parcel in){
use_food = in.readInt();
use_water = in.readInt();
health = in.readInt();
name = in.readString();
}
Update your Character class as below:
public class Character implements Parcelable {
public static int day;
public static int now_food;
public static int now_water;
public static int use_food;
public static int use_water;
public static int health;
public static String name;
public static char status; // d = 병걸림, n = 정상
public static char status_live; //w = 죽음 l = 생존
public static String status_water ; // t = 목마름 v = 매우 목마름
public static String status_food ; // h = 배고픔 v = 매우 배고픔
public Character() {
}
public Character(int use_food, int use_water, int health, String name, char status) {
this.status = status;
this.use_food = use_food;
this.use_water = use_water;
this.health = health;
this.name = name;
}
public Character(Parcel in) {
this.use_food = in.readInt();
this.use_water = in.readInt();
this.health = in.readInt();
this.name = in.readString();
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(use_food);
dest.writeInt(use_water);
dest.writeInt(health);
dest.writeString(name);
}
public static final Parcelable.Creator<Character> CREATOR = new Parcelable.Creator<Character>() {
#Override
public Character createFromParcel(Parcel in) {
return new Character(in);
}
#Override
public Character[] newArray(int size) {
return new Character[size];
}
};
#Override
public int describeContents() {
return 0;
}
}
Send Character object:
character1.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(View v) {
// Object
Character ch1 = new Character(27,32,65,"name",'n');
Intent intent = new Intent(getActivity(), Character1_Activity.class);
intent.putExtra("ch1info", ch1);
startActivity(intent);
}
});
Retrieve Character object in your Character1_Activity.java:
Bundle bundle = getIntent().getExtras();
final Character ch1 = bundle.getParcelable("ch1info");
Log.d("Success", "Use water: " + ch1.use_water + "\nUse food:" + ch1.use_food
+ "\nHealth: " + ch1.health + "\nName: " + ch1.name + "\nStatus: " + ch1.status);
OUTPUT:
D/Success: Use water: 32
Use food:27
Health: 65
Name: name
Status: n
Hope this will help~

Android: putExtra parcelable stops activity launching. No error

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

Android: Parcelable with inheritance

Now, I have three class, the base class is BaseWidget which implements Parcelable, two subclasses are SelectWidget and TextWidget. Then, I use a class named WidgetInfo (also implements Parcelable) to keep a list of BaseWidget or SelectWidget or TextWidget objects.
While I put WidgetInfo object into an Intent to start TestActivity, and I received WidgetInfo in TestActivity ,but all the elements of list (which in WidgetInfo) convert to BaseWidget object. And subclass object member variable is lost. What is problem???
BaseWidget.java:
public class BaseWidget implements Parcelable{
private String name;
public BaseWidget() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
protected BaseWidget(Parcel in) {
this.name = in.readString();
}
public static final Creator<BaseWidget> CREATOR = new Creator<BaseWidget>() {
#Override
public BaseWidget createFromParcel(Parcel in) {
return new BaseWidget(in);
}
#Override
public BaseWidget[] newArray(int size) {
return new BaseWidget[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
}
}
TextWidget.java:
public class TextWidget extends BaseWidget{
private String width = "100";
public TextWidget() {
}
public String getWidth() {
return width;
}
public void setWidth(String width) {
this.width = width;
}
protected TextWidget(Parcel in) {
super(in);
width = in.readString();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(width);
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<TextWidget> CREATOR = new Creator<TextWidget>() {
#Override
public TextWidget createFromParcel(Parcel in) {
return new TextWidget(in);
}
#Override
public TextWidget[] newArray(int size) {
return new TextWidget[size];
}
};
}
SelectWidget.java:
public class SelectWidget extends BaseWidget{
private int height = 200;
public SelectWidget() {
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
protected SelectWidget(Parcel in) {
super(in);
height = in.readInt();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(height);
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<SelectWidget> CREATOR = new Creator<SelectWidget>() {
#Override
public SelectWidget createFromParcel(Parcel in) {
return new SelectWidget(in);
}
#Override
public SelectWidget[] newArray(int size) {
return new SelectWidget[size];
}
};
}
WidgetInfo.java:
public class WidgetInfo implements Parcelable{
private List<BaseWidget> widgetList;
public WidgetInfo() {
}
public List<BaseWidget> getWidgetList() {
return widgetList;
}
public void setWidgetList(List<BaseWidget> widgetList) {
this.widgetList = widgetList;
}
protected WidgetInfo(Parcel in) {
widgetList = in.createTypedArrayList(BaseWidget.CREATOR);
}
public static final Creator<WidgetInfo> CREATOR = new Creator<WidgetInfo>() {
#Override
public WidgetInfo createFromParcel(Parcel in) {
return new WidgetInfo(in);
}
#Override
public WidgetInfo[] newArray(int size) {
return new WidgetInfo[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedList(widgetList);
}
}
start Intent:
WidgetInfo info = new WidgetInfo();
BaseWidget widget1 = new BaseWidget();
BaseWidget widget2 = new TextWidget();
BaseWidget widget3 = new SelectWidget();
List<BaseWidget> list = new ArrayList<>();
list.add(widget1);
list.add(widget2);
list.add(widget3);
info.setWidgetList(list);
Intent intent = new Intent(this, TestActivity.class);
intent.putExtra("widgetInfo", info);
startActivity(intent);

Android - MyParceableClassInner[] inside MyParceableClassOuter

I'm trying to pass a custom parceable class which contains an array of another custom parceable class between activities. I tried to follow the advice here, but it didn't work for me.
This is the inner class, it works fine when passed alone:
import android.os.Parcel;
import android.os.Parcelable;
public class EntryImage implements Parcelable {
public int imageId;
public int entryid_id;
public String url;
public int height;
public EntryImage(int imageId, int entryid_id, String url, int height) {
this.imageId = imageId;
this.entryid_id = entryid_id;
this.url = url;
this.height = height;
}
public EntryImage(Parcel in) {
readFromParcel(in);
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(imageId);
parcel.writeInt(entryid_id);
parcel.writeString(url);
parcel.writeInt(height);
}
private void readFromParcel(Parcel in) {
imageId = in.readInt();
entryid_id = in.readInt();
url = in.readString();
height = in.readInt();
}
public static final Parcelable.Creator<EntryImage> CREATOR = new Parcelable.Creator<EntryImage>() {
public EntryImage createFromParcel(Parcel in) {
return new EntryImage(in);
}
public EntryImage[] newArray(int size) {
return new EntryImage[size];
}
};
}
And this is the outer class. The problem is in the last few lines of readFrom and writeToParcel:
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Arrays;
public class Entry implements Parcelable {
public int entryId;
public String name;
public EntryImage[] images;
public Entry(int entryId, String name, EntryImage[] images) {
this.entryId = entryId;
this.name = name;
this.images = images;
}
public Entry(Parcel in) {
readFromParcel(in);
}
public EntryImage getEntryImage (int asdf) {
return images[asdf];
}
#Override
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(entryId);
parcel.writeString(name);
parcel.writeParcelableArray(images, flags);
}
private void readFromParcel(Parcel in) {
entryId = in.readInt();
name = in.readString();
//images = in.readTypedArray(EntryImage[].class.getClassLoader());
Parcelable[] parcelableArray = in.readParcelableArray(EntryImage.class.getClassLoader());
EntryImage[] images = null;
if (parcelableArray != null) {
images = Arrays.copyOf(parcelableArray, parcelableArray.length, EntryImage[].class);
}
}
public static final Parcelable.Creator<Entry> CREATOR = new Parcelable.Creator<Entry>() {
public Entry createFromParcel(Parcel in) {
return new Entry(in);
}
public Entry[] newArray(int size) {
return new Entry[size];
}
};
}
The line in Entry.readFromParcel
EntryImage[] images = null;
should instead be
images = null;

Categories