Save custom objects when activty stops on Android - android

I've written a small andorid app. This app uses a vector of custom objects and displays them in a listview. I want to save those objects when the activity is send to background. What is the best way for this. In the vector are about 25 objects. Every object has a boolean, two long, and two strings.
Thanks for your help

do you need them saved when the app shuts down or just when the activity goes into the background?
if your objects are parcelables you could use the save and restore instance state methods:
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList("objectsArray", myObjects); // if its an array of parceleble objects
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
myObjects= savedInstanceState.getParcelableArrayList("objectsArray");
}
here is an example of a parcelable object
public class KNUserSketch implements Parcelable{
public int id;
public int user;
public String url;
public int views;
public int locations;
public KNUserSketch(JSONObject obj)
{
id = KNSafeJSonUtilties.safeGetInteger(obj, "id");
user = KNSafeJSonUtilties.safeGetInteger(obj, "user");
views = KNSafeJSonUtilties.safeGetInteger(obj, "views");
locations = KNSafeJSonUtilties.safeGetInteger(obj, "locations");
url = KNSafeJSonUtilties.safeGetString(obj, "url");
Log.v("JSON","jsonObject: "+obj.toString());
url.replace("https:", "http:");
}
public KNUserSketch(){
id=-1;
user=-1;
views = 0;
url ="";
}
public KNUserSketch(Parcel p){
id= p.readInt();
user = p.readInt();
url = p.readString();
views = p.readInt();
locations = p.readInt();
}
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeInt(id);
dest.writeInt(user);
dest.writeString(url);
dest.writeInt(views);
dest.writeInt(locations);
}
public static final Parcelable.Creator<KNUserSketch> CREATOR = new Creator<KNUserSketch>() {
public KNUserSketch createFromParcel(Parcel source) {
return new KNUserSketch(source);
}
public KNUserSketch[] newArray(int size) {
return new KNUserSketch[size];
}
};
}

You could use SharedPreferences to put the objets in a safe place, but objets will have to implement Parcelable protocol.

Related

EXTRA with parcelable comes out NULL but without its fine

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

Save 2d array of custom object onSaveInstanceState

Hi im trying to save a 2d array of a custom object in a Bundle inside the method onSaveInstanceState so it saves the array of custom objects when the users rotates the screen
but i dont know how to achieve it.. If possible id like an "easy" solution... Thanks
This is the class of the custom object, i tried to add the implements Parcelable & methods but not sure if that part is correct:
package com.example.game
import android.os.Parcel;
import android.os.Parcelable;
//hacemos el implements parcelable para que se puede guardar en el savedinstance
public class NumeroCarton implements Parcelable {
protected int numero;
protected boolean numacertado;
public NumeroCarton(int numero) {
this.numacertado =false;
this.numero = numero;
}
public int getNumero() {
return numero;
}
public void setNumero(int numero) {
this.numero = numero;
}
public boolean isNumacertado() {
return numacertado;
}
public void setNumacertado(boolean numacertado) {
this.numacertado = numacertado;
}
////parcelable :
private NumeroCarton(Parcel in) {
numero = in.readInt();
}
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(numero);
}
public static final Parcelable.Creator<NumeroCarton> CREATOR
= new Parcelable.Creator<NumeroCarton>() {
public NumeroCarton createFromParcel(Parcel in) {
return new NumeroCarton(in);
}
public NumeroCarton[] newArray(int size) {
return new NumeroCarton[size];
}
};
}
Ok, Inside the activity where i have the object i want to save, its micarton, a 2d array
of the class i wrote above :
NumeroCarton[][] micarton=new NumeroCarton[5][3];
And i want to save it inside the bundle of the onSaveInstanceState method:
public void onSaveInstanceState(Bundle outInstance) {
super.onSaveInstanceState(outInstance);
outInstance.putInt(STATE_PUNTOS, puntos);
//This is my problem:
outInstance.putParcelable(STATE_MICARTONN, micarton);
//The method putParcelable(String, Parcelable)
// in the type Bundle is not //applicable for the arguments
//(String, NumeroCarton[][])
//Neither outInstance.putParcelableArray[](STATE_MICARTONN, micarton)
}
I think if you make the custom class serializable it will work.
There is another easy solution, try to convert 2nd array into csv string like this:
data11,data12,data13
data21,data22,data23
....
in this format, you can easily convert 2nd array to a string and backwards

Android - Saving custom object - Shared Preferences or Database?

