EXTRA with parcelable comes out NULL but without its fine - android

I am getting a bit frustrated with an issue that I cannot seem to fully understand.
I have a listview with items and when I click them I want to pass an object (Parcelable) to a new activity. This is the code below:
lv_Entries.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent getItchesScreen = new Intent(Home.this, Itches.class);
getItchesScreen.putExtra("i", 3);
Entry e = entries.get(position);
getItchesScreen.putExtra("entry", e);
startActivity(getItchesScreen);
}
});
Now, I have the "i" extra there for debugging purposes. I was just sending "entry" and when I got the intent on the activity it didn't work. Code below:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_itches);
tv_date = (TextView) findViewById(R.id.tv_date);
Bundle b = getIntent().getExtras();
entry = b.getParcelable("entry");
tv_date.setText(entry.getDate());
itches = entry.getItches();
itchesAdapter = new ItchAdapter(this, itches);
ListView lv_Itches = (ListView) findViewById(R.id.lv_itches);
lv_Itches.setAdapter(itchesAdapter);
}
So when I read my bundle there is nothing at all. No "entry" key and no "i" key (I debugged to read i using watch feature)
BUT! If I don't send "entry" and only send "i" and I debug to catch "i" I do get it!
I have no idea why sending entry is ruining things but I cannot find any answer. I debugged the object and it does find it though .get(position).
Hope anyone can give me any ideas, and sorry for any trouble.
EDIT
Below is the code for Entry:
public class Entry implements Parcelable{
private String date;
private ArrayList<Itch> itches;
public Entry(String date){
this.date = date;
itches = new ArrayList<Itch>();
}
// PARCELABLE
public Entry(Parcel source){
date = source.readString();
source.readTypedList(itches, Itch.CREATOR);
}
public void AddItch(Itch itch){
itches.add(itch);
}
// get intensity average for the itches
public int IntensityAverage(){
int intensity = 0;
for(Itch i : itches){
intensity += i.getIntensity();
}
return intensity/itches.size();
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public ArrayList<Itch> getItches() {
return itches;
}
public void setItches(ArrayList<Itch> itches) {
this.itches = itches;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(date);
dest.writeTypedList(itches);
}
public static final Parcelable.Creator<Entry> CREATOR =
new Parcelable.Creator<Entry>() {
public Entry createFromParcel(Parcel source) {
return new Entry(source);
}
public Entry[] newArray(int size) {
return new Entry[size];
}
};
}
Itch class is also Parceable. I am populating correctly (no crashes on Android at least) the ListView with it.
For convenience I place the code here aswell:
public class Itch implements Parcelable{
private String time;
private String local;
private int intensity;
public Itch(String time, String local, int intensity){
this.time = time;
this.local = local;
this.intensity = intensity;
}
// PARCELABLE
public Itch(Parcel source){
time = source.readString();
local = source.readString();
intensity = source.readInt();
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getLocal() {
return local;
}
public void setLocal(String local) {
this.local = local;
}
public int getIntensity() {
return intensity;
}
public void setIntensity(int intensity) {
this.intensity = intensity;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(time);
dest.writeString(local);
dest.writeInt(intensity);
}
public static final Parcelable.Creator<Itch> CREATOR =
new Parcelable.Creator<Itch>() {
public Itch createFromParcel(Parcel source) {
return new Itch(source);
}
public Itch[] newArray(int size) {
return new Itch[size];
}
};
}

Alright so... What was the problem? Simple.
The reason why the parcelable always came out null was because a stupid error was occurring. Which error?
Well, okay so take a look at this piece of code:
entry = b.getParcelable("entry");
What is it saying? It is saying that entry will be equal to the parcelable "entry" key. But what does that really mean? Look at entry constructor.
// PARCELABLE
public Entry(Parcel source){
date = source.readString();
source.readTypedList(itches, Itch.CREATOR);
}
So when you say that entry is equals to a parcelable, then you will call this constructor in the Entry class that I have posted. But why is it wrong you might ask?
Well, so take a look. We're giving ArrayList itches to the method readTypeList. but... wait a second. If that is a constructor that means that we're building from 0... So... is itches initiated? No it is not! Because I was only initiating itches in the "normal" constructor!
public Entry(String date){
this.date = date;
itches = new ArrayList<Itch>();
}
So the solution is...
// PARCELABLE
public Entry(Parcel source){
date = source.readString();
//add this if condition!
if (itches == null) {
itches = new ArrayList<Itch>();
}
source.readTypedList(itches, Itch.CREATOR);
}
And thats it. That fixes our problem! :)
If other error occurs please be aware:
Make SURE that your key is correct. So check out for any typos in your getting extras.
entry = b.getParcelable("entyr");
as instead of
entry = b.getParcelable("entry");
And any other type of error like that.
That is not a good practive, you should have a variable that has the "entry" written on it so you never have this type of error mistakes. I have it in my code because I am fast-programming to build up a prototype :)
Happy coding!

