Showing posts with label tutorial. Show all posts
Showing posts with label tutorial. Show all posts

Sunday, July 31, 2016

Image loading with Glide


Image loading seems like an easy task at the first glance but as every task, it has its' own caveats.

First of all, you probably want to do this asynchronously because you don't want to flood your main thread with that kind of tasks.

Then, you want to cache images so you don't load them every time your activity of fragment resumes.

You need to handle error cases when the network is not available or server is sending you garbage or doesn't send anything at all. If you don't do this it will definitely harm the user-experience.

After all, you probably need to do some pre-processing steps before showing the image to the user such as cropping, resizing, reversing etc. Also, it would be convenient to have an easy way to set an image in an ImageView.

You may ask: "Why do you think that you know what I need and want?". The answer is that you're not alone. Android developers already made tons of apps that use pictures from the network.

And what happens when many developers are facing the same problem? Right, they make (most likely an open source) library.

The libraries

There are many libraries that solve the problem and, on the high level, they do it pretty much similar. For example, if you just want to load the image in the image view you will write something like this

String imageUrl 
    = "http://i1.kym-cdn.com/photos/images/facebook/000/002/109/orly_owl.jpg";
LibraryClass.with(context).load(imageUrl)
    .into(imageView);

No matter what concrete library you use (except it's something really exotic).

The most popular ones are Picasso, ImageLoader, Glide, and Fresco (made by Facebook). It's hard to say which one is the best one and developers say that picking one is the matter of taste. But I think that it's worth to mention that Gilde and Fresco support gif loading and Glide is recommended by Google.

Facebook engineers also say that Fresco is more optimized in terms of memory usage but when considering this note that Fresco is not as well tested as Picasso, Glide, and ImageLoader (which is the oldest one).

To show examples I will use Glide because I have been working with it.

Image Loading

First of all, to use Glide you need to add a Gradle dependency.

compile 'com.github.bumptech.glide:glide:3.7.0'

There are several ways you can use an image in your app. You can load it directly in an image view or save its' bitmap to use it anywhere else, for example, in a notification.

Let's consider first use-case. To simply load an image in an image view you must write exactly the code above except you must change LibraryClass to Glide that is it will look like this 

Glide.with(requester).load(imageUrl)
    .into(imageView);

I intentionally changed context to requester to emphasize that it could be not context. with() methods accepts Activity, Context, or Fragment as an argument which in my opinion is very handy.

There are many small features that will make UX of your app much better. For example placeholders, you definitely don't want your user to watch on the empty screen while your images are loading, your app should indicate that it's loading something to show to the user. Placeholders are the great way to do that. It can be a message that says that image is loading, loading animation or simple gray pane that shows that something should be there.

And placeholders are really well implemented in Glide (as well as other libraries) and it's easy to use. That's how it's done.

Glide
    .with(requester)
    .load(imageUrl)
    .placeholder(R.drawable.image_placeholder)
    .into(imageView);

You can show error image (the image that should be shown if something went wrong) using the same way

Glide
    .with(requester)
    .load(imageUrl)
    .error(R.drawable.image_error)
    .into(imageView);

In both of these methods, you can pass a Drawable object as the argument instead of resource id.

The second feature that can enhance UX of your app is animations. When your image appears out of nowhere in a blink of an eye it's kinda little disturbing and doesn't look like things act in the real world, which is a violation of Material Design guidelines.

In Glide as well as many other libraries there is a built-in way to animate the appearance of your images. In Glide you can do this using crossFade() method.

Glide
    .with(requester)
    .load(imageUrl)
    .placeholder(R.drawable.image_placeholder)
    .error(R.drawable.image_error)
    .crossFade()
    .into(imageView);

Also, you can pass an int as an argument to set the duration of the fade animation.

Load as Bitmap

To load image as bitmap you just need to use method asBitmap() set the constraints and use get() like this


Glide
    .with(requester)
    .load(imageUrl)
    .asBitmap()
    .placeholder(R.drawable.image_placeholder)
    .error(R.drawable.image_error)
    .into(width, height)
    .get();

Note that get() should be used only in a background thread which, in my opinion, is fair. If you don't use your image in UI why would you download it in UI thread?

Summary

Image loading includes many steps that cannot be removed from the process and these steps sometimes, not hard but dreary to implement. But the code as everything else ever written is (if properly constructed) reusable and programmers make new libraries every day since the beginning of the programming era.

Libraries as Glide make it possible to load images in just one line of code providing you with the instruments that will make your users' experience better. 

P.S. If you want to dive in and learn about Glide in details visit their javadocs and GitHub Wiki.

Sunday, July 24, 2016

Introduction to Firebase Database for Android



I've already written a post about Firebase and its' features but features highlighted in the post are additional to the core functionality of Firebase.

What is this core functionality? Well, this is the thing that Firebase started from. It's Realtime Database.

A real-time database is, basically, the database that can effectively store dynamic data. By dynamic, I mean data that is constantly changing for example stocks prices.

Firebase Database

So Firebase has its' own built-in real-time database which you can use as a backend for your app. Let's consider the structure of this database.

First of all, it's worth to mention that this database is not relational and doesn't use tables as you might expect. It uses JavaScript Object Notation (JSON) to store the data so it's kinda "object-oriented" database. 

I think that this it an advantage at least for developers because JSON, in my opinion, is easier to understand than relational tables if you're working within an object-oriented language. Also, using JSON eliminates some pitfalls that are associated with relational tables but, as always, brings some others.

The second important thing that Firebase Database is stored in the cloud and Firebase provides its' own hosting for it so you don't need to care about it. The amount of space you allowed to work with is described in your subscription plan.

And the most important feature in terms of development is that you can set data change listeners that will fire every time data in the database is changed and moreover give you a snapshot of changed node in the object tree.

Now when we have a big picture let's dive in and look how it works.

Closer Look

From this point, I assume that you have an account for Firebase.

First of all, we need to create our application.

App creation window

You can choose any name you like whereas app URL should be unique for every app registered in firebase. 

When you successfully created your app you can enter your dashboard and see an empty database.


Now you can go ahead and add some data directly from the dashboard or use the SDK to do so from your Android, iOS or Web app. Let's try do add something manually.

Manually added nodes

The important thing to notice that every node in the tree has its' own URL, we will use it later to refer to the concrete piece of data and attach a change listener to it.

Android SDK

For instructions on how to add Firebase to your Android app visit this page.

To use the database in our app we should add this gradle dependency in our app 
com.google.firebase-database:9.2.1

Now let's write some data to our database using Android app. One of the greatest things about this SDK is that you can write into the database using Plain Old Java Objects (POJO). This feature gives you an opportunity to keep your code clean and on the consistent level of abstraction.

Let's create POJO for our messages

public class Message {
    private String author;
    private String message;

    public Message (String auth, String msg) {
        this.author = auth;
        this.message = msg;
    }
    
    public String getAuthor() {
        return author;
    }

    public String getMessage() {
        return message;
    }
}

Note that for every field in Message class there is a public getter. It's a rule of SDK. If you don't have a public getter for some of the field you may get an exception so be sure to check that.

And the actual write method will look like this.

private void addMessage(String author, String message) {
    Firebase ref = new Firebase("https://tomasteryexmpl.firebaseio.com/chat/messages");
    Firebase messageRef = ref.push();

    messageRef.setValue(new Message());
}

It should be a method of the class that handles your database workflow. You can also pass composed Message object instead of author and message separately.

Let's do some clarifications. The ref variable stores a reference to the list of messages that we made earlier.

Method push() creates the unique key for the new entry in this list and returns its' reference in the database so messageRef stores reference to the new message.

When you have your reference you can easily write data to it using setValue(Object) method. And now you're done this method will successfully write your messages to the database and each message will have its' own unique key. Kinda easy, huh?

Let's look what happened to our data.

Added a message with unique code

Read the Database

In Firebase data reading differs from standard databases. To read from a database you should attach an asynchronous listener to the node you want to read. This listener will be triggered first time for initial state and every time data in this node is changed.

There are 2 types of listeners: ValueEventListener and ChildEventListener. The difference, basically, is that ValueEventListener will send you a snapshot of the whole object when it's changed while ChildEventListener will only send a snapshot of the changed child.

To listen for the messages it will be better to set a ChildEventListener to messages node so that we don't get the full list of messages every time a new message is sent.


private void setMessageListener() {
    Firebase ref = new Firebase("https://tomasteryexmpl.firebaseio.com/chat/messages");

    ref.addChildEventListener(new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot snapshot, String previousChildKey) {
            Message newMsg = snapshot.getValue(Message.class);
            addMessageToUI(newMsg);
        }
        //... ChildEventListener also defines onChildChanged, onChildRemoved,
        //    onChildMoved and onCanceled, covered in later sections.
    });
}

