Giter Site home page Giter Site logo

09-adapter-flyweight-android's Introduction

This is an assignment to the Software Architecture class at the Technische Hochschule Nürnberg.

Assignment 9: Adapter and Flyweight

This assignment covers the two design patterns Adapter and Flyweight.

At first you have to improve the performance by implementing the flyweight pattern. Afterwards you will use a common Android view element (RecyclerView) which already implements the flyweight pattern. The usage of this view element requires you to implement custom adapter to get your data to the view.

Setup

  1. Create a fork of this repository (button in the right upper corner)
  2. Clone the project (get the link by clicking the green Clone or download button)
  3. Import the project to your Android Studio; it behaves almost the same as IntelliJ.

Adapter - Intro

The given app generates a random fleet of Star Wars fighters. To get an overview about your fleet the app shows all your fighters in a ListView as so called cards containing the following informations:

  • an image of the fighter type
  • the name of the fighter type
  • the name of the pilot

In the last assignments we used the default ArrayAdapter<> to transfer our data to a ListView. This is (more or less) only possible for String values (or by overriding the toString() method as we did last week) but if you want to display data in more complex elements containing more than just a TextView you have to implement a custom adapter which is aware of the structure of your element and is able to assign the data correctly.

To accomplish this, the given app already contains a custom ArrayAdapter<> (FighterListAdapter). The class contains a private static nested class which serves as a container for the view element (a so called view holder, more on that later). Furthermore it overrides the method getView() where it inflates the custom view element (if necessary) and transfers the data from a Fighter instance to the view element (the adaptation process).

Flyweight - Part 1

The count of fighters generated is hard coded in the class MainActivity (FIGHTER_COUNT). If you increase the count to 50 or above you'll notice that the emulator won't start anymore because the app loads too many data to the memory while generating the fighters. If you already had a look at the FighterFactory you might have seen that every time a fighter has to be created the factory loads the corresponding image into the memory and assigns the loaded image to the created fighter instance.

Here comes the Flyweight pattern into play:

  1. Think about what are the intrinsic and what are the extrinsic parts of the Fighter class. (In case you don't remember the terms or the concept have a look here.)
  2. Refactor the class FighterFactory to follow the Flyweight pattern by caching the intrinsic parts.
  3. Modify the process of creation to benefit of your caching mechanism.

Hint: think of a data structure that enables you to retrieve the matching element with a single call (e.g. Map<String, X> or Map<Class<?>, X> (Where X is a placeholder for your cached type not a generic).

Flyweight - Part 2

To further improve the performance of the app you can use the Android built-in RecyclerView. This document explains how to use the RecyclerView in combination with the already mentioned card elements. As the fighter_item.xml is already a card element you can ignore all .xml parts!

The concept of the RecyclerView is also based on the Flyweight pattern. A RecyclerView keeps track of all created row elements and reuses (rebinds) them when they aren't visible any more i.e. when they left the screen because you scrolled up or down.

The following image demonstrates the concept visually (borrowed from grokkingandroid.com):

Recycler View - credits to grokkingandroid.com

Refactor the app to use a RecyclerView to improve the performance by following these steps:

  1. Implement a new adapter class FighterRecyclerViewAdapter.
  2. Modify the file activity_main.xml and replace the whole given ListView node with this snippet:
<android.support.v7.widget.RecyclerView
        android:id="@+id/fighterListView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginEnd="16dp"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
  1. Replace the ListView reference in the class MainActivity by a reference to the newly created RecyclerView.
  2. Assign a new instance of LinearLayoutManager as layout manager to your RecyclerView.
  3. Create an instance of your FighterRecyclerViewAdapter with a list of previously generated Fighters and assign it to the reference of your RecyclerView.

To implement a custom RecyclerView.Adapter<> you also have to implement a new view holder which extends RecyclerView.ViewHolder.

View holders are wrappers for custom view elements. When created they get a reference to the view element, unwrap the single elements and "cache" them as private fields. Later on you're using the view holder instance to pass data to the view element either by accessing the "cached" fields directly or by calling convenience methods (like in the given FighterListAdapter).

In the given use case you can implement the view holder as a static nested class. The Android docs and the blog entry on grokkingandroid.com are containing samples how the view holder may be implemented. Beside the view holder you're required to implement these methods:

  • onCreateViewHolder(...) which inflates your custom view element (see the given FighterListAdapter)
  • onBindViewHolder(...) which is doing the adaptation work to transfer the data from a Fighter instance to your view element using your custom view holder
  • getItemCount()

When you have completed the assignment the overall performance of the app should be much better.

Side note: Keep in mind that the image handling as it was accomplished in this assignment is not best practice but was just done this way to provoke performance problems. In real world applications you would just pass the id (using the R class) of an image resource to the ImageView to let Android care about loading the image.

A word about when to use a RecyclerView

The RecyclerView does not have to create 1000 objects of a row element when you have a list of 1000 items because it reuses (recycles) already existing row elements.

But there's still one problem: the RecyclerView does not affect the items in the list you want to display. Because of that even if you would have used the RecyclerView before you refactored the FighterFactory class the memory consumption of the app would have been (approximately) the same because all the images are loaded into the memory before the RecyclerView comes into play.

09-adapter-flyweight-android's People

Contributors

prskr avatar sikoried avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.