Reading Time: 11 minutesWe are going to start the Retrofit basics tutorial with the preparation of the sample application. In every case, when you start a new project, you have to make shorter or longer preparations before you can start implementing the business logic.
In this chapter first, we will start a new project in Android Studio, then we will add the needed dependencies. Thenafter, we will create the four fragments, the toolbar and the navigation graph, and some more smaller things 😊. The last thing will be a base class for our app.
Jump
In this chapter we won’t talk about Retrofit, we will work only on the preparation of the sample application. If you want to start the tutorial immediately with Retrofit, then jump to the next chapter.
There you can download the project from GitHub , what we are going to prepare in this chapter.
BUT, we highly recommend you to do this chapter as well. Why? Because, if you want to be a good programmer, then you have to practice all the time, and this chapter is a good opportunity for this.
Step 1 – Create new project
After a short introduction, our first step is to create a whole new project. For this, launch Android Studio and create a new project. If you see the “Welcome page” of Android Studio, then click on the “Start a new Android Studio project”.
If you have an open project, then from the “File” menu select “New”, then “New Project”. After thet, this window will popup.
Here select the “Empty Activity” option.
In the next window, we should provide some information about the app. We name the new project as “RetrofitDemo”.
As always, this tutorial will be written in Kotlin. So, select from the dropdown list the Kotlin language.
From the next list of the “Minimum SDK” select API 21. In our case API 21 gonna be enough.
There is a link, called “Help me choose”. If you click on it, then a colorful figure will show you the different Android versions and their imported innovations.
If you are done, click on the “Finish” button. The build can take few minutes. Be patient! 😉
When the build has been finished, then you should see the open MainActivity:class and next to this the activity_main.xml files. For now on you can close both of them.
Step 2 – Add the needed dependencies
Next step is to enable for the project the dependencies, what we are going to use.
So, to add them to the project, go to the top left corner of Android Studio. There will be the tab called “Project”. Click on it and change the view to Android. Then open the Gradle Scripts menu and double click on the build.gradle (Module: app) file.
Set the target JVM
Now, scroll down a bit, until the end of the android {} section. There paste the below lines.
android {
...
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
Target JVM
We need to use JVM 1.8, otherwise we can’t use use the Navigation Componenets library.
Enable Data Binding
Also here, after the JVM lines, paste the below lines also. These will enable in the project Data Binding.
android {
...
dataBinding {
enabled true
}
}
Enable Data Binding
Dependencies
Next is to add the dependencies. They are going to the dependencies {} section of the build.gradle (Module: app) file.
Copy and paste the below lines at the end of the dependencies.
/** Retrofit **/
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
/** Navigation **/
implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"
/** Lifecycle components **/
implementation "androidx.lifecycle:lifecycle-common:$archLifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime:$archLifecycle_version"
implementation "android.arch.lifecycle:extensions:$archLifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$archLifecycle_version"
/** Kotlin Coroutines **/
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutines_version"
Dependencies
The versions
The last step before we can synchronize the app is to define the versions of the above mentioned dependencies. We are going to do it in one place, which is located in the build.gradle (Project: app) file. You can find it next the build.gradle (Module: app) file.
At the top of the file, inside of the buildscript{} section you should have the version of Kotlin.
After it paste the needed versions. Then the versions should look like below.
ext.archLifecycle_version = '2.2.0'
ext.kotlinCoroutines_version = '1.3.7'
ext.kotlin_version = '1.3.72'
ext.navigation_version = '2.3.0-beta01'
ext.retrofit_version = '2.9.0'
Versions
You can find the current version of Retrofit under its official website:
Retrofit
Sync the project
Finally, it is time to finish this step. So, click on the “Sync Now” text, what you can find at the top right corner of Android Studio.
Depending on your computer, it can take some minutes, so be patient. 😊
Step 3 – Create the fragments
As we have talked about in the intro of this chapter, we will have four fragments in our sample app. Currently they won’t have to much code, only its bindings.
Download the assets
The first thing what you should do, is to download some files for this app. The next .ZIP file contains
-
-
- the logo of WordPress
- the needed strings in the string.xml file
- the color in the colors.xml
- the dimens in the dimen.xml
- the menu for the main screen
- the layout of the item for the RecyclerView
- the Toolbar for the app
- the navigation graph, which is responsible to navigate between the fragments
So, using the below link download the file and extract it into your project’s res folder.
Download assets
New package
Before the creation of the fragments, we are going ot create a new package for the fragments, to have a clean design of our app.
We can do it, by clicking on the package of the project. You can find it in the Project tab, at the left side of Android Studio.
In the popup window name the new package as “fragments”. and click on the OK button.
The fragments
Inside of the new fragments package, we will create the four fragments. By name:
-
-
- LoginFragment
- MainFragment
- ProfileFragment
- RegisterFragment
LoginFragment
First, we will start with the LoginFragment. So, click with the right mouse button on the fragments package and from the popup menu select New, then Fragment and from the submenu Fragment (Blank). In the popup window name the fragment as “LoginFragment”.
After Android Studio finishes the creation, you will have lots of lines of code inside of our new fragment… we don’t need them, so remove all the unnecessary code. Finally, it should look like below.
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.inspirecoding.retrofitdemo.R
class LoginFragment : Fragment()
{
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View?
{
return inflater.inflate(
R.layout.fragment_login,
container,
false)
}
}
LoginFragment
fragment_login.xml
To start using Data Binding for the LoginFragment, we have to convert its layout. So, open the fragment_login.xml file. If you closed it, then you can find it in the res->layout folders.
Change the current FrameLayout to ConstraintLayout. Then, move your cursor to layout and press there on you keyboard the Alt+Enter hot keys on Windows or Control/Option+Enter on Mac. This will open up a quick menu, the Show Context Actions menu. There, select the first option, which is “Convert to data binding layout”.
Now, the layout should look like below.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.LoginFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_blank_fragment" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
fragment_login.xml
The next step is to add the views to the layout. In this tutorial we won’t go into the detailes of the layout. What you should note is the Guideline, what we use to align the WordPress logo and the other views.
The layout of the fragment_login.xml file looks like below. Copy and paste it into your project.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimaryDark"
tools:context=".ui.LoginActivity">
<!--guideline_horizontal-->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.25" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:src="@drawable/wordpress"
android:layout_marginTop="@dimen/margin_small"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1"
app:layout_constraintBottom_toBottomOf="@+id/guideline_horizontal"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<!--tv_login_welcomeback-->
<TextView
android:id="@+id/tv_welcomeback"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_xlarge"
android:text="@string/welcome_back"
android:textSize="@dimen/textsize_xxlarge"
android:textColor="@color/white"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/guideline_horizontal"/>
<!--til_login_email-->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_login_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_6xlarge"
android:layout_marginStart="@dimen/margin_large"
android:layout_marginEnd="@dimen/margin_large"
app:errorEnabled="true"
app:hintEnabled="false"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_welcomeback">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tiet_login_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="@dimen/margin_small"
android:hint="@string/email"
android:inputType="textEmailAddress"
android:textColor="@color/white"
android:textColorHint="@color/white"
android:textCursorDrawable="@null"
android:textSize="@dimen/textsize_large" />
</com.google.android.material.textfield.TextInputLayout>
<!--til_login_password-->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_login_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_large"
android:layout_marginEnd="@dimen/margin_large"
app:errorEnabled="true"
app:hintEnabled="false"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/til_login_email"
app:passwordToggleEnabled="true"
app:passwordToggleTint="@color/colorPrimary">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tiet_login_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="@dimen/margin_medium"
android:hint="@string/password"
android:inputType="textPassword"
android:textColor="@color/white"
android:textColorHint="@color/white"
android:textCursorDrawable="@null"
android:textSize="@dimen/textsize_large" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_medium"
android:layout_marginStart="@dimen/margin_large"
android:layout_marginEnd="@dimen/margin_large"
android:background="@color/colorAccent"
android:paddingTop="@dimen/margin_small"
android:paddingBottom="@dimen/margin_small"
android:text="@string/login"
android:textColor="@color/colorPrimaryDark"
android:textSize="@dimen/textsize_large"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/til_login_password" />
<TextView
android:id="@+id/tv_registerNow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_large"
android:gravity="center"
android:text="@string/dont_have_an_account_yet_register_now"
android:textColor="@color/white"
android:textSize="@dimen/textsize_large"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_login" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_3xlarge"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
fragment_login.xml
The last thing, what we have to do with the login fragment is to add the Data Binding to the LoginFragment::class as well. So, open the file from the fragments package and add the binding variable into the class, and change the call of the view.
In the login screen, we don’t need the Toolbar, so in the onStart() method we need to hide it.
Finally the class looks like below.
class LoginFragment : Fragment()
{
private lateinit var binding: FragmentLoginBinding
override fun onStart()
{
super.onStart()
(activity as AppCompatActivity).supportActionBar?.hide()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View?
{
binding = DataBindingUtil.inflate(layoutInflater, R.layout.fragment_login, container, false)
return binding.root
}
}
LoginFragment::class
RegisterFragment
The rest fragments won’t be too different from the LoginFragment, so just follow the same instructions from the creation of the login screen and paste the below code into the right files.
The below code goes into the fragment_register.xml file.
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimaryDark" >
<!--guideline_horizontal-->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.25" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:src="@drawable/wordpress"
android:layout_marginTop="@dimen/margin_small"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1"
app:layout_constraintBottom_toBottomOf="@+id/guideline_horizontal"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<TextView
android:id="@+id/tv_createAccount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_xlarge"
android:text="@string/create_account"
android:textSize="@dimen/textsize_xxlarge"
android:textColor="@color/white"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline_horizontal"/>
<!--til_name-->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_6xlarge"
android:layout_marginStart="@dimen/margin_large"
android:layout_marginEnd="@dimen/margin_large"
app:errorEnabled="true"
app:hintEnabled="false"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_createAccount">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tiet_register_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="@dimen/margin_small"
android:hint="@string/username"
android:inputType="text"
android:textColor="@color/white"
android:textColorHint="@color/white"
android:textCursorDrawable="@null"
android:textSize="@dimen/textsize_large" />
</com.google.android.material.textfield.TextInputLayout>
<!--til_email-->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_large"
android:layout_marginEnd="@dimen/margin_large"
app:errorEnabled="true"
app:hintEnabled="false"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/til_username">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tiet_register_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="@dimen/margin_small"
android:hint="@string/email"
android:inputType="textEmailAddress"
android:textColor="@color/white"
android:textColorHint="@color/white"
android:textCursorDrawable="@null"
android:textSize="@dimen/textsize_large" />
</com.google.android.material.textfield.TextInputLayout>
<!--til_password-->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_large"
android:layout_marginEnd="@dimen/margin_large"
app:errorEnabled="true"
app:hintEnabled="false"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/til_email"
app:passwordToggleEnabled="true"
app:passwordToggleTint="@color/colorPrimary">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tiet_register_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="@dimen/margin_medium"
android:hint="@string/password"
android:inputType="textPassword"
android:textColor="@color/white"
android:textColorHint="@color/white"
android:textCursorDrawable="@null"
android:textSize="@dimen/textsize_large" />
</com.google.android.material.textfield.TextInputLayout>
<!--btn_register-->
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_register"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_medium"
android:layout_marginStart="@dimen/margin_large"
android:layout_marginEnd="@dimen/margin_large"
android:background="@color/colorAccent"
android:paddingTop="@dimen/margin_small"
android:paddingBottom="@dimen/margin_small"
android:text="@string/register"
android:textColor="@color/colorPrimaryDark"
android:textSize="@dimen/textsize_large"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/til_password" />
<!--tv_alreadyHaveAnAccount-->
<TextView
android:id="@+id/tv_alreadyHaveAnAccount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_large"
android:gravity="center"
android:text="@string/already_have_an_account"
android:textColor="@color/white"
android:textSize="@dimen/textsize_large"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_register"/>
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_3xlarge"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
AndroidManifest.xml
The next lines goes into to RegisterFragment::class.
class RegisterFragment : Fragment()
{
private lateinit var binding: FragmentRegisterBinding
override fun onStart()
{
super.onStart()
(activity as AppCompatActivity).supportActionBar?.hide()
}
override fun onCreateView(
layoutInflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View?
{
binding = DataBindingUtil.inflate(
layoutInflater,
R.layout.fragment_register,
container,
false)
return binding.root
}
}
RegisterFragment
ProfileFragment
The next fragment is the ProfileFragment. It will be very simple, because it will contain only a TextView for the name of the logged in user and a Button to log out from the app.
As before, first create a new fragment and paste the next lines into its layout and class.
The below code goes into the profile_register.xml file.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.ProfileFragment">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Inspire Coding"
android:textStyle="bold"
android:textSize="@dimen/textsize_3xlarge"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:text="@string/hello_blank_fragment" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_logOut"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_6xlarge"
android:text="Log Out"
android:padding="@dimen/margin_large"
android:textColor="@color/white"
android:background="@color/colorPrimaryDark"
android:textSize="@dimen/textsize_xlarge"
app:layout_constraintTop_toBottomOf="@+id/tv_name"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
fragment_profile.xml
… and the code for the ProfileFragment::class
class ProfileFragment : Fragment()
{
private lateinit var binding: FragmentProfileBinding
override fun onCreateView(
layoutInflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View?
{
binding = DataBindingUtil.inflate(
layoutInflater,
R.layout.fragment_profile,
container,
false)
return binding.root
}
}
ProfileFragment::class
The main screen
After the creation of the previous screens, we can add the last fragment as well. So, as before, create a new fragment into the fragments package with the name of “MainFragment“.
The below lines goes into the fragment_main.xml file.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.MainFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_3xlarge"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
fragment_main.xml
The next lines will be the body of the MainFragment::class.
class MainFragment : Fragment()
{
private lateinit var binding: FragmentMainBinding
private lateinit var userAdapter: UserAdapter
override fun onStart()
{
super.onStart()
(activity as AppCompatActivity).supportActionBar?.show()
}
override fun onCreateView(
layoutInflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View?
{
binding = DataBindingUtil.inflate(
layoutInflater,
R.layout.fragment_main,
container,
false)
val toolbar = (activity as AppCompatActivity).findViewById(R.id.toolbar)
toolbar.navigationIcon = null
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
{
super.onViewCreated(view, savedInstanceState)
setHasOptionsMenu(true)
initRecyclerView()
}
private fun setProgressBarVisibility(visible: Int)
{
binding.progressBar.visibility = visible
}
private fun initRecyclerView()
{
context?.let { _context ->
userAdapter = UserAdapter(_context)
binding.recyclerView.apply {
layoutManager = LinearLayoutManager(_context)
adapter = userAdapter
}
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater)
{
inflater.inflate(R.menu.menu_main, menu)
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean
{
return when(item.itemId)
{
R.id.item_search -> {
findNavController().navigate(R.id.action_mainFragment_to_profileFragment)
true
}
else -> super.onOptionsItemSelected(item)
}
}
}
MainFragment::class
Note that
-
-
- in the onStart() method we show again the Toolbar
- in the onCreate() method after the binding, we hide the navigation icon
- the onViewCreated() method will set the menu and the RecyclerView
- and finally the setProgressBarVisibility() method will show or hide the loading spinner when the app does some background work, eg fetch the list of the users.
Currently you should have some errors, but don’t worry, we are going to solve them soon.
Step 4 – The adapter for the RecyclerView
On the main screen, we will list the all the resitered user from the database of the WordPress website. To have all of them visible, we are going to create a RecyclerView, which needs an adapter.
So, just create a new package called “adapter” and inside of it a new Kotlin file with the name of “UserAdapter”.
The code of the adapter looks like below.
class UserAdapter(var context: Context): RecyclerView.Adapter()
{
private var listOfUser = emptyList()
fun addAllUser(listOfUser: List)
{
this.listOfUser = listOfUser
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder
{
val layoutInflater = LayoutInflater.from(context)
val binding: ItemUserBinding = DataBindingUtil.inflate(
layoutInflater,
R.layout.item_user, parent, false
)
return UserViewHolder(binding)
}
override fun getItemCount() = listOfUser.count()
override fun onBindViewHolder(holder: UserViewHolder, position: Int)
{
holder.bindUser(listOfUser[position])
}
inner class UserViewHolder(val binding: ItemUserBinding): RecyclerView.ViewHolder(binding.root)
{
fun bindUser(user: User)
{
binding.tvName.text = user.name
}
}
}
UserAdapter::class
Step 5 – The User data class
In this application we are going to use a simple data holder, which will be a User data class.
If you would like to know more about data class, then check out our tutorial.
Data Class
So, create a new package called “model”, then there a new Kotlin file with the name of “User” and paste the below code into it.
data class User (
var userId: Int = 0,
var name: String = "",
var email: String = "",
var password: String = ""
)
User data class
Step 6 – The main activity
In this tutorial we follow the one activity approach. It means, thet we have only one activity, and there a fragment container, where we will add the fragmetns based on the navigation of the user.
To enable this functionality for our app, we have to add there also some lines of code. So, open the MainActivity::class and paste there the below lines.
class MainFragment : Fragment()
{
private lateinit var binding: FragmentMainBinding
private lateinit var userAdapter: UserAdapter
override fun onStart()
{
super.onStart()
(activity as AppCompatActivity).supportActionBar?.show()
}
override fun onCreateView(
layoutInflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View?
{
binding = DataBindingUtil.inflate(
layoutInflater,
R.layout.fragment_main,
container,
false)
val toolbar = (activity as AppCompatActivity).findViewById(R.id.toolbar)
toolbar.navigationIcon = null
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
{
super.onViewCreated(view, savedInstanceState)
setHasOptionsMenu(true)
initRecyclerView()
}
private fun setProgressBarVisibility(visible: Int)
{
binding.progressBar.visibility = visible
}
private fun initRecyclerView()
{
context?.let { _context ->
userAdapter = UserAdapter(_context)
binding.recyclerView.apply {
layoutManager = LinearLayoutManager(_context)
adapter = userAdapter
}
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater)
{
inflater.inflate(R.menu.menu_main, menu)
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean
{
return when(item.itemId)
{
R.id.item_search -> {
findNavController().navigate(R.id.action_mainFragment_to_profileFragment)
true
}
else -> super.onOptionsItemSelected(item)
}
}
}
MainActivity::class
Step 7 – The class of the application
Later on, we are going to use a ViewModel to handle the data for our app. This ViewModel will hold the list of the users and will notify the user interface about the changes in the data. When does it happen, then a Toast will show for the user the result and for this the text comes from the strings.xml file.
To get the text from this file, we need a context. In our app we will use a singleton application context, what we will define in the MyApp::class. This class will be inherited from the Application::class.
So, create a new file with this name in the package of the MainActivity::class and paste there the below code.
class MyApp: Application()
{
init
{
instance = this
}
companion object
{
private var instance: MyApp? = null
fun applicationContext() : Context
{
return instance!!.applicationContext
}
}
}
MyApp::class
Before we can use this class in the whole app, we have to add it to the AndroidManifest.xml file, what you can find in the manifest folder of your sample app.
Open the xml file, and add the below line into the <application> tag.
android:name=“.MyApp”
Run the app
Finally, we can run the app, but still you won’t see to much things on it. When the app succesfully build and run on your device, then the login screen should be visible.
GitHub
In case, if you have some errors, then you can download the sample app from our GitHub repository.
GitHub – Retrofit
Questions
I hope the description was understandable and clear. But, if you have still questions, then leave me comments below! 😉
Have a nice a day! 🙂
Click to rate this post!
[Total: 0 Average: 0]