And that's pretty all that you need to do to set a child listener to a node. Now every time a message is added to the database addMessageToUI will be called and you will see your message in your app. There are libraries that can do that for you (like Firebase UI) but these are out of the scope of the post.

To get more information about reading the database visit this page in Firebase Docs.

This is pretty all that you need to know to build a basic Android messaging app. For me, it looks extremely easy in comparison to all the backend mess that you would set up without Firebase.


Sunday, July 17, 2016

What is Content Provider

Today I will continue my "What is *Android component*" series and tell you about one of the essentials parts of an Android application a content provider.

Previous posts from this series:
What is Activity
What is Fragment

The problem

First of all, let's consider the problem that this component is meant to solve.

It's often useful for applications to retrieve data from other apps on the smartphone. Many pre-installed Android apps have the data that can improve the user experience of other apps. 

For example, phone book has information about the people that are probably your friends and it can be used by social networking app like LinkedIn to connect with someone you know in this social network.

User dictionary has information that can help users type faster by providing them with the most used words when they use a custom keyboard.

So, it would be convenient to have some tool that can share those kinds of data.

Something that would provide a consistent interface across all the apps on an Android device.

The solution

The solution came from the pair Content Provider and Content Resolver. These 2 Android components not only solve the problem but give much more benefits for an Android developer, but first things first.

