Android – Comparing Models in Kotlin, Java, and C# for Xamarin

Models are an obvious important part of our applications we develop. It’s how we define our data and because of that, we can grow our models to be quite large in number. This post will look at comparing the definition of models between Java, C# (for Xamarin), and Kotlin.

Our example model will be a simple Person that has a Name and Description along with an ID. Let’s look at how we can define our Person model with these fields as well as the ability to access these fields publicly.

Using Java

Java is going to be our largest and most annoying to develop. We need to define our class, private fields, and then public functions/methods to get and set the value of each of the fields. We also need to be able to instantiate a Person with all these properties set in the constructor.

Person.java

public class Person{
    private int id;
    private String name;
    private String description;

    public Person(int id, string name, string description){
        this.id = id;
        this.name = name;
        this.description = description;
    }

    public void setID(int id){
        this.id = id;
    }
    public int getID(){
        return this.id;
    }
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
    public void setDescription(String description){
        this.description = description;
    }
    public String getDescription(){
        return this.description;
    }
}

That’s exhausting…

Now we can instantiate it and update properties like this:

...
Person bob = new Person(1, "Bob", "He writes code and stuff");
bob.setDescription("He doesn't actually write code");
...

Using C# for Xamarin Applications

C# makes our lives a lot easier with the get and set mechanism built into properties.

Person.cs

public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }

    public Person(int id, string name, string description)
    {
        ID = id;
        Name = name;
        Description = description;
    }
}

Nice and neat!

Now we can instantiate it and update properties like this:

...
var bob = new Person(1, "Bob", "He writes code and stuff");
bob.Description = "He doesn't actually write code";
...

Using Kotlin

Kotlin has some cool tricks that allow us to define and set properties directly in our constructor without having to define and set them separately. This gives us the quickest way to create simple POCO definitions and speed up that development time.

Person.kt

class Person(var id: Int, var name: String, var description: String);

One line.

Now we can instantiate it and update properties like this:

...
val bob = Person(1, "Bob", "He writes code and stuff");
bob.description = "He doesn't actually write code";
...

Conclusion

Each language has their nuances, but I think we can all agree that defining models in Java is just a headache that other languages have solved with better solutions.

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Advertisements

Android.Kotlin – Create a TabLayout

We’ll once again take a break from the cross-platform Xamarin content and look at an example of using the latest Kotlin language from Jetbrains with our native Android applications. In this post, we’ll look at an implementation of a TabLayout with a ViewPager using Kotlin!

I also apologize for the lack of useful highlighting of the Kotlin code in this post. Since it is a new language, WordPress doesn’t support it as well for code snippets…

The source code for this example can be found on my GitHub here:
https://github.com/SuavePirate/KotlinPuppies.

The Layout

This example will use a RecyclerView for the content of each Fragment. So we need to define layouts for our Puppy, Fragment, and our entire Activity that houses the TabLayout and Fragments.

Our puppy item will contain a CardView that has an image and text to contain a picture of the puppy and the pup’s name!

puppy_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="8dp"
        app:cardElevation="8dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="16dp"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/puppyImageView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:srcCompat="@mipmap/ic_launcher" />

            <TextView
                android:id="@+id/puppyTextView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textAlignment="center"
                android:text="Puppy Name" />
        </LinearLayout>

    </android.support.v7.widget.CardView>
</LinearLayout>

Now let’s look at our Fragment layout that will contain a RecylerView that houses each collection of puppies.

puppy_fragment.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.suavepirate.kotlinpuppies.MainActivity$PlaceholderFragment">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/puppyRecyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        tools:listitem="@layout/puppy_item" />
</RelativeLayout>

Now let’s wrap it all together with our main layout:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.suavepirate.kotlinpuppies.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="@dimen/appbar_padding_top"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/AppTheme.PopupOverlay">

        </android.support.v7.widget.Toolbar>

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />


</android.support.design.widget.CoordinatorLayout>

Now that we have our layouts, let’s create our Fragment, Adapters, and then wrap it all together in our MainActivity.

Building the Recycler Adapter

Let’s first define our RecyclerView adapter and ViewHolder to contain our collections of puppies.

PuppyHolder.kt

class PuppyHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    private val puppyImage: ImageView = itemView.findViewById<ImageView>(R.id.puppyImageView)
    private val puppyName: TextView = itemView.findViewById(R.id.puppyTextView)

    fun updateWithPuppy(puppy: Puppy) {
        puppyImage.setImageDrawable(puppy.imageFile)
        puppyName.text = puppy.name
    }
}