have you tried doing this in onCreate()
Intent i = getIntent();
if(i.hasExtra("entry")){
entry = i.getParcelableExtra("entry");
}else{
Log.v("EXTRAS", "entry not found");
}

Related

android parcelable loss object

I have problems with reaching parcelable between activities. When I inspect the object before sending it to another activity it looks fine, but after receiving it I can only see a strange id and the rest of the fields is nulled. Why does it happen? Maybe the way I do it is wrong? It would be best, you will take a look at the code parts:
This is the parcelable object:
#Data
#NoArgsConstructor
public class Scene implements Parcelable
{
private Long id;
private String name;
private Light light;
private Track effect;
private Track music;
private Track ambience;
protected Scene(Parcel in)
{
if (in.readByte() == 0) { id = null; } else { id = in.readLong(); }
name = in.readString();
}
public static final Creator<Scene> CREATOR = new Creator<Scene>()
{
#Override
public Scene createFromParcel(Parcel in)
{
return new Scene(in);
}
#Override
public Scene[] newArray(int size)
{
return new Scene[size];
}
};
#Override
public int describeContents()
{
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags)
{
Map<String, Track> audio = new HashMap<>();
audio.put(Tags.EFFECT.value(), effect);
audio.put(Tags.MUSIC.value(), music);
audio.put(Tags.AMBIENCE.value(), ambience);
dest.writeLong(id);
dest.writeString(name);
dest.writeMap(audio);
}
}
The scene has a map containing audio files. They are serializable (or should it be better also parcelable?) Nothing complicated, simple POJO:
#Data
public class Track implements Serializable
{
private Long id;
private String name;
private String path;
private Long duration;
private String artist;
private String tag;
}
And finally how I get the object:
public class AudioPlayer extends Service
[...]
public int onStartCommand(Intent intent, int flags, int startId)
{
Scene scene = intent.getParcelableExtra("scene");
[...]
}
}
When I inspect the object by intent.setParcelableExtra(), I get this:
Scene(id=7, name=test, light=null, effect=Track(id=10, name=file.mp3, path=/some/path/file.mp3, duration=13662, artist=null, tag=effect), music=Track(id=11, name=other_file.mp3, path=/some/other/path/other_file.mp3, duration=189492, artist=null, tag=music), ambience=Track(id=12, name=another_other_file.mp3, path=/some/another/other/path/another_other_file.mp3, duration=10109, artist=null, tag=ambience))
When I inspect the object by intent.getParcelableExtra(), I get this:
Bundle[{scene=Scene(id=17179869184, name=null, light=null, effect=null, music=null, ambience=null)}]
I tried also make the Object Track parcelable but the effect was the same.
Please help me solve this issue. I donĀ“t understeand what goes wrong.
When implementing Parcelable, you must guarantee that everything you "write" is exactly matched by a corresponding "read" call. Let's look at your code:
#Override
public void writeToParcel(Parcel dest, int flags)
{
Map<String, Track> audio = new HashMap<>();
audio.put(Tags.EFFECT.value(), effect);
audio.put(Tags.MUSIC.value(), music);
audio.put(Tags.AMBIENCE.value(), ambience);
dest.writeLong(id);
dest.writeString(name);
dest.writeMap(audio);
}
protected Scene(Parcel in)
{
if (in.readByte() == 0) { id = null; } else { id = in.readLong(); }
name = in.readString();
}
Here you are writing a long, then a string, and then a map. But you are reading a byte, then conditionally a long, and then a string. You never read the map back out, and you also never write your light value.
These issues will need to be addressed. Here's what that might look like:
#Override
public void writeToParcel(Parcel dest, int flags)
{
if (id != null) {
dest.writeInt(1);
dest.writeLong(id);
} else {
dest.writeInt(0);
}
dest.writeString(name);
dest.writeSerializable(light);
dest.writeSerializable(effect);
dest.writeSerializable(music);
dest.writeSerializable(ambience);
}
protected Scene(Parcel in)
{
if (in.readInt() == 1) {
this.id = in.readLong();
} else {
this.id = null;
}
this.name = in.readString();
this.light = (Light) in.readSerializable();
this.effect = (Track) in.readSerializable();
this.music = (Track) in.readSerializable();
this.ambience = (Track) in.readSerializable();
}

