I have an object with a View member. So i want to pass an ArrayList of this object and i need to pass this View. I know how to implement Parcelable.
The code is something like this :
public class Variable implements Parcelable {
public View mView;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(mView)
}
public static final Parcelable.Creator<Variable> CREATOR
= new Parcelable.Creator<Variable>() {
public Variable createFromParcel(Parcel in) {
return new Variable(in);
}
public Variable[] newArray(int size) {
return new Variable[size];
}
};
private Variable(Parcel in) {
mView= (View) in.readValue(getClass().getClassLoader());
}
So I tried object method for the writeToParcel and Variable(Parcel in) methods but obviously it didn't work.
How I should do this ?
You should only implement parcelable for data objects and never for Views, the idea is to parcel/unparcel the data state to re-instantiate a given View with state.
You should also note that there is a hard set limit on the size of the buffer that a transaction can hold when you parcel your data and send it via Intent. So ideally avoid having large in-memory object being transferred via parcel (one bad example is lets say Bitmaps)
Also, implementing parcelable by hand is pretty tedious and could be error prone. I recommend using Studio's plugin or any good third party plugin for implementing Parcelable.
Hope it helps
Related
I have a class model called "Car".
If I want to create a new object of "Car" I can do something like this:
Car car = new Car();
But now, I made this class implements Parcelable. What is the best way of creating a new object of the class "Car"?
Right now I am doing this way:
Car car = new Car("blue");
And I am adding a new constructor to my model Class:
public class Car implements Parcelable {
public String color;
#Override
public int describeContents() { return 0; }
#Override
public void writeToParcel(Parcel dest, int flags) { dest.writeString(color); }
public static final Creator<Car> CREATOR = new Creator<Car>() {
public Car createFromParcel(Parcel in) { return new Car(in); }
public Car[] newArray(int size) { return new Car[size]; }
};
private Car(Parcel in) { color = in.readString(); }
public Car(String myColor) { color = myColor; }
}
Since I am new to this class Parcelable I'm not sure if this is the best aproach. Is anything bad having two constructors in my class? Is there any other more efficient way to do this?
I am afraid that adding this second constructor my application should lose some performance in creating new objects of this class.
Since I am new to this class Parcelable I'm not sure if this is the best aproach. Is anything bad having two constructors in my class? Is there any other more efficient way to do this?
It depends what you need, but your implementation of parcelable patters seems to be okey.
If u need to pass efficiently your object throught intent or arguments bundle, it is best approach. Parcelable is android more efficient implementation of class serialization.
If you want little less optimal (but easier) you could use serializable, this is default java approch, it's a bit slower, and has its own drawbacks ^^.
And if more important for you is readability of generated state (parcelable and serializable will make a byte stream from your object), you might want to use Json convertion (and for that i would suggest gson.
I am afraid that adding this second constructor my application should lose some performance in creating new objects of this class.
There is nothing wrong with multiple constructors. They are simply, a way to initialize your object state. Nothing more nothing less.
PS: For your old method of creating a car to work:
Car car = new Car();
Simply add empty constructor:
public Car() { }
Cheers.
I was wondering lately, which one of the three methods of passing parameters to the method - presented below - are the best for you, your CPU, memory and why. I am considering methods which allow me to pass more arguments in future, without changing the method signature.
If you know something better, I am here to listen and learn.
Pass by methods
Params.java
public interface Params {
int getParamOne();
int getParamTwo();
}
Calling
obj.foo(new Params() {
#Override
public int getParamOne() {
return 1;
}
#Override
public int getParamOne() {
return 2;
}
});
Receiving
public void foo(Params p) {
int p1 = p.getParamOne();
int p2 = p.getParamTwo();
}
Pass by class fields
Params.java
public class Params {
private int paramOne;
private int paramTwo;
// Getters and setters here
}
Calling and receiving
No magic here, just create a new Params object, use setters, pass it to the method and use getters.
Pass by Properties class
Calling
properties.put("paramOne", 1);
properties.put("paramTwo", 2);
obj.foo(properties);
Receiving
public void foo(Properties properties) {
int a = (int) properties.get("paramOne");
int b = (int) properties.get("paramTwo");
}
I was pleased to show an real-life example of code, which actually needs passing varying types and number of properties. I'm using the third method - passing by the properties:
public interface DataProvider {
public String getContent(Properties properties);
}
public class HttpProvider implements DataProvider {
#Override
public String getContent(Properties properties) {
InputStream in = new URL(properties.get("URL")).openStream();
String content = IOUtils.toString(in);
IOUtils.closeQuietly(in);
return content;
}
public class FtpProvider implements DataProvider {
#Override
public String getContent(Properties properties) {
FTPClient ftpClient = new FTPClient();
ftpClient.connect(properties.get("server"), properties.get("port"));
ftpClient.login(properties.get("user"), properties.get("pass"));
// Get file stream and save the content to a variable here
return content;
}
}
One interface for a different methods of obtaining a file. I am not persisting that this is good or not, it's just an example of code I've stumbled upon in my current project in work and I was wondering if could it be done better.
The usage of a "Params" class is better than properties, in performance. The java compiler can handle such short lived classes quite well.
One sees properties on some constructors / factory methods, like for XML and such.
One sees a parameter containing class in larger systems, to keep the API restricted to one parameter, and not use overloaded methods.
I would do:
public class Params {
public final int a;
public final int b;
public Params(int a, int b) {
this.a = a;
this.b = b;
}
}
And in the class immediately use params.a.
For the rest there is also the Builder Pattern, but that would be more a substitute for a complex constructor.
Signatures in interfaces should not ever change!!! If you contemplate to change APIs in the future (i.e. change, add or remove a parameter), an acceptable way may be by incapsulating your parameters in objects in order to do not break signatures.
I have a class called ClassA which contains a List of ClassB objects. Both classes implement Parcelable.
I am trying to create the read/write methods for this list in ClassA and am having trouble. For example I tried:
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeList(mClassBList);
}
but then
private ClassA(Parcel in) {
mClassBList = in.readList();
}
throws an error because it needs all these extra arguments.
How do I correctly read/write this List?
The links suggested by both George and buczek can be really helpful in your case.
Perhaps more directly, you need to do something like this:
//Supposing you declared mClassBList as:
List<ClassB> mClassBList = new ArrayList<ClassB>();
in.readTypedList(mClassBList, ClassB.CREATOR);
I still recommend you check out the answer, especially (as suggested by Buczek) How to pass a parcelable object that contains a list of objects?
I have an arraylist of "Swimmer" objects and I don't want it to delete every time the app closes. I have read about serialization and using shared preferences, but I have no idea where to write that code or what it does.
The arraylist is currently stored as a public variable in the main activity class where it is accessed by the other activites.
public ArrayList<Swimmer> allSwimmers = new ArrayList<Swimmer>();
This is the activity where I use a list view to display all of the swimmers in the list and when one of the swimmers is clicked it goes to a new activity to display the swimmers info.
Everything is fine I just would like to save "MyActivity.allSwimmers" (the arraylist) somewhere where when the app closes and restarts its not blank
public class AllSwimmers extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.all_swimmers);
ListAdapter theAdapter = new ArrayAdapter<Swimmer>(this, android.R.layout.simple_list_item_1,
MyActivity.allSwimmers);
ListView theListView = (ListView) findViewById(R.id.allSwimmersList);
theListView.setAdapter(theAdapter);
theListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Intent goToIndiv = new Intent(AllSwimmers.this, IndivSwimmer.class);
final int result = 1;
goToIndiv.putExtra("position", position);
startActivityForResult(goToIndiv, result);
}
});
}
}
To do this, you would have to save the data in a SQLiteDatabase. Here is a great tutorial on how to do it:
http://www.androidhive.info/2011/11/android-sqlite-database-tutorial/
Normally what you would want to do in order to be able to store custom data objects into memory, is to make them serializable.
You have to remember that persistent data outside the scope of a running application needs to be mapped into physical memory. In other words:
(As for) Serializing your data structure / object, means decomposing it into a format which can be stored.
Of course the other aspect of serialization is the ability to pick up this serialized data from memory into your enviroment as volatile objects / structure again.
In Java this is all done by adhering your custom data to Serializable interface. However since we are discussing for Android, it is much more recomended to adhere to Parcelable interface (better speed, efficiency and security managing data)
So, at first, there really seems to be no other reasonable way of acomplishing what you're asking than by the serialization (using Parcelable interface) of Swimmer in one way or another...
Here is a simple example of data modelling POJO with Parcelable:
public class Profile implements Parcelable {
private String id;
private String name;
private String category;
public Profile(String id, String name, String category){
this.id = id;
this.name = name;
this.category = category;
}
public Profile(Parcel in){
String[] data = new String[3];
in.readStringArray(data);
this.id = data[0];
this.name = data[1];
this.category = data[2];
}
#Оverride
public int describeContents(){
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringArray(new String[] {this.id,this.name,this.category});
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public Profile createFromParcel(Parcel in) {
return new Profile(in);
}
public Profile[] newArray(int size) {
return new Profile[size];
}
};
}
The "problem" is that if you want to make use of SharedPreferences, it doesn't feature built in support for Parcelable, nor any other form of Serialized data mapping protocol since it is meant only for primitive key/value mapping by design. (SharedPreferences was built as means to store app configuration values that need persistance such as sound on/off, credentials, etc.., and not large data heaps).
However there is a rather neat "workaround" into using SharedPreferences out of convenience for storing custom Data objects with JSON. Of course the big advantage being JSON data easily serialized into String primitive.
Using default JSON api (org.json) you can make your own parse/convert functions valid for any type of POJO data. There is many different api for JSON data management and endless ways of manipulating it easily. Here is a basic example with nested json arrays:
SharedPreferences prefs = this.getSharedPreferences("MyCustomDataPreferences", Context.MODE_PRIVATE);
/* Assuming this JSON from SharedPreferences: "{animals : [{familyKey:Dogs},
{familyKey:Cats}, {familyKey:Lizards}]}" */
//Notice how JSONObject just takes a String as an argument:
JSONObject obj = new JSONObject(prefs.getString("animalsJSON", null));
List<String> list = new ArrayList<String>();
JSONArray array = obj.getJSONArray("animals");
//Store into list all values with key "familyKey":
for(int i = 0 ; i < array.length() ; i++){
list.add(array.getJSONObject(i).getString("familyKey"));
}
As you can see, this way you can simply store string values composed as JSON objects, then restore them back into java objects for use, using built in SharedPreferences.
I am lost again. My object is as follows:
public class LogInfo implements Serializable{
public ArrayList<Point[][]> strokes;
public LinkedList<byte[]> codes;
public int[] times;
...
}
First of all I populate the ListView from an ArrayList of this objects. Then I select an object from the ListView, and I would like to populate new list in new fragment with fields
public ArrayList<Point[][]> strokes;
public LinkedList<byte[]> codes;
However, to create an ArrayAdapter I can't just pass an object to it (as I understand). I need to pass an array. the problem is, that I would like to pass an object previously created and selected, and then populate the list from its fields (not only strokes or codes, but both of them).
How should my ObjectAdapter class look like and what class should it extend? To select an Object from ArrayList of Objects I used:
public class LogInfoObjectAdapter extends ArrayAdapter<LogInfo>
Example (real life):
I have a lot of cars on the parking and I need to make a list of them, so I use ArrayAdapter to populate the list. After I choose one car from the list (car object) it has two arrays in it (for example broken bulbs and broken tires, but both array are same size). Now I want to will the new list with information from selected car. I hope it is clear enough. My problem is that to use ArrayAdapter I have to pass an array in the constructor, but I want to pass the whole object and inside my adapter class process it and add choosen fields to ListView
If you have an object with multiple lists, you don't need to extend ArrayAdapter, you can just extend the BaseAdapter and implement the methods needed (getCount(), getView(), etc).
public class Adapter extends BaseAdapter {
class LogInfo implements Serializable {
public ArrayList<Point[][]> strokes;
public LinkedList<byte[]> codes;
public int[] times;
}
private LogInfo mInfo;
public Adapter(LogInfo info) {
mInfo = info;
}
#Override
public int getCount() {
if (mInfo != null && mInfo.strokes != null) {
return mInfo.strokes.size();
}
return 0;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
if (mInfo != null) {
Point[][] p = mInfo.strokes.get(i);
byte[] b = mInfo.codes.get(i);
//create the view
}
return null;
}
}
1) Array adapter has method getItem() you can use it to get particaular item by index.
2) Make your LogInfo implements IIterable interface
http://developer.android.com/reference/java/lang/Iterable.html
public class LogInfo implements Serializable, Iterable<Point[][]>{
public ArrayList<Point[][]> strokes;
public LinkedList<byte[]> codes;
public int[] times;
public abstract Iterator<Point[][]> iterator (){
//Iterator implementation
}
Now you can use this object directly in other list whitch has following signature
public class LogInfoObjectAdapter extends ArrayAdapter<Point[][]>