Recycler View

This is my note for Udemy lesson: Advanced Android Bootcamp 2024.

1. Add Recycler View

Create a new project and drag a recycler view component to activity_main.xml, give it id name "recyclerView".

2. Create a Layout for List Item

Name it list_item.xml, which contains a text view with id name "tvName".

3. Create a Data Class

data class Fruit(
    val name: String,
    val supplier: String
)

4. Create a Recycler View Adapt

class MyRecyclerViewAdapter(
    private val fruitsList: List<Fruit>,
    private val clickHandler: (Fruit) -> Unit
): RecyclerView.Adapter<MyViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        val listItem = layoutInflater.inflate(R.layout.list_item, parent, false)
        return MyViewHolder(listItem, clickHandler)
    }

    override fun getItemCount(): Int {
        return fruitsList.size
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        holder.bind(fruitsList[position])
    }
}

class MyViewHolder(
    private val view: View,
    private val clickHandler: (Fruit) -> Unit
): RecyclerView.ViewHolder(view) {
    fun bind(fruit: Fruit) {
        val myTextView: TextView = view.findViewById<TextView>(R.id.tvName)
        myTextView.text = fruit.name

        view.setOnClickListener {
            clickHandler(fruit)
        }
    }
}

5. Edit Main Activity

class MainActivity : AppCompatActivity() {
    private val fruitsList = listOf<Fruit>(
        Fruit("Mango", "Joe"),
        Fruit("Apple", "Frank"),
        Fruit("Banana", "Tom"),
        Fruit("Guava", "Joe"),
        Fruit("Lemon", "Alex"),
        Fruit("Pear", "Joe"),
        Fruit("Orange", "Alex")
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
        recyclerView.setBackgroundColor(Color.YELLOW)
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = MyRecyclerViewAdapter(fruitsList) {
            listItemClicked(it)
        }
    }

    private fun listItemClicked(fruit: Fruit) {
        Toast.makeText(this, "Fruit is: ${fruit.name}", Toast.LENGTH_SHORT).show()
    }
}

Pass Data Between Fragments

This is my note for Udemy lesson: Advanced Android Bootcamp 2024.
First, check my previous note
Then in HomeFragment, do:

val bundle = bundleOf("user_name" to binding.editTextText.text.toString())
it.findNavController().navigate(R.id.action_homeFragment_to_secondFragment, bundle)

In SecondFragment, do:

val userName = arguments?.getString("user_name")

Use Data Binding In Fragment

This is my note for Udemy lesson: Advanced Android Bootcamp 2024.
Check my previous note: Simple Data Binding
Step 1 and 2 are the same. In step3, we need to write it in a different way.
Before:

class BlankFragment : Fragment() {
  override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val view =  inflater.inflate(R.layout.fragment_blank, container, false)
    val button = view.findViewById<Button>(R.id.control_button)
    button.setOnClickListener { ... }
    return view
  }
  ...
}

After:

class BlankFragment : Fragment() {
  private lateinit var binding: FragmentHomeBinding

  override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    binding = DataBindingUtil.inflate(inflater, R.layout.fragment_blank, container, false)
    binding.controlButton.setOnClickListener { ... }
    return binding.root
  }
  ...
}

Navigation Between Fragments

This is my note for Udemy lesson: Advanced Android Bootcamp 2024.

1. Add Dependencies

Reference
In project layer's build.gradle.kts:

buildscript {
  ...
  dependencies {
    val nav_version = "2.7.7"
    classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version")
  }
}

In app layer's build.gradle.kts:

dependencies {
  val nav_version = "2.5.3"
  implementation("androidx.navigation:navigation-fragment-ktx:$nav_version")
  implementation("androidx.navigation:navigation-ui-ktx:$nav_version")
}

2. Create a Navigation Graph File

Highlight app folder -> File -> New -> Android Resource File -> Input file name like "nav_graph" -> Change resource type to "Navigation"

3. Add NavHostFragment

  1. Open activity_main.xml, switch to design mode.
  2. Find "NavHostFragment" from Palette's Containers group, drag it to screen.
  3. A popup will show to ask which navigation graph it links to, choose the one just created(nav_graph.xml).

4. Create Fragments

  1. Open nav_graph.xml.
  2. Click the icon "New Destination" -> Create new destination -> Fragment(Blank)
  3. Edit fragment name and press "Finish" button.
  4. Repeat the step to create another fragment.

5. Create Navigation Acton

  1. Open nav_graph.xml
  2. Drag a line from one fragment to another, an action will be automatically created. Assume the two fragments are HomeFragment and SecondFragment, the created action will be action_homeFragment_to_secondFragment.
  3. Select the action(which displays as an arrow), we can set its animations in the attributes window.

6. Use the Navigation Action

First, create a button in HomeFragment, then in its onCreateView function, write the following code:

xxxButton.setOnClickListener {
  it.findNavController().navigate(R.id.action_homeFragment_to_secondFragment)
}

2 Way Binding between ViewModel and xml Components

This is my note for Udemy lesson: Advanced Android Bootcamp 2024.

1. Enable xml to Access to ViewModel

see this note

2. Edit ViewModel

class MainActivityViewModel: ViewModel() {
  val userName = MutableLiveData("Frank")
}

3. In xml, When Display LiveData in ViewModel Only:

<TextView
  ...
  android:text="@{viewModel.userName}" />

4. In xml, When Display and Change LiveData in ViewModel:

<com.google.android.material.textfield.TextInputEditText
  ...
  android:text="@={viewModel.userName}" />

Using LiveData ViewModel in xml

This is my note for Udemy lesson: Advanced Android Bootcamp 2024.

1. Set up Data Binding

See this note

2. Set up ViewModel

See this note

3. Edit ViewModel

class MainActivityViewModel: ViewModel() {
  private val _count = MutableLiveData(0)
  val count: LiveData<Int> get() = _count
  fun add() {
    _count.value = _count.value?.plus(1)
  }
}

4. Edit activity_main.xml

<layout ...>
  <data>
    <variable name="viewModel" type="com.xxx.xxx.MainActivityViewModel" />
  </data>
  <androidx.constraintlayout.widget.ConstraintLayout ...>
    ...
    <TextView
      ...
      android:text-"@{viewModel.count.toString()}" />

    <Button
      ...
      android:onClick="@{() -> viewModel.add()}" />
    ...
  </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

5. In MainActivity, Pass the ViewModel to xml

override fun onCreate(savedInstanceState: Bundle?) {
  ...
  binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
  viewModel = ViewModelProvider(this)[MainActivityViewModel::class.java]
  binding.viewModel = viewModel
  binding.lifecycleOwner = this
}