Content Provider

What is great in Android SDK is that most of the components' names speak for itself.

Basically, all the Content Provider does is provide access to the content of some app.

There is a database in the core of a Content Provider and Content Provider adheres concepts of encapsulation and hides the structure of the underlying database and provides its' own methods to work with it.

To request data from a Content Provider you should know a Uri so that it knows what kind of data you want. Usually, in the implementation, a content provider uses UriMatcher to distinguish different types of queries.

For example, you can request all weather for particular location using something like this content:/com.weatherpp.app/mounain_view but when you need weather for particular date you may need to use another Uri, probably something like this content:/com.weatherpp.app/mounain_view/06/17/16 and Content Provider is meant to understand what you want using this Uri and give you this data. (By the way, com.weatherapp.app part is called content authority)

Content provider should implement an interface that allows to insert, update and delete data from the database. To be precise, all content providers extend the ContentProvider class but I don't want to go into implementation details to keep things abstract and easy to understand.

Content Resolver

Content Resolver is a thing that determines which content provider to query using the Uri you give to it.

How does resolver do this? It's pretty easy, to be fair. Remember the content authority? This com.weatherpp.app thing. Before using a content provider you should register it in the system through your app's manifest and provide its' authority. And using this authority Content Resolver can understand which provider you want to use, somewhat similar to how a content provider decides what piece of data you want to query.

It's worth to mention that unlike content provider you don't need to implement content resolver. It's already implemented and built-in in the system. You can get it using context.getContentResolver() in your application.  

When to use Content Provider

So in which situations you should use content provider?

As I said, content provider gives many benefits to developers besides sharing data between apps. So in my opinion answer is: anytime you're working with a database.

To explain my answer, let me tell you about the benefits.

Abstraction

The first, and I think the most important, benefit is an additional level of abstraction between the database and an object using data.

Abstraction, as I see it, is always a good thing because it allows you to think in terms of the problem domain and not think about small, tricky details of implementation.

Encapsulation

This thing kinda supports abstraction, without encapsulation abstract things are not abstract.

Encapsulation also saves you from thinking about structure and implementation of your database operations.

Scalability

This is an outcome of abstraction. First of all, you can be sure that if you have different layers of abstraction changes in low-level implementation won't affect high level. 

So when you add a table to a database or new column to a table you don't need to change all the code that uses this database/table you simply change you provider's code or don't change anything at all.

Flexibility