How use object in multiple classes?

Im fighting with this some time and still don't know how to make it work. So i have class Player with constructor
Player(String playerName, double playerCash)
{
this.playerName = playerName;
this.playerCash = playerCash;
}
In MainActivity i make a player object
Player player = new Player("player", 100);
And now in TextView in SecondActivity i would like to use
playerCash = (TextView) findViewById(R.id.playerCash);
playerCash.setText(player.getPlayerCash());
Can someone explain me how i can make it works? I get cannot resolve symbol player. Thanks in advance
You can implement Parcelable interface for Player class and then pass instance of it from the MainActivity through Intent to the SecondActivity.
I am unsure if what you have posted is your entire class, or if you obviated a part of it. I will write this answer, assuming that is your entire class.
So, here is the deal: you need to create methods in your class for you to get and set data to/from it.
public class Player() implements Parcelable {
private String playerName;
private String playerCash;
public Player(String playerName, String playerCash) {
this.playerName = playerName;
this.playerCash = playerCash;
}
public String getPlayerName() {
return playerName;
}
public void setPlayerName(String playerName) {
this.playerName = playerName;
}
public String getPlayerCash() {
return playerCash;
}
public void setPlayerCash(String playerCash) {
this.playerCash = playerCash;
}
public Player(Parcel in) {
String[] data = new String[2];
in.readStringArray(data);
this.playerData = data[0];
this.playerCash = data[1];
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringArray(new String[] {this.playerName,
this.playerCash});
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public Player createFromParcel(Parcel in) {
return new Player(in);
}
public Player[] newArray(int size) {
return new Player[size];
}
};
}
edit
I didn't read the part where you say you want to share it between Activities. I only noticed it because someone mentioned implementing Parcelable, which does help your problem.
Anyway, I edited my code to implement it.
To share data between Activities you will also need an intent, and there you can share the data stored on your Player class:
Intent i = new Intent();
i.putExtra("player", new Player("Jhon", "Over 9000!");
And in your 2nd Activity, to get it you would do:
Bundle b = getIntent().getExtras();
Player player = b.getParcelable("player");
Hope that helps.

Passing an object from one android activity to another

I have a class that I'm using for parsing data from a csv file (called CSVReader), inside of that there is some methods for the parsing as well as a couple of strings and a list that is of a custom object type (List allRecords).
What I'm doing is when the app loads, parsing all the data into that list and then trying to pass that information along to the next activity but inside the next activity I keep getting allRecords as being null.
LoginActivity
CSVReader data = new CSVReader();
data.populateRecords(this);
Intent intent = new Intent(LoginActivity.this, Find.class);
Bundle bundle = new Bundle();
bundle.putParcelable("list", data);
intent.putExtra("bundle", bundle);
startActivity(intent);
I've gone through the debugger and the bundle definitely has the data in there.
Find
Intent intent = getIntent();
Bundle bundle = intent.getBundleExtra("bundle");
data = (CSVReader) bundle.getParcelable("list");
Using the debugger still, and mMap (in the bundle) is now null and so is data.
Am I doing something wrong? Both classes DummyData and CSVReader implement Parcelable.
EDIT: Adding custom class CSVReader:
List<DummyData> allRecords;
private String base;
private String location;
private String partner;
public static Creator<CSVReader> CREATOR = new Creator<CSVReader>(){
#Override
public CSVReader createFromParcel(Parcel source){
return new CSVReader(source);
}
#Override
public CSVReader[] newArray(int size) {
return new CSVReader[size];
}
};
private CSVReader(Parcel in){
allRecords = new ArrayList<DummyData>();
in.readTypedList(allRecords, DummyData.CREATOR);
base = in.readString();
location = in.readString();
partner = in.readString();
}
...
...
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(base);
dest.writeString(location);
dest.writeString(partner);
dest.writeList(allRecords);
}
[EDIT]
I was looking over your code again, and noticed you're writing the List to the parcel LAST and reading the list from the parcel FIRST. You have to read items from the parcel in the order they are written. Try putting dest.writeList(allRecords) at the top of the method so it is the first item written, or you can put in.readList(allRecords, DummyData.class.getClassLoader()) at the bottom of the list in that method.
Give it a shot.
//////////////////////////////////////////////
From the docs,
public final void readTypedList (List<T> list, Creator<T> c)
Read into the given List items containing a particular object type
that were written with writeTypedList(List) at the current
dataPosition(). The list must have previously been written via
writeTypedList(List) with the same object type.
You're using writeList() to write the data to the parcel. Try using writeTypedList(). You could also try changing readTypedList() with readList() I believe. Something like:
in.readList(allRecords, CSVReader.class.getClassLoader());
Hope this helps.
If you plan to pass data to another activity, you need to use objects of classes that implement Parcelable. Here is an example,
package com.weather.model;
import java.util.ArrayList;
import java.util.List;
import android.os.Parcel;
import android.os.Parcelable;
public class Forcast implements Parcelable {
private String id;
private String code;
private String message;
private City city;
private String count;
private List<Weather> weatherList = new ArrayList<Weather>();
public Forcast(){
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public City getCity() {
return city;
}
public void setCity(City city) {
this.city = city;
}
public String getCount() {
return count;
}
public void setCount(String count) {
this.count = count;
}
public List<Weather> getWeatherList() {
return weatherList;
}
public void setWeatherList(List<Weather> weather) {
this.weatherList = weather;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(code);
dest.writeString(message);
dest.writeParcelable(city, flags);
dest.writeString(count);
dest.writeList(weatherList);
}
public static final Parcelable.Creator<Forcast> CREATOR = new Parcelable.Creator<Forcast>() {
#Override
public Forcast createFromParcel(Parcel source) {
return new Forcast(source);
}
#Override
public Forcast[] newArray(int size) {
return new Forcast[size];
}
};
protected Forcast(Parcel in){
id = in.readString();
code = in.readString();
message = in.readString();
city = (City)in.readParcelable(City.class.getClassLoader());
count = in.readString();
in.readList(weatherList, Weather.class.getClassLoader());
}
}
I included City model so you can see how it goes for an object in comparison to list of objects. Assume you have a Forcast instance with all the values as 'forcast' ( Forcast forcast = new Forcast() or something similar)
Intent intent = new Intent(this, SomeActivity.class);
intent.putExtra(com.weather.model,forcast)
startActivity(intent)
I hope that helps
You need to put bundle object by using putExtras method. Then you can get the bundle by using getIntent().getExtras().
Intent intent = new Intent(LoginActivity.this, Find.class);
Bundle bundle = new Bundle();
bundle.putParcelable("list", data);
intent.putExtras( bundle);
startActivity(intent);
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
data = (CSVReader) bundle.getParcelable("list");

How to pass a Parcelable Extra to another activity

I'm trying to pass a Parceble Extra to another activity using this example, but when I try get it on my second activity NullPointerExeception shows up, could somebody help me?
My Parcelable class:
public class MetaDados implements Parcelable {
private int codigoInstituicao;
// . . .
public MetaDados(int codigoInstituicao, int ano, String offlineUuid, String sigla, String nameInst,
String startedDate, String name, String finishedDate, long size) {
this.codigoInstituicao = codigoInstituicao;
// . . .
}
public int getCodigoInstituicao() {
return codigoInstituicao;
}
public void setCodigoInstituicao(int codigoInstituicao) {
this.codigoInstituicao = codigoInstituicao;
}
//getters and setters . . .
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(codigoInstituicao);
// . . .
}
public static final Parcelable.Creator<MetaDados> CREATOR = new Parcelable.Creator<MetaDados>() {
public MetaDados createFromParcel(Parcel in) {
return new MetaDados(in);
}
public MetaDados[] newArray(int size) {
return new MetaDados[size];
}
};
private MetaDados(Parcel in) {
codigoInstituicao = in.readInt();
//. . .
}
}
My AsynkTask how start my other activity:
ArrayList<MetaDados> metaDadosFull = new ArrayList<MetaDados>();
ArrayList<MetaDados> metaDadosPres = new ArrayList<MetaDados>();
Intent it = new Intent(activity, DownloadSelectionActivity.class);
it.putExtra("metaDadosFull", metaDadosFull);
it.putExtra("metaDadosPres", metaDadosPres);
activity.startActivity(it);
And my DownloadSelectionActivity where I try to get it:
ArrayList<MetaDados> fullList = (ArrayList<MetaDados>) getIntent().getParcelableExtra("metaDadosFull");
for (MetaDados metaDados : fullList) {
Log.d(Constants.DOWNLOAD_SELECTED_ACTIVITY, metaDados.getName());
}
ArrayList<MetaDados> presList = (ArrayList<MetaDados>) getIntent().getParcelableExtra("metaDadosPres");
for (MetaDados metaDados : presList) {
Log.d(Constants.DOWNLOAD_SELECTED_ACTIVITY, metaDados.getName());
}
Use Intent.putParcelableArrayListExtra() instead of putExtra(), and getParcelableArrayListExtra() instead of getParcelableExtra(). You can lose the casts as well, that may be where it's blowing up.

