Getting started with ToDoApp on Android

As mentioned earlier, we are using Android Studio 3.0 (stable) for this project. The following screenshot depicts the project structure that we're using:

In this project, we are using package-by features, and I do prefer to use package-by for Android development, mainly for its scalability and maintainability. Also, note that it is best practice to use package-by feature in Android; although, you can obviously use your preferred model. You can read more about the package-by feature at https://hackernoon.com/package-by-features-not-layers-2d076df1964d.

Now, let's understand the package structure used in this application. The root package here is com.rivuchk.todoapplication, the package for the application, identical with the applicationId. The root package contains two classes—ToDoApp and BaseActivity. The ToDoApp class extends android.app.Application so that we can have our own implementation of the Application class. Now, what is BaseActivity? BaseActivity is an abstract class created within this project, and all activities in this project should extend BaseActivity; so, if we want to implement something throughout all the activities in this project, we can write the code in BaseActivity and rest assured that all activities will now implement the same.

Next, we have an apis package for the classes and files related to the API calls (we will use Retrofit) and datamodels for models (POJO) classes.

We have the Utils package for CommonFunctions and Constants (a singleton Object to hold constant variables such as BASE_URL and others).

The addtodo, tododetails, and todolist are three feature-based packages. The todolist package contains Activity and Adapter for displaying the list of todos. The tododetails package contains the Activity responsible to display the details of todo. We will use the same Activity to edit as well. The addtodo package holds the Activity that will be used to accomplish the functionality of adding a todo.

Before starting with the activities and layouts, I want you to take a look inside BaseActivity and ToDoApp, so here is the code inside the ToDoApp.kt file:

    class ToDoApp:Application() { 
      override fun onCreate() { 
        super.onCreate() 
        instance = this 
      } 
 
      companion object { 
        var instance:ToDoApp? = null 
      } 
    } 

A small class indeed; it contains only a companion object to provide us with the instance. This class will grow as we move ahead with this chapter. We declared ToDoApp as the application class for this project in the manifest, as shown here:

    <application 
      android:allowBackup="true" 
      android:icon="@mipmap/ic_launcher" 
      android:label="@string/app_name" 
      android:roundIcon="@mipmap/ic_launcher_round" 
      android:supportsRtl="true" 
      android:theme="@style/AppTheme" 
      android:name=".ToDoApp"> 
      .... 
    </application> 

The BaseActivity is also now small. As with the ToDoApp, it'll also grow over the course of this chapter:

    abstract class BaseActivity : AppCompatActivity() { 
       final override fun onCreate(savedInstanceState: Bundle?) { 
        super.onCreate(savedInstanceState) 
        onCreateBaseActivity(savedInstanceState) 
       } 
      abstract fun onCreateBaseActivity(savedInstanceState: Bundle?) 
    } 

For now, BaseActivity only hides the onCreate method from the Activity class, and provides a new abstract method—onCreateBaseActivity. This class also mandates that we override onCreateBaseActivity in child classes so that if there's anything we need to implement inside the onCreate method, of all activities, we can do that inside the onCreate method of BaseActivity, and forget the rest.

So, let's get started with the todolist. This package contains all the sources required to display the list of todos. If you look at the previous screenshot carefully, you should notice that the package contains two classes—TodoListActivity and ToDoAdapter.

So, let's start with the design of TodoListActivity; when completed, this Activity should look like the following screenshot:

As the screenshot depicts, we will need a FloatingActionButton and a RecyclerView for this Activity, so here is the XML layout for this example—activity_todo_list.xml:

    <?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.rivuchk.todoapplication.
todolist.TodoListActivity"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <android.support.v7.widget.RecyclerView
android:id="@+id/rvToDoList"
android:layout_width="match_parent" android:layout_height="match_parent" app:layoutManager="LinearLayoutManager" android:orientation="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> <android.support.design.widget.FloatingActionButton
android:id="@+id/fabAddTodo"
android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin" app:srcCompat="@drawable/ic_add" /> </android.support.design.widget.CoordinatorLayout>

Take a look at the preceding layout. In the declaration of RecyclerView, we set layoutManager to LinearLayoutManager and orientation to vertical-all from the layout itself, so we would not need to worry about setting it inside the code.