Actually, you're not required to expose all your data to other apps if you're using content providers.

So you can use it for your convenience and if you want to expose it you can do it by changing only one line in the manifest. You change it and voila you have your very own API.

Consistency

If you use content provider you have a consistent interface for all your data operations such as insert, delete, and query. And it's consistent not only inside your application but inside the whole platform.

And as Reto Meier said once
If you chose to not use content providers, well you chose poorly.

Sunday, July 3, 2016

What is Fragment

The concept of a fragment is tied very tight with the concept of an activity. And if you don't understand clearly what activity is I encourage you to read last week's post first and then return to fragments.

Also, here's the post that will help you to get a nice overview of basic Android classes such as Context, Activity, Fragment, Thread etc.

What is the problem

With the growth of popularity of Android system more and more developers started to pay attention to it. More and more apps were developed for Android and it entailed more and more complexity in these apps. In particular, this complexity was growing in activities and layouts.

Possible solutions

First of all, developers wanted something that would be reusable in several activities. And this, as I think, gave a birth to ActivityGroup

As the documentation says it's
A screen that contains and runs multiple embedded activities
which seems like a bit overhead. In this implementation, every activity has its' own context, while developers wanted something that would be a part of one single activity context.

And with the arrival of tablets, this problem became more obvious. And at that moment of time Google introduced the fragment concept. Intentionally, fragments were designed to meet exactly the needs of tablet layouts, but now there are a plethora of use-cases for fragments. 

So what is Fragment

Fragment represents a behavior or part of the user interface in an activity. Multiple fragments can be used in one activity to represent different parts of the activity. Also, one fragment can be used in different activities.

A fragment itself doesn't know about other fragments in the activity part of which it appears to be.
By definition, it's independent part of an activity and can do its' job even without other fragments. So if you fall into a situation when one of your fragments depends on another fragment you should think about the design of your application.

A fragment always should be embedded in an activity and the activity's lifecycle actually defines the fragment's lifecycle. If an activity is on pause then all of its' fragments are on pause. If an activity is destroyed then all of its' fragments are destroyed. If an activity is running not all (if at all) of its' fragments are running, though.

While activity is running, a developer can manually and independently control the fragment's lifecycle. For example, he/she can add new fragment, or delete old one or pause it. 

Also, while doing these transactions it's possible to add them in the backstack so the user can revert a transaction by pressing "back" button.

And it worth to mention that fragments operate on the same level of abstraction as activities.

There are two types of fragments: static and dynamic.

Static fragments

Generally, static fragments are fragments that will not be replaced by other fragments during the lifecycle of an activity. To add an instance of this fragment to your activity you can use the <fragment> tag in the XML file that represents your activity's layout. And that's it your fragment will work as if it would be an activity. Also, using this approach you will be able to find this fragment using its' android:id.

Dynamic fragments

I think that the name is self-explanatory. Yeah, right, dynamic fragments are the ones that could be added, deleted and replaced while corresponding activity is running. These fragments are added in ViewGroup programmatically using FragmentManager. To refer to this type of fragments during runtime you would use a special tag that should be unique for every fragment in the activity.

A couple of use cases

The most popular and easiest use-case for fragments is the implementation of master-detail flow on tablets.

Master-detail flow is the technique that used in many mobile apps. Generally, it's when you have a list of items that describe something briefly and the screen that shows details of this something. For example, in an email app, you don't see a full email right away you see the title, maybe some text but you should tap on it to see details.



Usually, on smartphones, there is no place for both, master and detail layouts and these are separate activities. But tablets are much much bigger than smartphones so it's more convenient to have everything on one screen. Like in this picture.


So in this case, fragments perform like both: part of an activity and reusable parts. You can use detail fragment in smartphone and tablet layouts, but in smartphone layout, it will have

Also, fragments can be used without layout as a separate thread of your activity, but when do so remember that the fragment's lifecycle depends on the activity's lifecycle.

Wrap up

Fragments are powerful, as said with great power comes great responsibility and, in software development, complexity. But you don't need to understand all this complex underlying basements of fragment to take advantage of them.

For me, fragments were something that only sophisticates the structure of an application. But it was because the lack of understanding. Now I understand what is fragment and think that it's elegant solution to the problem that arose with the growth of Android system. 

