Tuesday, March 22, 2016

Android Parcelable Object

Mission: 
Send one custom object or a list of them from one Activity class to another Activity class.

Before we start, let's take a look at what I have in the project.
  • An Activity Class named FirstActivity.
  • An Activity Class named SecondActivity.
  • An Custom Object Class named City.
public class City {
    private String name;
    private double longitude;
    private double latitude;

    // Constructor, Setter and Getter
}

As you could see, the City class is composed of three properties, name, longitude and latitude with appropriate constructor, setters and getters.


How can we send a list of city objects from FirstActivity to SecondActivity? 

The only tunnel for this task is send the data within an Intent. Intent is like an envelope help you send bunch of data in it to the right place, like an Activity. But the problem is the Intent object could mostly only carry primary type objects, like int, double, String, etc, other than custom object. So, when you need to send a custom object, or list of custom objects along with an Intent object, you need to make this custom object class "Parcelable". It's like pack your data into a parcel, then send it through an Intent object. In the new Activity, when Intent object is received, the parcel will be opened (resolved).


Here is how we could do it:

1, In the City.java file, declare class will implement Parcelable Interface.
import android.os.Parcelable;

public class City implements Parcelable{
    private String name;
    private double longitude;
    private double latitude;

    // Constructor, Setter and Getter
}

Now the Custom Class will be Parcelable, could be carried along by the Intent object.

2, Implement Required Methods for Parcelable Interface.
    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeDouble(longitude);
        dest.writeDouble(latitude);
    }
The first method defines the kind of object you are going to Parcel, you can use the hashCode() here.
The second method is actually trying to pack your object data into the parcel.

PS: If some of the property's type is not primary, you need to "Flat" it to primary type object first. E.g. You have a enum type property, then you need to convert it to int value, then use dest.writeInt(value);

Tip: In Android Studio, when there is an error, there will be a red bulb to indicate the Android Studio has a solution for this. After you add "implements Parcelable" after "class City", the red bulb will show up, click on it and choose implement the Parcelable Interface, it will automatically implements these two methods for you.

3, Classes implementing the Parcelable interface must also have a non-null static field called CREATOR of a type that implements the Parcelable.Creator interface. This is the step where you could unpack data from a parcel, then construct it into a new object.
    protected City(Parcel in) {
        name = in.readString();
        longitude = in.readDouble();
        latitude = in.readDouble();
    }

    public static final Creator CREATOR = new Creator() {
        @Override
        public City createFromParcel(Parcel in) {
            return new City(in);
        }

        @Override
        public City[] newArray(int size) {
            return new City[size];
        }
    };

Tip: In Android Studio, these two methods could also be auto implemented in the way introduced in the last step.

4, How to use it?
  • Send an Intent object with Parcelable object.
  •     City city = new City("New York", 40.7056497, -73.9780035);
        Intent intent = new Intent(getApplicationContext(), SecondActivity.class);
        intent.putExtra("Intent String ID for City Object", city);
        startActivity(intent);
    
  • Send an Intent object with list of Parcelable objects.
  •     City cityNY = new City("New York", 40.7056497, -73.9780035);
        City cityLA = new City("Los Angeles", 34.0204989, -118.4117325);
        ArrayList cityList = new ArrayList<>();
        cityList.add(cityNY);
        cityList.add(cityLA);
        Intent intent = new Intent(getApplicationContext(), SecondActivity.class);
        intent.putParcelableArrayListExtra("Intent String ID for City Object List", cityList);
        startActivity(intent);
    
  • Resolve a Parcelable object from an Intent object.
  •     Intent intent = getIntent();
        City city = intent.getExtras().getParcelable("Intent String ID for City Object");
  • Resolve a list of Parcelable objects from an Intent object.
  •     Intent intent = getIntent();
        ArrayList cityList = intent.getExtras().getParcelableArrayList("Intent String ID for City Object List");
    
  • Array of Parcelable object could also be sent and received along with Intent object.

Full source code of City:

package com.antonio081014.demo.android.parcelabledemo;

import android.os.Parcel;
import android.os.Parcelable;

public class City implements Parcelable {
    private String name;
    private double longitude;
    private double latitude;

    // Constructor, Setter and Getter
    public City(String name, double longitude, double latitude) {
        this.name = name;
        this.longitude = longitude;
        this.latitude = latitude;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getLongitude() {
        return longitude;
    }

    public void setLongitude(double longitude) {
        this.longitude = longitude;
    }

    public double getLatitude() {
        return latitude;
    }

    public void setLatitude(double latitude) {
        this.latitude = latitude;
    }
    
    protected City(Parcel in) {
        name = in.readString();
        longitude = in.readDouble();
        latitude = in.readDouble();
    }

    public static final Creator CREATOR = new Creator() {
        @Override
        public City createFromParcel(Parcel in) {
            return new City(in);
        }

        @Override
        public City[] newArray(int size) {
            return new City[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeDouble(longitude);
        dest.writeDouble(latitude);
    }
}

Friday, February 12, 2016

Stored Property Observer in Swift

Firstly, let's take a look at the following Code Example:

In Swift,

Stored Property has two function to notify observer when it will be set(trying but before it is set, willSet) and it has been set(trying and already set it, didSet). So, every time trying to set the property, the willSet function will be called first, followed by didSet.

Here I did an interesting experiment: trying to modify the property while these two observing functions are called.

In the willSet function, assign it to a new String “Hi” does not do anything. It looks like a temporary assignment, and then assign it back very soon, because in the next calling function didSet, str is “Hello, Antonio”, rather than “Hi”, also the oldValue was not changed either.

While, in the didSet function, assign it to a new String “Hi” does actually assign the String “Hi” to this property, it changed the property’s value indeed, though the oldValue is still “Hello, playground”.

This is because the willSet function is called before the Stored Property has actually been set, while the “didSet” function is called after the Stored Property has already been set. So, in willSet function, assign a new String will not change the property value, since it will be assigned soon, while in didSet function, the property has been assigned, there is no other assignment here, so if it’s assigned by a new String value, this property value will be changed.

There is one thing deserve to note, assign new value to the property in the willSet and didSet function will not invoke recursively willSet nor didSet observing function.

Wednesday, August 5, 2015

WWDC2014 Video 237 A Strategy for Great Work

This session is presented by Ken, who has more than 10 yrs experience working at Apple. Here are 10 Lessons he shared in this session.

  • Know a good idea when you see it 
  • Don't try to solve every problem at once 
  • Find smart friends and listen to them 
  • Work should explain itself
  • Choose the simplest thing which might work 
  • Only show your best work
  • Iterating quickly leads to better work
  • Be kind to people, but be honest about work 
  • Separate yourself from your work 
  • You’re never done

I specially present my affection on the following Lesson and Quote. Love this session.