How to Pass Custom Arraylist content from one Activity to another Activity in android

i have an objects in an custom arraylist as "finaljsoncontent", and now i am trying to pass this "finaljsoncontent" array to another Activity, and i have also tried getters and setters, and also bundle, but i cant, help me how to do this.
Thanks in advance.
Check this out: How do I pass an object from one activity to another on Android?
Your class "JSonKey" should implement parcealable or serializable so that Android can "send" it from an activity to the other activity.
You could try implementing Parcelable, then you can pass it in a bundle. You will need to reduce your object to mostly primitive types to do this. Otherwise you can extend the Application class and store it there. You would retrieve that using the call to getApplicationContext(). Or, of course, you could always create some sort of static globals class that all of your classes can reference.
Here is one of my implementations of parcelable..
package warrior.mail.namespace;
import android.os.Parcel;
import android.os.Parcelable;
public class JView implements Parcelable {
public String subject;
public String from;
public boolean unread;
public String body;
public int inboxIndex;
private long id;
public static final Parcelable.Creator<JView> CREATOR = new Parcelable.Creator<JView>() {
public JView createFromParcel(Parcel in) {
return new JView(in);
}
public JView[] newArray(int size) {
return new JView[size];
}
};
public JView(){
body = "";
}
public JView(String subject,String from,boolean unread){
body = "";
this.subject = subject;
this.from = from;
this.unread = unread;
}
public JView(Parcel parcel){
subject = parcel.readString();
from = parcel.readString();
body = parcel.readString();
unread = parcel.createBooleanArray()[0];
inboxIndex = parcel.readInt();
}
#Override
public int describeContents() {
return inboxIndex;
}
#Override
public void writeToParcel(Parcel out, int arg1) {
out.writeString(subject);
out.writeString(from);
out.writeString(body);
boolean[] array = new boolean[] {unread};
out.writeBooleanArray(array);
out.writeInt(inboxIndex);
}
public void setIndex(int index){
inboxIndex = index;
}
public void setUnread(boolean arg){
unread = arg;
}
public void setContent(String content){
body = content;
}
public void setSubject(String subject){
this.subject = subject;
}
public void setFrom(String f){
from = f;
}
public void setId(long arg){
id = arg;
}
public long getId(){
return id;
}
public void updateIndex(){
}
}
You can either make your class Parcelable(android specific) or make it serializable like in java(just write implements Serializable with your class)

Categories

Resources