And I hope that I tackled this lack of understanding for you. If I didn't and you still have questions fell free to ask in comment section below!

That's all for today, see you in the next one!

P.S. If you want to bee up to date about posts on this blog follow me on Twitter.

Sunday, June 26, 2016

What is Activity

Hi, today we will talk about one of the basal things in Android application an Activity.

How to understand an Activity

Activity is the basis of your application and entry point as well.

From the user side, it's a single focused thing that user can do while interacting with your application. Most of the Activities interact with the user and take care of creating a window for your UI. 

Also, using multiple Activities to represent various tasks helps a programmer to make app's code less complex and easier to maintain. 

Activities can be used as fullscreen or floating windows and as a part of another activity (in an ActivityGroup, note that it's deprecated since API 13).

Activity insights

Firs of all to start an activity you should define it in your manifest using <activity> tag inside <application>. Like this:

<manifest>
  <application>
      <activity android:name=".MyActivity" />

  </application>
</manifest >

Every class that extends Activity should implement these two methods
  1. onCreate(Bundle) - which is an entry point of your Activity, where you should initialize it (or recreate it we will talk about it later). You can think about it as a kind of constructor for your class. Usually, here we set an activity layout using setContentView(int) and set all the necessary fields including ones that relate to our layout using findViewById(int).
  2. onPause() - this one is called when the user leaves your Activity. At this point, you can save all data that can be necessary for future Activity launches (usually using ContentProvider which I will talk about in future posts).
There are many more events in Activity lifecycle, let's look at these.

Activity lifecycle

A set of activities is managed as a stack it means that when a new activity is started it is placed in the top of the stack and remains there until it destroyed or another activity is started. On the other hand, previous activities are below the new one in the stack and remains there while all the upper activities exist.

While in the stack, an activity can be in one of the four states.
  1. Activity is running (at the top). While in this state activity performs all the actions.
  2. Activity is not in focus but visible, or paused. It means that there's another activity that is semi-transparent or doesn't take all window's space so OS still should maintain UI of background activity. In this state, activity is still alive and can perform actions, but it's not recommended because it can be killed in the case of extremely low memory, while in this state. This is why we save all the data in onPause().
  3. Activity is not visible, or stopped. In this case, activity is still alive and still holds the state and member information, but there is more probability that it will be killed to free memory for something else.
  4. Activity is dropped, as I said OS can drop activity if it needs to free memory for something that has more priority. It does it by asking activity to finish, or simply killing its process (it's one of the reasons why you should save data before paused state). When the user decides to go back to this activity it's completely recreated, the developer should consider it and restore it to the previous state.
Here's a diagram from Activity documentation that shows most important parts (colored) of an activity lifecycle and all the methods that are called during this lifecycle. 
As you may see, activity exist even if app process killed it's just remaining in the activity stack and waits until the user navigates to it again, in this case, it should be recreated, using saved data. When activity is finished or system should completely destroy it, onDestroy() method is called and OS shutting it down.

In the onDestroy() method activity app should release all the remaining resources (close all the connections, shut down all the threads related to it etc.)  

Why lifecycle is so important

As I said, the system can decide to kill your activity if there's some higher priority process that requires memory. In this case, you should save your activity state in order to recreate it, when user will navigate to it again.

But this is not the only case when you should recreate an activity. Another reason to recreate it is configuration change.

Such things as orientation change, language change, or input devices plugging (like a keyboard) will cause your activity to go through its' lifecycle straight up to onDestroy() and after that system creates a new instance of your activity and calls onStart(Bundle) on it with savedInstanceBundle that contains the state of previous activity.

The reason to do so is quite simple. The fact is that in different configurations you app can use different resources, for example, you may want your app to look different in portrait and landscape orientations because in landscape you have more horizontal space.

However, you may want your app to not be recreated after some configuration changes. For example, if you don't care about whether a keyboard is plugged in or not (or you want to handle it yourself). 

In this case, you can tell the system to just warn your activity about a configuration change instead of killing it.

To do so you should use android:configChanges  attribute in activity's manifest to specify those changes. After that whenever specified configuration is changed onConfigurationChange(Configuration) will be called on your activity, and you can handle it yourself.

Also, activity's lifecycle in many ways controls lifecycles of all it's fragments (I will write about these in future posts).

Ways to save the state of an activity

I hope that when you have read the above, you have that one question. How to save the state of my activity? So if you do, read on.

There are two ways to do so. And these two ways should be used in different cases.

Case #1: You need to save some underlying information. Consider your user made some changes in his profile in this situation when the user leaves edit activity you should save all the applied changes to the database. Doing so you kill two birds with one stone. You update your database with new information and save the current state of your activity and when the user comes back to it the app will read it from the database.

As was said it's preferable to do in onPause(). It looks something like this.

@Override
protected void onPause() {
  super.onPause();
  //Always call the superclass method first, it performs operations required by system
  
  //Save applied changes to the database
  
}

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  // Read from database and populate the views
}

Case #2: You need to save the state of your UI. Let's refer to our example with edit activity. The user can start typing something in EditText and leave you application because of an important message or something, and when he returns he wants everything in text fields to be as he left it. To achieve this effect you should use onSaveInstanceState(Bundle) and populate the bundle with the data you need to save. 

Actually, SDK already takes care of it but if it didn't you would write something like this

@Override
public void onSaveInstanceState(Bundle outState) {
  outState.putString(EDIT_TEXT_STATE, mEdit.getText().toString());
  
  super.onSaveInstanceState(outState);
  //Call superclass method as well. As I said, it handles states of some elements for you.
}

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState); // Always call the superclass first
   
  // Check if there is a state Bundle
  if (savedInstanceState != null) {
    mEdit.setText(savedInstanceState.getString(EDIT_TEXT_STATE));
  }
}