We used a FloatingActionButton to add new todos. We also used AppBarLayout as an action bar.

It's time to move ahead and take a look inside the onCreateBaseActivity method of the TodoListActivity, as shown here:

    lateinit var adapter: ToDoAdapter 
 
    private val INTENT_EDIT_TODO: Int = 100 
 
    private val INTENT_ADD_TODO: Int = 101 
 
    override fun onCreateBaseActivity(savedInstanceState: Bundle?) { 
      setContentView(R.layout.activity_todo_list) 
      setSupportActionBar(toolbar) 
 
      fabAddTodo.setOnClickListener { _ -> 
         startActivityForResult(intentFor<AddTodoActivity>
(),INTENT_ADD_TODO) } adapter = ToDoAdapter(this,{ todoItem-> startActivityForResult(intentFor<TodoDetailsActivity>
(Pair(Constants.INTENT_TODOITEM,todoItem)),INTENT_EDIT_TODO) }) rvToDoList.adapter = adapter fetchTodoList() }

In the preceding program, we created an instance of ToDoAdapter to set it as the adapter of rvToDoList, the RecyclerView where we will display the list of todos. While creating the instance of ToDoAdapter, we passed a lambda; this lambda should be called when an item from the rvToDoList is clicked.

We also called a fetchTodoList()function at the end of the onCreateBaseActivity method. As the name indicates, it is responsible to fetch the todo list from the REST API. We will see the definition and go into the details of this method later, but, for now, let's take a look at Adapter:

    class ToDoAdapter( 
      private val context:Context, //(1)   
val onItemClick:(ToDoModel?)->Unit = {}//(2)
):RecyclerView.Adapter<ToDoAdapter.ToDoViewHolder>() { private val inflater:LayoutInflater =
LayoutInflater.from(context)//(3)
private val
todoList:ArrayList<ToDoModel> = arrayListOf()//(4)
fun
setDataset(list:List<ToDoModel>) {//(5)
todoList.clear() todoList.addAll(list) notifyDataSetChanged() } override fun getItemCount(): Int = todoList.size override fun onBindViewHolder(holder: ToDoViewHolder?,
position: Int) { holder?.bindView(todoList[position]) } override fun onCreateViewHolder
(parent: ViewGroup?, viewType: Int): ToDoViewHolder { return ToDoViewHolder
(inflater.inflate(R.layout.item_todo,parent,false)) } inner class ToDoViewHolder(itemView:View):
RecyclerView.ViewHolder(itemView) { fun bindView(todoItem:ToDoModel?) { with(itemView) {//(6) txtID.text = todoItem?.id?.toString() txtDesc.text = todoItem?.todoDescription txtStatus.text = todoItem?.status txtDate.text = todoItem?.todoTargetDate onClick { [email protected](todoItem)//(7) } } } } }

Study the preceding code carefully. It's the complete ToDoAdapter class. We took an instance of context as a comment (1) constructor parameter. We used that context to get an instance of Inflater, which in turn was used to inflate the layouts inside the onCreateViewHolder method. We created a blank ArrayList of ToDoModel. We used that list to get item counts of the adapter getItemCount() function, and inside the onBindViewHolder function, to pass it to the ViewHolder instance.

We also took a lambda as a val parameter inside the constructor of ToDoAdapteronItemClick (comment (2)). That lambda should receive an instance of ToDoModel as a parameter and should return unit.

We used that lambda at bindView of ToDoViewHolder, inside onClick (comment (7)) of itemView (the view for that item in the list). So, whenever we click on an item, the onItemClick lambda will be called, which is passed from the TodoListActivity.

Now, focus on comment (5)setDataset() method. This method is used to assign a new list to the adapter. It will clear the ArrayListTodoList and add all items from the passed list to it. This method, setDataset, should be called by the fetchTodoList() method in TodoListActivity. That fetchTodoList() method is responsible for fetching the list from the REST API, and it will pass that list to the adapter.

We will look inside the fetchTodoList() method later, but let's concentrate on the REST API and Retrofit 2 for API calls.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.172.115