This code defines a class that inherits the RecyclerView.ViewHolder with a default constructor that requires a View parameter that is also passed into the base class constructor. It then defines the two subviews we need to populate – the TextView and ImageView of a single puppy. Lastly, we create our updateWithPuppy function that will be called by our Adapter to instantiate the content with the given puppy’s information.

Now that we have our ViewHolder, we can create our Adapter:

PuppyAdapter.kt

class PuppyAdapter(private val puppies: ArrayList<Puppy>) : RecyclerView.Adapter<PuppyHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PuppyHolder {
        val puppyItem = LayoutInflater.from(parent.context).inflate(R.layout.puppy_item, parent, false) as LinearLayout
        return PuppyHolder(puppyItem)
    }

    override fun onBindViewHolder(holder: PuppyHolder, position: Int) {
        holder.updateWithPuppy(puppies[position])
    }

    override fun getItemCount(): Int {
        return puppies.toArray().count();
    }

}

This adapter uses another cool feature of Kotlin – Defining a private field in the constructor while also auto-setting it. The class declaration and default constructor of PuppyAdapter(private val puppies: ArrayList) is the equivalent to something like this in Java:

public class PuppyAdapter{
    private final ArrayList<Puppy> puppies;
    public PuppyAdapter(ArrayList<Puppy> puppies){
        this.puppies = puppies;
    }
}

That’s pretty sweet! The rest of the wire up for the Adapter is pretty standard. It sets the ViewHolder using the PuppyHolder we created above and updates it with the puppy by finding it with the given index.

The Puppy Fragment

Now we can create our Fragment that will contain and wire up the RecyclerView for each puppy collection.

PuppyListFragment.kt


class PuppyListFragment(passedContext: Context) : Fragment(){

    val puppyFactory : PuppyFactory = PuppyFactory(passedContext)
    val ARG_LIST_TYPE = "LIST_TYPE"
    val passThroughContext : Context = passedContext


    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        val rootView = inflater!!.inflate(R.layout.fragment_main, container, false)
        val recyclerView = rootView.findViewById<RecyclerView>(R.id.puppyRecyclerView) as RecyclerView
        val listType = this.arguments.getSerializable(ARG_LIST_TYPE) as PuppyListType
        var puppies = ArrayList<Puppy>()
        when (listType) {
            PuppyListType.All -> puppies = puppyFactory.puppies
            PuppyListType.Active -> puppies = puppyFactory.activePuppies
            PuppyListType.LeashTrained -> puppies = puppyFactory.leashTrainedPuppies
            PuppyListType.Big -> puppies = puppyFactory.bigPuppies
            PuppyListType.Small -> puppies = puppyFactory.smallPuppies
        }

        recyclerView.adapter = PuppyAdapter(puppies)
        recyclerView.layoutManager = LinearLayoutManager(passThroughContext)
        return rootView
    }

    companion object {
        val ARG_LIST_TYPE = "LIST_TYPE"

        fun newInstance(listType: PuppyListType, context: Context): PuppyListFragment {
            val fragment = PuppyListFragment(context)
            val args = Bundle()
            args.putSerializable(ARG_LIST_TYPE, listType)
            fragment.arguments = args
            return fragment
        }
    }


}

In the onCreateView override, we get our puppies by type from our factory class and then instantiate our PuppyAdapter and LinearLayoutManager that get applied to the RecyclerView that we grab from our layout created earlier. Now we can pass in the PuppyListType that the fragment is responsible for displaying which will then set up our RecyclerView to render those particular puppies.

We also set up what is the equivalent of a static function that can instantiate a new instance of a PuppyListFragment by using a nested companion object.

Adding Page Adapter

Now that we have our Fragment and it’s child RecyclerView for puppies all set up, we can now create an adapter that is responsible for handling the different pages within the TabLayout that we are ultimately setting up.

PageAdapter.kt

class PageAdapter(fm: FragmentManager, private val context: Context) : FragmentPagerAdapter(fm) {