Summary

It's pretty much all the basics of activities. With it, you can build activities that don't care if system kills them, they will stay in the state that they were left. For complete reference about activities visit the documentation page and the guide. Here you can learn about intent-handling and result activities.

See you next week, peace!

Saturday, May 7, 2016

Tutorial: Flexible Space With Image Action Bar

Android Support Library

Android Support Library provides many useful features for android developers and doing it with backward-compatibility in mind. Watch this video where Ian Lake explain why it's so good (it's just me or his smile looks terrifying? Leave your thoughts in the comment section).


As you may guess we'll use design part of this library, actually a small part of the design part. To be able to use it in your project you should add a gradle dependency.

compile 'com.android.support:design:23.3.0'

Flexible Space With Image is a scrolling technique that was presented as a part of the material design and Android Support Design Library makes it really easy to implement one and also makes it backward-compatible so you don't need to write a code mess to support it on each API.




We can achieve this effect with very small amount of java code using XML primarily.


We’ll use CoordinatorLayout, AppBarLayout, and CollapsingToolbarLayout.

CoordinatorLayout actually is what you probably think it is. It's layout that can coordinate its child layouts between each other. With other layouts from Support Desing Library, it provides an implementation of nice scrolling techniques of material design.


AppBarLayout is basically vertical LinearLayout that is ahead of the game. Its child elements can change behavior while scrolling. It provides full functionality only if it used as direct CollapsingToolbarLayout child.

And CollapsingToolbarLayout. This speaks for itself. It's a toolbar and it can collapse :). Remember that it's designed to be a direct child of AppBarLayout.  

Also, you'll want to use NestedScrollVIew or another scrollable layout to see all impact.

Let's continue to build the messaging app from the last tutorial, and we will make profile activity.

The XML code will be something like this

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    app:contentScrim="?attr/colorPrimary">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginBottom="32dp"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/strange"
                android:fitsSystemWindows="true"/>

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin" />

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

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

    <android.support.v4.widget.NestedScrollView
        android:id="@+id/scrollableView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

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

            <TextView
                android:id="@+id/number_textview"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="16dp"
                android:text="+1 234 5678 90" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Description"
                android:textColor="@android:color/black"
                android:textSize="20sp" />

            <TextView
                android:id="@+id/description_textview"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/strange" />
        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>

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

Let's talk about attributes.

I think that the most important one is layout_scrollFlags it determines how AppBarLayouts children will react to scrolling. There're 5 flags: scroll, enterAlways, enterAlwaysCollapsed, snap and exitUntilCollapsed.

layoutCollapseMode attribute will define how elements will behave while collapsing.