I'm creating a location based reminder application.
I've got a custom object called Reminder, which stores latitude, longitude, the location name and the subject of the reminder - Aswell as what profile it belongs to.
I'm then inputting the location name and sujbect into a ListView (Using cardlibs here too).
However now I need to save the data for when I close the application, and was wondering the best way to go about this - Do I store the entire 'Reminder' object or do I just store multiple pieces of data in Shared Preferences / A database.
This is my code - It's very inefficient/Ugly:
Reminder:
public class Reminder implements Parcelable {
public double latitude;
public double longitude;
public String subject;
public String locationName;
public String profile;
public Reminder() {
}
public Reminder(Parcel in) {
String[] data = new String[5];
in.readStringArray(data);
this.subject = data[0];
this.locationName = data[1];
this.latitude = Double.parseDouble(data[2]);
this.longitude = Double.parseDouble(data[3]);
this.profile = data[4];
}
public String getProfile() {
return profile;
}
public double getLatitude() {
return latitude;
}
public String getLocationName() {
return locationName;
}
public double getLongitude() {
return longitude;
}
public String getSubject() {
return subject;
}
public void setProfile(String profile) {
this.profile = profile;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public void setLocationName(String locationName) {
this.locationName = locationName;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public void setSubject(String subject) {
this.subject = subject;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringArray(new String[] { this.subject, this.locationName,
String.valueOf(this.latitude), String.valueOf(this.longitude), this.profile });
}
public static final Parcelable.Creator<Reminder> CREATOR = new Parcelable.Creator<Reminder>() {
public Reminder createFromParcel(Parcel source) {
// TODO Auto-generated method stub
return new Reminder(source); // using parcelable constructor
}
public Reminder[] newArray(int size) {
// TODO Auto-generated method stub
return new Reminder[size];
}
};
}
List using a fragment:
public class HomeFragment extends Fragment {
public static ArrayList<Card> cards = new ArrayList<Card>();
Reminder reminder;
public HomeFragment() {
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
reminder = getActivity().getIntent().getParcelableExtra("reminder");
Card card = new Card(getActivity());
CardHeader cardHeader = new CardHeader(getActivity());
if (reminder != null) {
cardHeader.setTitle(reminder.getSubject());
card.addCardHeader(cardHeader);
card.setTitle(reminder.getLocationName());
cards.add(card);
}
CardArrayAdapter mCardArrayAdapter = new CardArrayAdapter(
getActivity(), cards);
CardListView listView = (CardListView) getActivity().findViewById(
R.id.card_list);
mCardArrayAdapter.notifyDataSetChanged();
if (listView != null)
listView.setAdapter(mCardArrayAdapter);
}
Any criticism on how my code could of been wrote better would also be really beneficial, as I feel I'm being a huge rookie and missing something obvious which would make it more efficient.
Thanks!
Basically the choice to use shared preferences vs a database hinges on a number of things:
1) How many objects are we talking about? How complex are they?
2) Do you intend on searching/manipulating these objects or are you just saving/loading them.
3) Do you intend to export/move/send objects?
4) Do you want the objects to be recoverable across application contexts - that is beyond only the single app in question.
In your specific case I would use a database.
http://developer.android.com/guide/topics/data/data-storage.html#pref
As you can see in the docs here prefs isn't really intended for Object storage - it's for key value pairs. While you could store an object as a number of key value pairs in the shared prefs and reconstruct from there, you would have to go through some weird model conversions to do this for multiple objects. In short it doesn't really make sense.

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 do I send an array of objects from one Activity to another?

I have a class like:
Class persona implements Serializable {
int age;
String name;
}
And my first Activity fill an array:
persona[] p;
Then, I need this info in another Activity. How I can send it?
I try to make:
Bundle b = new Bundle();
b.putSerializable("persona", p);
But I Can't.
AFAIK the is no method that put a serializable array into bundle any way here is a solution to use that uses parcel
change you class to this
import android.os.Parcel;
import android.os.Parcelable;
public class persona implements Parcelable {
int age;
String name;
public static final Parcelable.Creator<persona> CREATOR = new Creator<persona>() {
#Override
public persona[] newArray(int size) {
// TODO Auto-generated method stub
return new persona[size];
}
#Override
public persona createFromParcel(Parcel source) {
// TODO Auto-generated method stub
return new persona(source);
}
};
public persona(Parcel in) {
super();
age = in.readInt();
name = in.readString();
}
public persona() {
super();
// TODO Auto-generated constructor stub
}
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(age);
dest.writeString(name);
}
}
then you can send the array like this
Bundle b = new Bundle();
b.putParcelableArray("persona", p);
btw using Parcelable instead of Serializable is more efficient in Android
You class will need to implement Parcelable. Then, you can send it in a bundle by using the Bundle.putParcelableArray()-method.
Also, a general advice: Class names should always start uppercase

Categories

Resources