[AndroidBits] How to decouple navigation between your components

[AndroidBits] How to decouple navigation between your components

 A beginners guide to power-up Bundles and Intents.

October 31, 2016

This article was initially published on  my website, also  available on Medium.

’em n00bz!

While starting out working with Android one of the major issue developers usually have, is passing data between Activities, Fragments, Services, etc. some get around the problem by allocating data in memory or running for what seems to be the most common solution, moving all variables and/or objects to the Application instance ??.

Note: I’ve written a small article on how to navigate between your Android components that applies this article’s knowledge but takes it a step further. I do recommend to read this first if you are not familiar with Intent/Bundles.

How Do They Do It?

The standard way to pass data in Android is using Intents/Bundles. When you’re sending data between Activities/Receivers/Services means this data will be serialised (converted into a byte array) and deserialised (from byte array) once requested. Note that only certain data types are considered Parcelable and they are explicitly spelled out in the Bundle API.

In the destination, you will always have Deep copies of your data/objects.

Practice makes perfect ??

In order to pass your own custom objects, you have to implement either Serializable (please don’t) or Parcelable, if not, the data for each field must be passed individually which translates into a lot of manual work.

public class Foo {
    private long mId;
    private String mName;
  
    public Foo(long id, String name) {
        mId = id;
        mName = name;
    }
}

The Foo object does not implement the Parcelable interface, there is no way to or the data.

Starting a new Activity while passing the foo’s data:

Foo myExampleFoo = new Foo(1, "Hello world"); // Example object

Intent intent = new Intent(this, CharacterActivity.class);
intent.putExtra("keyFooId", myExampleFoo.getId());
intent.putExtra("keyFooName", myExampleFoo.getName()); 

If Foo implements Parcelable, archiving the same result is simple

Intent intent = new Intent(this, MyActivity.class);
intent.putExtra("keyFoo", foo);
startActivity(intent);

You can generate a default implementation of Parcelable either on parcelabler.com or use the AS plugin: search for “Android Parcelable”.

Note: order matters in Parcelable, so be sure to keep it right if you make any manual changes:

public class Foo implements Parcelable {

    private long mId;
    private String mName;

    public Foo(long id, String name) {
        mId = id;
        mName = name;
    }


    @Overridepublic int describeContents() {
        return 0;
    }

    // This is where you write the values you want to save to the `Parcel`.  // The `Parcel` class has methods defined to help you save all of your values.  // Note that there are only methods defined for simple values, lists, and other Parcelable objects.  // You may need to make several classes Parcelable to send the data you want.@Overridepublic void writeToParcel(Parcel dest, int flags) {
        dest.writeLong(this.mId);
        dest.writeString(this.mName);
    }

    // Using the `in` variable, we can retrieve the values that // we originally wrote into the `Parcel`.  This constructor is usually // private so that only the `CREATOR` field can access.protected Foo(Parcel in) {this.mId = in.readLong();this.mName = in.readString();
    }

    public static final Parcelable.Creator<Foo> CREATOR = new Parcelable.Creator<Foo>() {
        @Overridepublic Foo createFromParcel(Parcel source) {
            return new Foo(source);
        }

        @Overridepublic Foo[] newArray(int size) {
            return new Foo[size];
        }
    };
  • plugin-generated Parcelable default implementation

Retrieving data

Accessing the passed data is the same as (literally) getting it from a Bundle. The most important aspect is to use the same keys while accessing the data, no matter what your destination component is.

Activities access the Intent’s data by calling getIntent().getExtras(), this will return a bundle with the passed data.

Bundle passedData = getIntent().getExtras();
long passedId = passedData.getLong("keyFooId");
String fooName = passedData.getString("keyFooString");
Foo foo = new Foo(passedId, passedName);

Don't forget to check for nulls

On the other hand, if you are using fragments passing data, create a Bundle and pass it as the fragment’s arguments:

Bundle args = new Bundle();
args.putString("keySomeValue", "Hello world");
Fragment fragment = new Fragment();
fragment.setArguments(args);

Retrieving this data on the fragment’s instance:

String passedString = getArguments().getString("keySomeValue")); 

[AndroidBits]: Small articles (bits, get it? ??) discussing simple topics, that I found to be of immense value during my quest to become a better dev!


Would love to talk, feel free to reach out and follow me on  twitter.com/joaquimley 

要查看或添加评论,请登录

Joaquim Ley的更多文章

社区洞察

其他会员也浏览了