Here's how it looks.



By the way, you should use a theme without action bar for this code to work. Use theme like this.

<style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowActionBarOverlay">true</item>
        <item name="windowNoTitle">true</item>
</style>

And set theme attribute of your activity in AndroidManifest to AppTheme.NoActionBar

<activity
            android:name=".ProfileActivity"
            android:theme="@style/AppTheme.NoActionBar" />

There is a very few Java code that you need to write to make it perfect.

public class FlexibleActivity extends AppCompatActivity {

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

        //Initialize toolbar
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        //Set custom title
        toolbar.setTitle("Doctor Strange");

        setSupportActionBar(toolbar);
        //Show "back" button
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);


    }
}

It'll set the custom title in the toolbar and show back button to return to parent activity (if your activity has one).

In the end of the day, this will look like that.



Okay, that's all for today, feel free to ask any questions in the comment section below.

Stay tuned to learn more tweaks with CoordinatorLayout.

See you in the next one, peace!

P.S. You can look at my code on my GitHub repository

Saturday, April 30, 2016

Tutorial: Android ListView With Custom Adapter

There are so many apps utilizing ListView in Android. Your feed in a social network, your tasks in a to-do app, even your mail in your favorite email app stored in a ListView.


Basically, ListView is a container for a collection of items that can be represented as an array. You should be able to get any item from a collection by its index and get the size of an underlying collection. Also, it would be nice to be able to add new elements to your collection unless you want it to be constant.

In my opinion, ArrayList fits this definition perfectly. In ArrayAdapter, they use List as an underlying collection, though, but in some implementations of it (LinkedList for example) get operation is linear of index you pass to it, so it can be bad for performance. But it's not a reason to reject ArrayAdapter, just be careful with what implementation you pass to it.

Custom List Adapter

ArrayAdapter by default adapts only strings to TextViews, but we want something more interesting.

Let's say we are developing a messaging app and we want to show active conversations. We will represent our chat with this class.

public class Chat {
    private int mProfilePic;
    private String mName;
    private String mMessage;

    Chat(int profilePic, String name, String message) {
        mProfilePic = profilePic;
        mName = name;
        mMessage = message;
    }

    public int getProfilePic() {
        return mProfilePic;
    }

    public String getName() {
        return mName;
    }

    public String getMessage() {
        return mMessage;
    }
}


So we want our ListView to show some information besides strings. How do we do that?

Turns out it's not so complex if you know the basics!

There are several ways to achieve this goal. One of these is to use ArrayAdapter and override getView method (the simplest) and the other is to build your WhateverYouWantAdapter that will extend BaseAdapter class (the funniest).

Let's consider both approaches.

ArrayAdapter

There is a method getView in all adapters that returns the view of your list item.

By default ArrayAdapter just finds TextView passed as a parameter to its constructor and sets the text that is stored in underlying list (by the way if your objects are not Strings it just calls toString and makes them so). You can find this in source code (line 368 see createViewFromResource method).

So to implement custom ListView we just need to override this behavior. But wait a minute you also need some place to put your data in right. Let's build a simple layout that will represent our conversation.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp">
    <!--I'm using hdodenhof's library to make image circle-->
    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/profile_pic_imageview"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:scaleType="centerCrop"
        android:layout_marginEnd="8dp"/>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@android:color/black"
            android:textSize="20sp"
            android:layout_marginBottom="12dp"/>
        <TextView
            android:id="@+id/message"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp"/>
    </LinearLayout>
</LinearLayout>

Where is Harry?

So here we have our friend's profile pic, his name and last message received from him.

In our getView method, we need to get access to them and set values.

public class ChatAdapter extends ArrayAdapter<Chat> {

    public ChatAdapter(Context context, int resource, ArrayList<Chat> data) {
        super(context, resource, data);
    }

    public View getView(int position, View view, ViewGroup parent) {
        //Get the instance of our chat
        Chat chat = getItem(position);

        LayoutInflater inflater = (LayoutInflater) getContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE );

        //Create new list item
        View rowView = inflater.inflate(R.layout.list_item, null, true);

