Chapters

Hide chapters

Android Apprentice

Third Edition · Android 10 · Kotlin 1.3 · Android Studio 3.6

Before You Begin

Section 0: 4 chapters
Show chapters Hide chapters

Section II: Building a List App

Section 2: 7 chapters
Show chapters Hide chapters

Section III: Creating Map-Based Apps

Section 3: 7 chapters
Show chapters Hide chapters

10. Completing the Detail View
Written by Darryl Bayliss

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

In the last chapter, you set up a new Activity to display the contents of a list. At the moment, that Activity is empty.

In this chapter, you’ll add to that Activity using familiar components such as a RecyclerView to display the list, and a FloatingActionButton to add tasks to the list. You’ll also learn how to communicate back to the previous Activity using an Intent.

Getting started

If you’re following along with your own project, open it and keep using it with this chapter. If not, don’t worry. Locate the projects folder for this chapter and open the ListMaker app inside the starter folder.

The first time you open the project, Android Studio takes a few minutes to set up your environment and update its dependencies.

Open ListDetailActivity.kt and review its contents.

Currently, you pass in a list from MainActivity.kt via an Intent and set the title of the Activity to the name of the list. That’s good, but this Activity needs to do more. For starters, it needs to let a user view all of the items in the list, as well as add new items.

You can accomplish the first task — viewing all of the items — using a RecyclerView.

Open activity_list_detail.xml from the res/layout folder, and show the Design view in the Layout window if it’s not already selected.

In the Palette window, select the Common option from the left-hand list. You’ll see the RecyclerView available for selection in the right-hand list.

Click and drag the RecyclerView to the whitespace in the Layout shown on the right of the Layout Window.

With the RecyclerView added, you need to give it an ID and some dimensions. In the Attributes window, change the ID of the RecyclerView to list_items_recyclerview.

Next, update the layout_width and layout_height to 0dp match_constraint. This ensures the RecyclerView adheres to the constraints you’re about to set, and that it takes up the entire screen.

In the Constraint Widget, click the four + buttons around the square to add constraints to the RecyclerView. Change the margins for each constraint to 0.

With the RecyclerView set up in the layout, it’s time to use it in your code.

Coding the RecyclerView

Open ListDetailActivity.kt. At the top of the class, add a property to hold a reference to the RecyclerView:

lateinit var listItemsRecyclerView : RecyclerView
// 1
listItemsRecyclerView =
    findViewById(R.id.list_items_recyclerview)
// 2
listItemsRecyclerView.adapter = ListItemsRecyclerViewAdapter(list)
// 3
listItemsRecyclerView.layoutManager = LinearLayoutManager(this)

class ListItemsRecyclerViewAdapter(var list: TaskList) : RecyclerView.Adapter<ListItemViewHolder>()

class ListItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)

Adapting the Adapter

Open ListItemsRecyclerViewAdapter.kt.

override fun getItemCount(): Int {
  return list.tasks.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListItemViewHolder {

  val view = LayoutInflater.from(parent.context)
             .inflate(R.layout.task_view_holder, parent, false)
  return ListItemViewHolder(view)
}

Visualizing the ViewHolder

You now have a Layout for the ViewHolder, next, you need to reference the TextView in the Layout in your code.

val taskTextView = itemView.findViewById(R.id.textview_task)
    as TextView
override fun onBindViewHolder(holder: ListItemViewHolder, position: Int) {
  holder.taskTextView.text = list.tasks[position]
}

lateinit var addTaskButton: FloatingActionButton
addTaskButton = findViewById(R.id.add_task_button)
addTaskButton.setOnClickListener {
  showCreateTaskDialog()
}
private fun showCreateTaskDialog() {
  //1
  val taskEditText = EditText(this)
  taskEditText.inputType = InputType.TYPE_CLASS_TEXT

  //2
  AlertDialog.Builder(this)
          .setTitle(R.string.task_to_add)
          .setView(taskEditText)
          .setPositiveButton(R.string.add_task) { dialog, _ ->
            // 3
            val task = taskEditText.text.toString()
            list.tasks.add(task)
            // 4
            val recyclerAdapter = listItemsRecyclerView.adapter as ListItemsRecyclerViewAdapter
            recyclerAdapter.notifyItemInserted(list.tasks.size-1)
            //5
            dialog.dismiss()
          }
          //6
          .create()
          .show()
}
<string name="task_to_add">What is the task you want to add?</string>
<string name="add_task">Add</string>

Returning Results from Activities

ListDataManager is declared and used in MainActivity.kt. To save the list with the newly added task, you could also declare it in ListDetailActivity.kt and save the list anytime the user adds a new task.

private fun showListDetail(list: TaskList) {
  val listDetailIntent = Intent(this, ListDetailActivity::class.java)
  listDetailIntent.putExtra(INTENT_LIST_KEY, list)

  startActivityForResult(listDetailIntent, LIST_DETAIL_REQUEST_CODE)
}

companion object {
  const val INTENT_LIST_KEY = "list"
  const val LIST_DETAIL_REQUEST_CODE = 123
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data:
    Intent?) {
  super.onActivityResult(requestCode, resultCode, data)
  // 1
  if (requestCode == LIST_DETAIL_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
    // 2
    data?.let {
      // 3
      listDataManager.saveList(data.getParcelableExtra(INTENT_LIST_KEY) as TaskList)
      updateLists()
    }
  }
}
private fun updateLists() {
  val lists = listDataManager.readLists()
  listsRecyclerView.adapter =
      ListSelectionRecyclerViewAdapter(lists, this)
}
override fun onBackPressed() {
  val bundle = Bundle()
  bundle.putParcelable(MainActivity.INTENT_LIST_KEY, list)

  val intent = Intent()
  intent.putExtras(bundle)
  setResult(Activity.RESULT_OK, intent)
  super.onBackPressed()
}

Where to go from here?

You reused a lot of your knowledge in this chapter and picked up new tricks to reuse code in your apps in a clean way.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.

Unlock now