Pagination allows loading a long list of data in chunks. You see this in action in news feeds in social media apps, otherwise known as endless or infinite scrolling. In this tutorial, I will specifically show you how to handle pagination with Swipe-to-Refresh involved.
(more…)Category: Android
-
Customize Color with Styled Google Maps in Android
You can now style and customize your Google Maps colors and more. In this Android tutorial, let’s see how we can do that in our apps.
Google Maps has added this ability across all platforms. This means regardless of whether you use Google Maps for Web, iOS or Android, you’ll be able to style them.
By default, Google Maps looks like this.
Default Google Maps We’re all used to this and by no means am I saying it looks bad. But say I want to display a map that corresponds to my brand color scheme.
Directions Module by David Rodriguez Now imagine if my only option was to display the default Google maps, with it’s default colors. It wouldn’t go well with the design, would it? The color scheme of the map won’t be in harmony with the rest of the design. In other words, it sticks out, like a sore thumb.
In such scenarios, we need a map that reflects our brand theme. Our brand color palette. This wasn’t possible before.
But now, Google allows Styled maps. Using this, we can customize the map to look the way we want. This includes modifying colors, with a very high degree of control.
Getting Started
We’ll start by creating a new Android Studio project. Thankfully, we have pre-defined templates (for Activities) to start with. Activity templates were introduced in Android Studio 1.4.
So when you create a new project, chose the ‘Google Maps Activity’ template.
Android Studio – Activity Templates Here are the project settings:
- minSdkVersion – 14
- targetSdkVersion – 26
Thanks to this, we don’t have to spend a lot of time configuring the Maps SDK and whatnot. I remember the first time I tried using Maps in Android (back in 2012). It took me well over an hour to simply display a Map!
But you don’t have to worry anymore as we’ve come a long way from that!
Configuring Google Maps
Once the project has loaded, Android Studio will open the google_maps_api.xml file by default.
Auto-generated maps_api.xml You’ll notice there is one step to follow to get your Google Maps API Key. Trust me, this is nothing compared to the amount of steps earlier!
So follow the comments on the file. Don’t worry, I’ll still walk you through them. but you’ll have to grab the URL and keys from the google_maps_api.xml file’s comments.
1. Go to the URL provided – console.developers.google.com
You’ll land on a page like this.
Create a new project in Google Developer Console Select ‘Create a Project’ from the dropdown and then hit the Continue button.
2. Create Google Maps API Key
In the next step (screen), click the ‘Create API Key’ button.
Creating new API key… 3. Get your generated API Key
Google now generated your Maps API key. So copy it and paste it in your XML file for the string name ‘google_maps_key’. Replace the ‘YOUR_KEY_HERE’ with your actual API key!
You can optionally set up API Key restrictions if you want (see screenshot above). It’s fairly simple. Click restrictions and you’ll get a screen like this.
Generated API key restrictions Choose ‘Key restriction’ as ‘Android Apps’ and hit Save button. Note that you don’t have to bother about the Package name and SHA-1 certificate fingerprint. You’ll realize that the fingerprint is same as the one in your Android Studio project comments.
In other words, Google took care of that for you too. Sweet? Now let’s move on.
With our API key in place, we’re finally ready to use Google Maps.
But before we get to styling, let’s check if Maps itself works. So run your app and check it out.
It’s always better to test every step of the way. Otherwise, you’ll never know what went wrong where.
NOTE:
Google Maps needs Google Play Services to work. So it’s safe to always run the app on a real device. Or, you can configure and use an AVD that includes Google APIs with Play Services.Here’s how Google Maps loads on my phone.
Default Google Maps – Android It works just fine. So let’s finally move on to styling it.
Using Styled Maps
Google Maps can load styling options via two different formats:
1 – JSON file
You load the JSON file in the onMapReady() method.
@Override public void onMapReady(GoogleMap googleMap) { try { // Customise map styling via JSON file boolean success = googleMap.setMapStyle( MapStyleOptions.loadRawResourceStyle( this, R.raw.style_map_json)); if (!success) { Log.e(TAG, "Style parsing failed."); } } catch (Resources.NotFoundException e) { Log.e(TAG, "Can't find style. Error: ", e); }
- String resource Using a string resource works in a similar way.
@Override public void onMapReady(GoogleMap googleMap) { try { // Customise map styling via String resource boolean success = googleMap.setMapStyle(new MapStyleOptions(getResources() .getString(R.string.style_json))); if (!success) { Log.e(TAG, "Style parsing failed."); } } catch (Resources.NotFoundException e) { Log.e(TAG, "Can't find style. Error: ", e); }
Now we know how to load our Map styles. But how do we actually create our style? Let’s look at that next.
Creating a Color Theme for Google Maps
I’ll put it bluntly. There are two ways you can go about it.
One, write a JSON file. Manually writing every property (do you even know them?).
Or two, using the Map Styling Wizard.
In other words, save yourself time and frustration. Go with the second option. Use the Styling Wizard. It’s a no-brainer. Seriously!
Google Maps Styling Wizard
Welcome to Google Maps Styling Wizard For this part, you just play around with the Styling Wizard. Adjust the density of features depending on how much detail you want on the map. Then select a basic, pre-defined theme to work with. Finally, you can click on ‘MORE OPTIONS’ to alter the properties of each Map object. Trust me, there’s a LOT of things you can customize that it’s easy to get lost.
Abundant customization options in Map Styling Wizard I’ve chosen very light, pastel-like colors for the map. These are colors mainly for the terrain, parks, water and highways.
Once you’re done, click the FINISH button. Next, copy the JSON from the popup that appears.
Auto-generated JSON from Styling Wizard Head over to your Android Studio project and create a new file under Project/app/src/main/res/raw/maps.style.json.
This JSON file is where we’ll paste the JSON copied from the Maps Style Wizard. Now all that’s left is to tell Google Maps to load its style from this JSON file.
Remember we spoke about how to do this in the
onMapReady()
method?Let me remind you again. Now that we have our JSON file ready, we can call it in like this.
Open MapsActivity.java and go to the
onMapReady()
method. The template has this method already implemented for you.So with the default template existing, here’s how to load the Styled Map.
@Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; try { boolean success = mMap.setMapStyle( MapStyleOptions.loadRawResourceStyle( this, R.raw.maps_style)); if (!success) { Log.e(TAG, "Style parsing failed."); } } catch (Resources.NotFoundException e) { Log.e(TAG, "Can't find style. Error: ", e); } ... }
It’s actually just one line of code. The try catch block just makes it look verbose.
With Styled Maps now loaded, run your app and check it.
Styled Maps – Output
Based on the colors I chose against a Grey- themed Google Map, mine looks like this.
My custom styled Google Maps I changed parks to purple color. Just so I visually know that Styled maps are working. I know it’s an ugly map. But I’m sure you can do better!
Wrap Up
In this Android tutorial, we saw how to Style our default-looking Google Maps.
First, we created an Android Studio project, using the Maps Activity template. We then created an API key to use with Maps.
Next, we used the Maps Styling Wizard to configure Google Maps to our liking. Then, we pasted the generated JSON over to our project. Finally, we told Google Maps to load its styling from that JSON file.
Where to from here?
That’s all there is to it! With Styled maps, it is now possible to customize Google Maps to be more relevant to your app color-scheme. No more out-of-place looking Maps. If used properly they can now blend well with your UI designs.
How are you going to customize your map? I’m very interested to see what you’ll come up with. Show me in the comments below.
Header Image Credits: Asar Morris
-
Android O Tutorial: Supporting Picture-in-Picture (PIP)
Picture in Picture or PIP is a feature famously seen on YouTube and Android TV apps. It minimizes your content (typically video), keeping it pinned to a corner while you carry out your other tasks.
In other words, the video keeps playing in the corner, while you continue using the app.
What’s Picture-in-Picture?
Picture-in-picture mode lets apps run a video activity in the pinned window while another activity continues in the background. – developer.android.com
Let me rephrase that for you. Open YouTube and watch a video. You’ll notice you can minimize that video and continue to watch it whilst using the app.
PIP in YouTube app Recently, even Facebook added it. You can minimize a video and continue watching it, while you’re scrolling through your newsfeed. Sweet!
PIP in Facebook
Until now, to implement such a feature, Android Developers like you and I had two options:
- Write our own – won’t come off pretty
- DraggablePanel – works fine
Yep, I heard you. DraggablePanel was our only choice. While that was and is a fine library, I’d say there’s a better option today.
Picture in Picture with Android O
When Android Nougat came, we saw PIP support for Android TV. It was only a matter of time when it came to mobile. Finally, in the next version, Android O added support for mobile too!
In this article, I’ll tell you how to enable support for mobile. Developers who have worked on Android TV with Nougat should feel right at home. But don’t worry if you haven’t. You’ll be able to follow along just as easy.
Getting Started – Project Setup
To use all of Android O’s features properly, you need Android Studio 3.0 Preview. This works as a standalone install compared to your existing, stable Android Studio.
If you already have all of that setup, then feel free to go ahead with this tutorial.
If you haven’t setup Android Studio 3.0 Preview, I strongly recommend you go through the Android O: Getting Started article first. It covers how to setup Android Studio Preview to use API 26.
Anyways, for your reference, here’s what we’ll be using:
- Android Studio 3.0 Preview
- Gradle version – 3.0.0-alpha4
- compileSdkVersion – 26
- buildToolsVersion – 26.0.0
- Support Library Version – 26.0.0-beta2
You can use these to update your Gradle build accordingly.
Lastly, make sure you’re using Google’s maven repository. Open your project-level build.gradle file.
buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.0.0-alpha4' } } allprojects { repositories { google() jcenter() } } // ...
Adding PIP Support on Android
First, we need to create an
Activity
and declare that it supports picture-in-picture. So go ahead and create a newActivity
. I call mine PipActivity.java.Next, open your AndroidManifest.xml. Here, we’ll declare that PipActivity supports Picture-in-Picture. We do so by using the
supportsPictureInPicture
attribute.<activity android:name=".PipActivity" android:launchMode="singleTask" android:supportsPictureInPicture="true" android:theme="@style/AppTheme.NoActionBar" />
NOTE:
Developers who have worked with Android Nougat for TV might notice that theresizeableActivity
attribute is no longer required for PIP. However, keep in mind that if you setresizeableActivity
to false, then thesupportsPictureInPicture
attribute is ignored.Handling Activity Duplication and Recreation
Notice the
launchMode
attribute in the Manifest. Any guesses why it’s required?Avoiding Activity Duplication – Using Launch Modes
The Launch Mode singleTask tells Android that there should be only one instance of that Activity.
In other words, if I keep starting PipActivity, only one instance of it should open. There should never be any duplicates.
This scenario is highly likely and is mandatory that you handle it.
For example, take the YouTube app. You’re browsing through a playlist and you open a particular video. Then, if you enter PIP mode, you’re back to the playlist screen. Now, if you click the same video again, we want the existing video to enlarge back up. Or, if you click another video, we want PIP to maximize with the clicked video playing. We do not want another (PIP) screen to open.
The singleTask Launch Mode handles this for us.
Preventing Activity Recreation
If you’re that daring person who wants to support PIP and orientation changes, then you’ll need one extra attribute.
Add the configChanges attribute to your Manifest to prevent PipActivity from being recreated each time on orientation change.
This will be extremely handy when your PiP includes a player (which will most likely be the scenario).
Starting Picture-in-Picture mode
Now that we’ve prepared our
Activity
, the next step is to trigger PIP mode.So to do that, we need to create a simple layout first. Open your Activity’s XML layout.
XML Layout
Honestly, I leave this to your imagination. But for the sake of this tutorial, I’m going to pretend we have a UI that includes a player.
PIP XML layout The layout is very simple. Here’s the XML code for the same.
<FrameLayout android:id="@+id/frame_mock_player" android:layout_width="match_parent" android:layout_height="@dimen/app_bar_height" android:background="@color/colorAccent"> <ImageButton android:id="@+id/btn_minimize" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top|start" android:layout_margin="@dimen/layout_margin" android:background="?selectableItemBackgroundBorderless" android:src="@drawable/ic_picture_in_picture_alt_black_24dp" android:tint="@android:color/white" /> <!--Other Player UI here--> </FrameLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="#EFEFEF"> <!--Video details UI here--> </FrameLayout>
In short, we have a
FrameLayout
that would be our player. We also have a button that indicates switching to Picture in Picture mode.You can add that icon via a right click on res/drawable folder> New> Vector Asset. In this way, you can choose from the entire set of Google’s Material Design icons.
TIP:
These icons that you import are by default, black in color. So make sure to tint vector icons for pre-Lollipop devices.Triggering PIP
With the layout complete, it’s now time to start Picture-in-Picture. So to do that, head over to PipActivity.
PiP is triggered when we click the button on the top-right. So we’ll write our entire logic inside that button’s click listener.
mBtnPip.setOnClickListener(view -> { if (android.os.Build.VERSION.SDK_INT >= 26) { //Trigger PiP mode try { Rational rational = new Rational(mFramePlayer.getWidth(), mFramePlayer.getHeight()); PictureInPictureParams mParams = new PictureInPictureParams.Builder() .setAspectRatio(rational) .build(); enterPictureInPictureMode(mParams); } catch (IllegalStateException e) { e.printStackTrace(); } } else { Toast.makeText(PipActivity.this, "API 26 needed to perform PiP", Toast.LENGTH_SHORT).show(); } });
There are a couple of things going on here, so let’s tackle it one at a time.
If you’ve seen the PIP animation, notice that the ‘ratio’ the player maintains when maximized and minimized, are the same.
So it’s essential that we do the same. You can simply enter Picture-in-Picture mode using
enterPictureInPictureMode()
. But you can pass in some optional parameters if you wish. That’s what we’re doing here.We will maintain the ratio of our dummy player to be the same in PIP mode. For that, we need to pass a
PictureInPictureParams
object.NOTE:
I’m triggering PIP mode only for API 26 and above. Ideally, as a fallback, you must hide or disable this feature. For the sake of this tutorial, I’m displaying aToast
message.
Best Practices
Now that we’ve seen how to launch PIP, there are a couple of things to keep in mind.
Adapting UI to PIP mode
When in PIP mode, avoid displaying any UI controls except the video player.
When PipActivity enters PIP mode, we need to hide everything displayed except the video. So to do that, we need some way to know that we’re currently in PIP.
We can detect when an
Activity
enters Picture-in-Picture using theonPictureInPictureModeChanged()
method.In our case, the only UI control we need to hide is the PIP
ImageButton
on the top-left.@Override public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) { super.onPictureInPictureModeChanged(isInPictureInPictureMode); if (!isInPictureInPictureMode) { mBtnPip.setVisibility(View.VISIBLE); } else { mBtnPip.setVisibility(View.GONE); } }
TIP:
You can overrideonPictureInPictureModeChanged()
either in yourActivity
orFragment
.Updating PIP Content
Remember we discussed the importance of
singleTask
Launch Mode to avoid duplicate PIPs? I even used the YouTube app as an example.If you think carefully about that example, there’s one thing that we don’t know how to handle. When we’re in PIP, and we click on another content, we solved the duplication problem. But PIP must be updated with the content that we clicked. How can we do that?
Use the
onNewIntent()
method to update your PIP with the new content data.Managing Playback
Once our
Activity
goes into PIP mode, we need to ensure that the content playback continues.NOTE:
When you switch to PIP mode, Android considers thatActivity
to be in a paused state. Hence it calls that Activity’sonPause()
method.Forget PIP for a second. If your
Activity
goes intoonPause()
, then ideally, you’ll pause your playback too. But if you’re in PIP mode, make sure you don’t pause playback.Android’s given us a handy method
isInPictureInPictureMode()
that we can use to handle this.@Override protected void onPause() { super.onPause(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && isInPictureInPictureMode()) { // Continue playback... } // Not in PIP & Activity is paused. Pause playback if required.... }
Output
Finally, we’ve done everything that’s needed to make Picture in Picture work. We’ve also made sure to handle its common scenarios. Let’s see how it works.
Make sure you create an Android Emulator (AVD) that runs API 26 (Google Play System Image). Once you’ve done that, run your app. You should get a working PIP like this.
Wrap up
Picture-in-Picture was finally brought to Android Smartphones thanks to Android O. In this article, we briefly saw how to prepare Android Studio to use the latest Android O SDK (API 26). Then we learnt how to use PIP.
Although PIP is generally used for video playing content, this tutorial excluded a guide for video playing. This was done to ensure the focus stays on Picture in Picture.
SOURCE CODE:
Sample working Project available on GitHub.Where to from here?
Remember, there is no hard and fast rule that PIP must only be used for video playing content. Its usage is only restricted to your imagination.
How will you use PIP in your app? Have any questions? Let me know in the comments below.
Lastly, if you liked reading this, don’t forget to share (on the left). If you want updates on the next article, subscribe below.
-
Android Architecture Components Tutorial – Room, LiveData and ViewModel
During the concluded Google I/O 2017, there were some amazing announcements about Android. Say hello to Android Architecture Components. For once, these are announcements that ease our lives as Android Developers.
Android Architecture Components
A new collection of libraries that help you design robust, testable, and maintainable apps. – developer.android.com
It helps us developers address two pain points:
- Manage our UI components lifecycle
- Persist data over configuration changes
In fact, these are the two biggest problems we Android Developers face. Period.
Maintaining data over orientation changes and handling our objects with lifecycle is hard. That’s why, to avoid the hassle, you lock your apps in Portrait mode, don’t you? Don’t lie. Even I’ve done it.
But don’t worry, Android Architecture Components will help alleviate both our fears.
There are 3 main architecture components:
- Room
- LiveData
- ViewModel
So first, let’s find out what these components actually are. Then, we’ll learn how we can use them.
We’ll even make a handy app that keeps track of what people borrow. This will help us learn better about how all these 3 components work together.
Room
Remember the amount of boilerplate code you had to write to create and manipulate even a very small database? You had to define the database structure, create an SQLiteHelper class etc.
Room is a library that saves you all such trouble. Now you can query your data without having to deal with cursors or loaders. You can define your database by adding annotations in your Model class. Yes, it’s that simple.
If you’ve used third-party ORMs like Sugar, you’ll feel right at home here. In fact, from now on, I wouldn’t even want to use one. Room is that brilliant! Why would you want to use a third-party library, when the official Android libraries give you an equal, or if not, better solution.
Architecture
In this app, we will follow an architecture called MVVM – Model View ViewModel.
In MVVM, the
ViewModel
exposes the required data and interested parties can listen to it.But you don’t have to worry. We’ll do a simple implementation for this article. You’ll have no problem following.
So in our case, the
Activity
will listen on the data and make changes in the UI.
Getting started
Create a new project in Android Studio.
First, Add Google’s maven repository to your project-level build.gradle file.
//... allprojects { repositories { jcenter() maven { url "https://maven.google.com" } } } //...
Next, add the following dependencies for Room in your app-level build.gradle file.
compile "android.arch.lifecycle:extensions:1.0.0" compile "android.arch.persistence.room:runtime:1.0.0" annotationProcessor "android.arch.lifecycle:compiler:1.0.0" annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
Creating the Model
Create a class called BorrowModel.
import java.util.Date; @Entity public class BorrowModel { @PrimaryKey(autoGenerate = true) public int id; private String itemName; private String personName; @TypeConverters(DateConverter.class) private Date borrowDate; public BorrowModel(String itemName, String personName, Date borrowDate) { this.itemName = itemName; this.personName = personName; this.borrowDate = borrowDate; } public String getItemName() { return itemName; } public String getPersonName() { return personName; } public Date getBorrowDate() { return borrowDate; } }
You might see an error at DateConverter.class. But don’t panic, we’ll create that next. So for now, pay attention to the Annotations used here.
We use the
@Entity
annotation to tell Room to use the current class as a database table.Any attribute preceded by the
@PrimaryKey
annotation will serve as a primary key for the table. Here we use'autoGenerate = true'
so that the key is automatically generated every time an entry is made.SQL cannot store data types like
Date
by default. That’s why we need a way to convert it into a compatible data type to store it in the database. We use the@TypeConverters
to specify the converter for theborrowDate
attribute. So to help us with this conversion, we’ll create a class called DateConverter.NOTE:
Make sure to importjava.util.Date;
import java.util.Date; class DateConverter { @TypeConverter public static Date toDate(Long timestamp) { return timestamp == null ? null : new Date(timestamp); } @TypeConverter public static Long toTimestamp(Date date) { return date == null ? null : date.getTime(); } }
As you can see, the class just converts
Date
toLong
and vice versa.Data Access Object
Next up, we need to create a DAO – Data Access Object class. This class will be used to define all the queries we will perform on our database.
@Dao @TypeConverters(DateConverter.class) public interface BorrowModelDao { @Query("select * from BorrowModel") LiveData<List<BorrowModel>> getAllBorrowedItems(); @Query("select * from BorrowModel where id = :id") BorrowModel getItembyId(String id); @Insert(onConflict = REPLACE) void addBorrow(BorrowModel borrowModel); @Delete void deleteBorrow(BorrowModel borrowModel); }
We use
@Dao
to tell Room that this is a DAO class.We define our queries as strings and pass them as a parameter to
@Query
. Each@Query
annotation is paired with a method. When the paired method is called, the query gets executed.Next, we use the
@Insert
annotation for methods that insert entries into the table. We can similarly use@Delete
and@Update
for deletion and update methods respectively.In case there are conflicts during such manipulation operations, we have to specify a conflict strategy too. In our example, we are using REPLACE. It means that the conflicting entry will be replaced by the current entry.
Make sure you import REPLACE correctly using
import static android.arch.persistence.room.OnConflictStrategy.REPLACE;
Creating the database
Now, all we need to do is create a RoomDatabase class. So create an abstract class called AppDatabase.
@Database(entities = {BorrowModel.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { private static AppDatabase INSTANCE; public static AppDatabase getDatabase(Context context) { if (INSTANCE == null) { INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "borrow_db") .build(); } return INSTANCE; } public abstract BorrowModelDao itemAndPersonModel(); }
We annotate the class with
@Database
which takes two arguments:- An array of the Entity classes(the tables)
- The database version which is just an integer.
This class is used to create the database and get an instance of it. We create the database using
Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "borrow_db") .build();
The arguments are:
Context
- Your database class
- Name to given to the database
TIP:
We have to create an abstract method for every DAO class that we create. This is really important.And that’s it. Our database is ready to roll.
ViewModel
Earlier in the post, we mentioned
ViewModel
. ViewModels are entities that are free of theActivity
/Fragment
lifecycle. For example, they can retain their state/data even during an orientation change.ViewModels do not contain code related to the UI. This helps in the decoupling of our app components.
In
Room
, the database instance should ideally be contained in a ViewModel rather than on theActivity
/Fragment
.Create the AndroidViewModel
We create a ViewModel for our borrowed items.
public class BorrowedListViewModel extends AndroidViewModel { private final LiveData<List<BorrowModel>> itemAndPersonList; private AppDatabase appDatabase; public BorrowedListViewModel(Application application) { super(application); appDatabase = AppDatabase.getDatabase(this.getApplication()); itemAndPersonList = appDatabase.itemAndPersonModel().getAllBorrowedItems(); } public LiveData<List<BorrowModel>> getItemAndPersonList() { return itemAndPersonList; } public void deleteItem(BorrowModel borrowModel) { new deleteAsyncTask(appDatabase).execute(borrowModel); } private static class deleteAsyncTask extends AsyncTask<BorrowModel, Void, Void> { private AppDatabase db; deleteAsyncTask(AppDatabase appDatabase) { db = appDatabase; } @Override protected Void doInBackground(final BorrowModel... params) { db.itemAndPersonModel().deleteBorrow(params[0]); return null; } } }
Every ViewModel class must extend the
ViewModel
class. If the ViewModel needs the application context, then it must extend theAndroidViewModel
class. The ViewModel will contain all the data needed for ourActivity
. In our example, we are using something called LiveData.LiveData is a wrapper that lets interested classes observe changes in the data inside the wrapper.
We wrap our list of borrowed items inside LiveData so that the
Activity
can observe changes in the data and update the UI.In our ViewModel, we first get an instance of our database using
AppDatabase.getDatabase(this.getApplication())
First, we need to load the list of borrowed items from the database. For that, we should use the query we defined in the DAO class,
getAllBorrowedItems()
.Next, call the abstract method we created for DAO and then call the query method. Refer to this snippet in the
BorrowedListViewModel
class.appDatabase.itemAndPersonModel().getAllBorrowedItems();
Now since we will be displaying a list of items, we need a
RecyclerView
. So first, let’s create an adapter for the same.public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder> { private List<BorrowModel> borrowModelList; private View.OnLongClickListener longClickListener; public RecyclerViewAdapter(List<BorrowModel> borrowModelList, View.OnLongClickListener longClickListener) { this.borrowModelList = borrowModelList; this.longClickListener = longClickListener; } @Override public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new RecyclerViewHolder(LayoutInflater.from(parent.getContext()) .inflate(R.layout.recycler_item, parent, false)); } @Override public void onBindViewHolder(final RecyclerViewHolder holder, int position) { BorrowModel borrowModel = borrowModelList.get(position); holder.itemTextView.setText(borrowModel.getItemName()); holder.nameTextView.setText(borrowModel.getPersonName()); holder.dateTextView.setText(borrowModel.getBorrowDate().toLocaleString().substring(0, 11)); holder.itemView.setTag(borrowModel); holder.itemView.setOnLongClickListener(longClickListener); } @Override public int getItemCount() { return borrowModelList.size(); } public void addItems(List<BorrowModel> borrowModelList) { this.borrowModelList = borrowModelList; notifyDataSetChanged(); } static class RecyclerViewHolder extends RecyclerView.ViewHolder { private TextView itemTextView; private TextView nameTextView; private TextView dateTextView; RecyclerViewHolder(View view) { super(view); itemTextView = (TextView) view.findViewById(R.id.itemTextView); nameTextView = (TextView) view.findViewById(R.id.nameTextView); dateTextView = (TextView) view.findViewById(R.id.dateTextView); } } }
Creating the Android LifecycleActivity
It’s a pretty straightforward adapter. So I won’t be getting into the details of it. But if you’re interested in how
RecyclerView
works, this Android tutorial tells you how to create aRecyclerView.Adapter
.Now create an
Activity
that extendsLifecycleActivity
to display a list of all the borrowed items.LifecycleActivity
is a class that provides us with the state of the lifecycle.public class MainActivity extends LifecycleActivity implements View.OnLongClickListener { private BorrowedListViewModel viewModel; private RecyclerViewAdapter recyclerViewAdapter; private RecyclerView recyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { startActivity(new Intent(MainActivity.this, AddActivity.class)); } }); recyclerView = (RecyclerView) findViewById(R.id.recyclerView); recyclerViewAdapter = new RecyclerViewAdapter(new ArrayList<BorrowModel>(), this); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(recyclerViewAdapter); viewModel = ViewModelProviders.of(this).get(BorrowedListViewModel.class); viewModel.getItemAndPersonList().observe(MainActivity.this, new Observer<List<BorrowModel>>() { @Override public void onChanged(@Nullable List<BorrowModel> itemAndPeople) { recyclerViewAdapter.addItems(itemAndPeople); } }); } @Override public boolean onLongClick(View v) { BorrowModel borrowModel = (BorrowModel) v.getTag(); viewModel.deleteItem(borrowModel); return true; } }
NOTE:
Whenever we need to use ViewModels inside ourActivity
, theActivity
must extendLifecycleActivity
.Creating a ViewModel is simple.
viewModel = ViewModelProviders.of(this).get(BorrowedListViewModel.class);
The two parameters are:
- Context
- The ViewModel class
Now we need to make our
Activity
observe the changes in the ViewModel. So first, get a reference to the LiveData inside the ViewModel. Then, add anobserve()
method to the reference.The
observe()
method takes 2 parameters:- The owner of the Lifecycle. In our case, it is the
Activity
. - An
Observer
.
Whenever there is a change in the data, the
onChanged()
callback is executed and we get the new data. We can update the UI accordingly.Simple Exercise – Create the ‘Add Item Screen’
Now we have an
Activity
that can display a list of borrowed items. But how do we add items to the database?It’s simple. You need to create an AddItemActivity.
The entire procedure is exactly the same as before. But in this case, you need to call the
addBorrow()
DAO method and pass aBorrow
object as a parameter. And that is it. Our app is ready.I encourage you to try this screen on your own. But in case you get stuck, you can refer to my files on GitHub.
Output
So go ahead and run your app. You should get an output similar to this.
Room demo GIF The Android Architecture Components give us great advantage and relief. Hence, we don’t have to worry about
- lifecycle changes
- memory leaks
- data retention across configuration changes
If you recount, these are the biggest challenges faced by even veteran Android developers.
Source Code:
As always, the code from the post can be found on GitHub.
Wrap up
In the post, we got introduced to Android Architecture Components. Then, we learnt about Room and used it to create databases in a fast and easy way. Next, we also learnt how to make our UI respond to changes in data. Also, by using
LiveData
andViewModels
, we did not have to use a lot of callbacks.Additionally, we even learnt a bit about the MVVM architecture.
We have barely scratched the surface in terms of what’s possible with these new components. So I hope to discover more as I continue to tinker with Android Architecture Components.
So are you going to use these components? Would you consider
Room
in any of your apps? Or maybe ViewModels to simplify your code? I’d love to hear your comments. -
Android Image Gallery App: Using Gestures and Transition
In this post, we’ll look at creating a Material Design style, image Gallery app for Android. It will support image gestures like zoom, as well as shared element transitions.
This is part two of the Create an Image Gallery App with Android Studio and Glide post. Previously, we created an Image Gallery app using Glide and Android Studio templates. If you’re not familiar with the basics, I strongly recommend you read part one. It will give you a solid understanding of Glide and Layout Managers.
-
Android O Tutorial: Using Custom Font Resources
One of the new features in Android O is using Custom Font Resources. In this Android Tutorial, let’s see how to use them in our apps.
The first Android O Developer Preview just dropped. There’s a lot for us developers to know about.
One of the highlights in Android O is the ability to use custom font resources. In this article let’s look at using custom fonts in our apps.
Before Android O, how difficult was it to use a custom font in our apps? We had two options:
- Write a custom View
- Use a library
Both options need considerable effort, for just a simple font. Extending your custom View in EVERY layout.xml, instead of TextView is tedious. Moreover, using a third-party library for something basic as text, can be a risky call.
How many times have you admired a beautiful font, and wanted to use that in your app? But the sheer thought of integrating it, made you feel it’s not worth it? Well, not anymore!
Seeing Android O giving official support to custom fonts brought a big smile to my face. I hope it did to you as well.
Getting Started with Font Resources
Android O supports custom fonts via font resources. The magic lies in the app/res folder.
Create new resource directory in Android Studio Creating the font folder is easy. It is like every other resource such as menu, values, drawable, etc.
So right click the res folder and create a new font folder.
Create a new font resource directory Now you’re ready to drop in your fonts. So go ahead and pick a font of your choice.
Font Formats
Android O supports both .otf (OpenType) and .ttf (TrueType) font formats.
I’m going to create a simple page design. Like a book, where the heading is a large serif font.
What we’ll be creating Using Custom Font Resources in Android O
For this Android O tutorial, I’m going to pick my fonts from Google Fonts. They have a great collection, so definitely check that out!
My two font choices are:
Here are the available font styles for Merriweather. I’m happy with just the regular font so I’ll take that alone.
Download font via fonts.google.com You can download the .otf or .ttf fonts of your choice and drop them in the res/fonts folder.
Note:
Keep in mind, that resource files should use lowercase alphabets and underscores. For example, the downloaded font was Merriweather-Regular.ttf. When you copy it to the res/fonts folder, rename it to merriweather_regular.ttf.Once you drop in your custom font files in the fonts folder, you can preview your fonts. Simply double-click on a font, and Android Studio previews the typeface. Neat right?
Font Typeface preview We’re going to need two fonts. One for the heading, and one for the body text. Look closely at the design above. The headline uses a serif font, while the content body is a sans-serif. In other words, the heading will use Merriweather while the content body will use Lato.
Remember, I encourage you to use whatever you like. Feel free to experiment. I’m just using a simple example to show you what’s possible.
Using Custom Fonts via XML
Head over to your XML layout file. Let’s skip the layout design and go straight to using our fonts.
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:fontFamily="@font/merriweather_regular"/>
Here’s my simple TextView. All you need to use a font is ONE attribute, and you’re good to go. Its really that easy!
android:fontFamily="@font/merriweather_regular"
Custom Fonts via Java
You can assign a font programmatically too. First fetch the font typeface. Then set it to your
TextView
.Typeface typefaceLato = getResources().getFont(R.font.lato_regular); mTextIntro.setTypeface(typefaceLato);
Additionally, you can even specify a basic font style such has bold, italic or a combination of the two.
mTextIntro.setTypeface(typefaceLato, Typeface.BOLD_ITALIC);
Custom font typeface styles There’s something interesting to note here. If you’re using a font family, you’ll have the same font, with different weight.
You know what I’m talking about. If you download a font and extract the .zip file, you’ll get multiple font variations like this.
So for example, assume I’m using Merriweather-Regular. If Iset the typeface style to bold, Android will choose Merriweather-Bold from my font-family and display that.
Now that I’ve dropped a hint about font family, you might be wondering what exactly it is. So let’s talk about that next.
Using a font family
As we’ve seen above, what if you want to use the same font in its different styles? Alright, maybe you can get away using the default Typeface style of bold or italic. But what if you want a thinner font? Thin and italic?
When you downloaded the .zip file from Google Fonts, did you notice there wasn’t just a single font? There was a multitude of them. All varying in weight or thickness. You can group all these different fonts, and use them together as a font family.
Creating a Font Family
You can do this in 3 easy steps.
1 Right click the res/fonts folder and create a new ‘Font resource file‘.
Create New Font resource file 2 Add an element for EVERY font variation you wish to include. Let’s go back to the design we’re trying to do. Font styles that are thin, thick and in italics would be nice. So let’s add three.
I only wish to vary fonts for the body content. So let’s add 3 font variations for Lato.
<font-family xmlns:android="http://schemas.android.com/apk/res/android"> <font android:font="@font/lato_light" android:fontStyle="normal" android:fontWeight="300"/> <font android:font="@font/lato_regular" android:fontStyle="normal" android:fontWeight="400"/> <font android:font="@font/lato_bold" android:fontStyle="normal" android:fontWeight="700"/> </font-family>
If you’re unsure about the
fontWeight
, a quick look at Google Fonts will clear your doubts.After that, using a single font from a font family is the same. Just reference them via the font attribute
android:fontFamily="@font/lato_black"
Just remember to first add all your font variations to the font folder. Then create a ‘Font resource file‘. Then add an element per font variation. Finally, reference your font style just like a regular single font.
Customizing Font Styles for Readability
Using the fonts outright on a
TextView
does not guarantee good readability. Take a look for yourselves.Default TextView Seriously, that’s bad. It hardly readable. Keep in mind that a smartphone is a small device, compared to a desktop or tablet. This makes it harder to read the text.
So if your app’s priority is for users to read content. Then its also your priority to make sure the content is easy to read.
The key lies in playing around with two attributes:
letterSpacing
lineSpacingExtra
So with that in mind, here are my
TextView
elements in the layout.... <TextView style="@style/TextAppearance.AppCompat.Headline" android:layout_width="match_parent" android:layout_height="wrap_content" android:fontFamily="@font/merriweather_regular" /> <TextView style="@style/TextAppearance.AppCompat.Subhead" android:layout_width="match_parent" android:layout_height="wrap_content" android:lineSpacingExtra="4dp" android:letterSpacing="0.08" /> <TextView style="@style/TextAppearance.AppCompat.Body1" android:layout_width="match_parent" android:letterSpacing="0.04" android:layout_height="wrap_content" android:fontFamily="@font/lato_regular" android:lineSpacingExtra="4dp" /> ...
With these extra attributes, font should now be easy to read. See the difference for yourself. Its better right?
If you have a hard time remembering the different attributes, use the ‘Design‘ Pane in the XML Editor. The ‘Properties‘ pane on the right, lists all available attributes that you can change.
TextView Properties in Design view of XML editor
Final Results
Here’s how the app finally looks like.
What we’ll be creating Now take a breather here and notice how easily this was. We used 3 different custom fonts without breaking a sweat. Using a font of your choice is as simple as drag and drop! Then, all it took was a single attribute to reference the font file.
I’ve used
merriweather_regular
for the large title heading. The following introduction text is like a quote. That useslato_bold
, withTypeface.ITALIC
.Typeface typefaceLato = getResources().getFont(R.font.lato_bold); mTextIntro.setTypeface(typefaceLato, Typeface.ITALIC);
Yes, such a mix and match is also possible.
SOURCE CODE: Available on GitHub
Where to from here?
Using custom Font resources is just one of the new features in Android O. You can read about the other Android O features here.
While using custom fonts is something basic, its good to know its finally added. Also, it’s relative ease of use makes this feature adoptable by many Android Developers.
So what’s your take on custom fonts? How are you using it? Let me know in the comments.
Also, I’ll be covering other new Android O tutorials in future articles. So don’t forget to subscribe below.
-
Introduction to Google’s Awareness API
A while ago, Google announced something really interesting called the Awareness API. According to Google Developers – Android Awareness API bridges the physical world of users, and the digital world of Android to help you build more assistive and context-aware apps.
The last sentence can be a bit confusing. So here are some examples that will help you realise how powerful the Awareness API is:
Imagine you pass by a pharmacy and your phone reminds you that you have to buy medicines. Or as soon you enter your car, your phone automatically connects to the car’s Bluetooth and your navigation app opens up in driver mode.
Cool right? Awareness API makes this really easy.