    override fun getItem(position: Int): Fragment {
        when (position) {
            0 -> return PuppyListFragment.newInstance(PuppyListType.All, context)
            1 -> return PuppyListFragment.newInstance(PuppyListType.Big, context)
            2 -> return PuppyListFragment.newInstance(PuppyListType.Small, context)
            3 -> return PuppyListFragment.newInstance(PuppyListType.LeashTrained, context)
            4 -> return PuppyListFragment.newInstance(PuppyListType.Active, context)
        }
        return PuppyListFragment.newInstance(PuppyListType.All, context)
    }

    override fun getCount(): Int {
        // Show 5 total pages.
        return 5
    }

    override fun getPageTitle(position: Int): CharSequence? {
        // return null to show no title.
        return null
        
    }

}

This is a pretty standard implementation of a PageAdapter. We override the getItem function and return the appropriate instantiated PuppyListFragment by passing in the PuppyListType we want to use by the grouping.

Set up the Activity

The last bit now is the set up our Activity that will house our TabLayout and ViewPager that will contain multiple instances of the PuppyListFragment to show different collections of puppies by category.

MainActivity.kt



class MainActivity : AppCompatActivity() {
    private var mSectionsPagerAdapter: PageAdapter? = null

    /**
     * The [ViewPager] that will host the section contents.
     */
    private var mViewPager: ViewPager? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val toolbar = findViewById<View>(R.id.toolbar) as Toolbar
        setSupportActionBar(toolbar)

        // Create the adapter that will return a fragment for each of the three
        // primary sections of the activity.
        mSectionsPagerAdapter = PageAdapter(supportFragmentManager, this)

        // Set up the ViewPager with the sections adapter.
        mViewPager = findViewById<ViewPager?>(R.id.container)
        mViewPager!!.adapter = mSectionsPagerAdapter

        val tabLayout = findViewById<View>(R.id.tabs) as TabLayout
        tabLayout.setupWithViewPager(mViewPager)

        // set icons
        tabLayout.getTabAt(0)!!.setIcon(R.drawable.ic_home_white_24dp)
        tabLayout.getTabAt(1)!!.setIcon(R.drawable.ic_dog_white_24dp)
        tabLayout.getTabAt(2)!!.setIcon(R.drawable.ic_small_dog_white_24dp)
        tabLayout.getTabAt(3)!!.setIcon(R.drawable.ic_trained_white_24dp)
        tabLayout.getTabAt(4)!!.setIcon(R.drawable.ic_active_white_24dp)

    }
}

Our MainActivity holds a private field for the ViewPager reference, and in the override of onCreate, we set up our view components by finding them in our associated layout file, then wire up the PageAdapter with our TabLayout. Then we set our icons for each given tab after calling the setupWithViewPager on our TabLayout.

View the Results

We can run our application and view our expected results of our tabs and different list of puppy cards!

Screen Shot 2017-07-05 at 11.14.13 AM

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Android.Basics – Adding a Bottom Navigation View

Changing my pace of steady Xamarin content to go to my roots of native mobile development. This time, we’ll look at implementing the latest control provided by Google and Material Design – The BottomNavigationView.

Resources

Aren’t These Just Tabs?

I mean… yeah, but… it’s new and cool! Google finally realized that stretching to the top of the app can be annoying.
Screen Shot 2017-06-27 at 5.56.48 PM.png

This new control is also a little different from the TabLayout we all know in love from Material Design and Android development in that it is limited to 5 maximum tab items and does not support scrolling. It’s meant to act as top level or sibling level navigation as long as all items are of equal importance in the context of the application/current view. It is also nice to give some variety to our applications navigation scheme; larger apps with many tabbed views can become overwhelming, so tossing something new is relieving to our users.

Code

There are 3 major components to setting up a view with a BottomNavigationView.

  1. First, we need to create a menu resource for our navigation items.
  2. Then we need to create, style, and set up our BottomNavigationView in our layout.
  3. Lastly, add listeners for when an item is selected in our BottomNavigationView and make sure it fits the experience expectation defined in Material Design.

Create a Menu

In our example, we will be building an application for viewing adoptable puppies. Each navigation item will be a different set of these puppies by categorizing them. Let’s create a menu for “all”, “big”, “small”, “trained”, and “active” as categories for our puppies:

res/menu/bottom_bar_menu.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/all_puppies"         android:title="@string/action_all"         android:icon="@drawable/ic_home_white_24dp" />

    <item android:id="@+id/big_puppies"         android:title="@string/action_big"         android:icon="@drawable/ic_dog_white_24dp" />

    <item android:id="@+id/small_puppies"         android:title="@string/action_small"         android:icon="@drawable/ic_small_dog_white_24dp" />

    <item android:id="@+id/trained_puppies"         android:title="@string/action_trained"         android:icon="@drawable/ic_trained_white_24dp" />

    <item android:id="@+id/active_puppies"         android:title="@string/action_active"         android:icon="@drawable/ic_active_white_24dp" />
</menu>

With our menu, we can create our layout.

Updating the Layout

In our example, we are moving from a TabLayout with a ViewPager. However, the Material Design documentation for the BottomNavigationView states that it should NOT be used with side-swiping actions such as a ViewPager. Let’s replace that ViewPager with a FrameLayout that will be used to swap our active Fragment and also remove the TabLayout that is being replaced by the BottomNavigationView:

res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:app="http://schemas.android.com/apk/res-auto"     xmlns:tools="http://schemas.android.com/tools"     android:id="@+id/main_content"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:fitsSystemWindows="true"     tools:context="com.suavepirate.bottomnavigationpuppies.activities.MainActivity">

    <android.support.design.widget.AppBarLayout         android:id="@+id/appbar"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:paddingTop="@dimen/appbar_padding_top"         android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar             android:id="@+id/toolbar"             android:layout_width="match_parent"             android:layout_height="?attr/actionBarSize"             android:background="?attr/colorPrimary"             app:layout_scrollFlags="scroll|enterAlways"             app:popupTheme="@style/AppTheme.PopupOverlay">

        </android.support.v7.widget.Toolbar>
    </android.support.design.widget.AppBarLayout>

<FrameLayout     android:id="@+id/container"     android:layout_width="match_parent"     android:layout_height="match_parent"     app:layout_behavior="@string/appbar_scrolling_view_behavior" ></FrameLayout>
<android.support.design.widget.BottomNavigationView     android:id="@+id/bottombar"     android:layout_width="match_parent"     android:layout_height="56dp"     android:layout_gravity="bottom|fill_horizontal|start"     app:menu="@menu/bottom_bar_menu"     android:background="@android:color/white"     app:elevation="8dp"/>
</android.support.design.widget.CoordinatorLayout>

It’s important to layout the BottomNavigationView at the bottom of the page as well as give it a solid background and elevation. Also, notice how we apply our menu we created to the view by setting app:menu="@menu/bottom_bar_men".

With our layout set, let’s wire up listeners to update the current Fragment based on the selected navigation item.

Setting Up Listeners

In our MainActivity.java we can implement the BottomNavigationView.OnNavigationItemSelectedListener interface and override the onNavigationItemSelected method:

MainActivity.java

// imports

public class MainActivity extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener {
    private PageAdapter mSectionsPagerAdapter;
    private FrameLayout mContainer;
    private BottomNavigationView mBottomBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        // Create the adapter that will return a fragment for each of puppy types
        mSectionsPagerAdapter = new PageAdapter(getSupportFragmentManager(), this);

        // Set up the ViewPager with the sections adapter.
        mContainer = (FrameLayout) findViewById(R.id.container);

        // set up the first Fragment
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.add(R.id.container, mSectionsPagerAdapter.getItem(0), "CURRENT_PAGE");
        ft.commit();

        // set up the bottom bar and listener
        mBottomBar = (BottomNavigationView)findViewById(R.id.bottombar);
        mBottomBar.setOnNavigationItemSelectedListener(this);

    }

    // Handles when an item is selected to update the fragment container
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);

        switch(item.getItemId()){
            case R.id.all_puppies: ft.replace(R.id.container, mSectionsPagerAdapter.getItem(0));
                break;
            case R.id.big_puppies: ft.replace(R.id.container, mSectionsPagerAdapter.getItem(1));
                break;
            case R.id.small_puppies: ft.replace(R.id.container, mSectionsPagerAdapter.getItem(2));
                break;
            case R.id.trained_puppies: ft.replace(R.id.container, mSectionsPagerAdapter.getItem(3));
                break;
            case R.id.active_puppies: ft.replace(R.id.container, mSectionsPagerAdapter.getItem(4));
                break;
        }
        ft.commit();
        return true;
    }
}

Now with all of this, we are able to switch the current Fragment with a fade in and out animation when the selected navigation item is updated. That means our BottomNavigationView is implemented and ready to go!

Screenshot_1497932698

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.