        //Get UI objects
        ImageView profilePic = (ImageView) rowView.findViewById(R.id.profile_pic_imageview);
        TextView nameView = (TextView) rowView.findViewById(R.id.name);
        TextView messageView = (TextView) rowView.findViewById(R.id.message);

        //Set image profile picture
        profilePic.setImageDrawable(getContext().getResources().getDrawable(chat.getProfilePic()));

        //Set text into TextViews
        nameView.setText(chat.getName());
        messageView.setText(chat.getMessage());

        return rowView;
    }

}


After that just make some test data and set your adapter to the list, everything else will be handled by Android.

ArrayList<Chat> chats = new ArrayList<>();
chats.add(new Chat(R.drawable.hermione, "Hermione Granger", "Harry! Where are you? " +
                "Dambledore is looking for..."));
chats.add(new Chat(R.drawable.ginger, "Ron Weasley", "Wingardium leviosaaaaaaaaaaaaaaaa"));
chats.add(new Chat(R.drawable.snape, "Severus Snape", "Well, it may have escaped your " +
                "notice, but life is not ..."));
chats.add(new Chat(R.drawable.iman, "Tony Stark", "I don't know why I'm even chatting with you"));

ChatAdapter adapter = new ChatAdapter(this, R.id.listview_chats, chats);

ListView chatList = (ListView) findViewById(R.id.listview_chats);
chatList.setAdapter(adapter);

BaseAdapter

This approach is manual but it's also fun because you will build your very own adapter and will understand deeply how adapters work.

The main idea is the same to override some methods in BaseAdapter they are not even implemented, so, we will do it manually. Also in the BaseList, there is no any underlying collection to store data, it means we need to make out own.

Let's use the same layout for list items. For our adapter to work we need to implement getView, getItem, getItemId, getCount methods. But before diving in the code let's consider what these should do.

  • getView(int position, View view, ViewGroup parent): for the getView idea is the same as for ArrayAdapter it should return our list item layout.
  • getItem(int pos): this method should return an instance of the object we store in list item in pos position. 
  • getItemId(int pos): you need this when for example when you use a database to retrieve items for your list, it just makes it easier to get item's id in this database. We need to implement to make our adapter work, let's just return 0 from it.
  • getCount(): this method just returns number of elements in your list

public class ChatAdapter extends BaseAdapter {
    private final Activity mContext;
    private final ArrayList<Chat> mChats;
    private final Resources mRes;
    private final LayoutInflater mInflater;

    public ChatAdapter(Activity context, ArrayList<Chat> chats) {
        mContext = context;
        mChats = chats;
        mRes = mContext.getResources();
        mInflater = mContext.getLayoutInflater();
    }

    @Override
    public int getCount() {
        return mChats.size();
    }

    @Override
    public Chat getItem(int pos) {
        return mChats.get(pos);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    public View getView(int position, View view, ViewGroup parent) {
        //Get the instance of our chat
        Chat chat = mChats.get(position);

        //Create new list item
        View rowView = mInflater.inflate(R.layout.list_item, null, true);

        //Get UI objects
        ImageView profilePic = (ImageView) rowView.findViewById(R.id.profile_pic_imageview);
        TextView nameView = (TextView) rowView.findViewById(R.id.name);
        TextView messageView = (TextView) rowView.findViewById(R.id.message);

        //Set image profile picture
        profilePic.setImageDrawable(mRes.getDrawable(chat.getProfilePic()));

        //Set text into TextViews
        nameView.setText(chat.getName());
        messageView.setText(chat.getMessage());

        return rowView;
    }

}

And now you can use you newborn adapter just as ArrayAdapter

There is a little bit different constructor so you should change one line of code just write
ChatAdapter adapter = new ChatAdapter(this, chats);
Instead of
ChatAdapter adapter = new ChatAdapter(this, R.id.listview_chats, chats);

Result

Stop! Tony Stark???
Both approaches led me to this view. It's pretty much it. I think we've got nice cosy layout and our users will be satisfied :)

Summary

Of course, it's better to use an ArrayAdapter but I didn't include BaseAdapter part "just because". I think it will deepen your understanding of how does ListAdapter works and will encourage you to learn how things work internally in Android.

Now I'm looking forward to writing more tutorials, so stay tuned. See you next week, peace!

P.S. You can look at my code on my GitHub repository