Reputation: 49
This is the first time I am using Android Architecture. I have decided to go with MVVM structure but I am stuck at the point where I have no idea how to set the textViews in my XML with the data I pull from the database.
Checking the logs, I have seen that the function calls to my database (Firestore) does retrieve the correct data documents. Do I set the UI elements from the Activity,ViewModel or the Fragment? (Please note that I'm using a Navigation bar and controller)
Please assist me, my code is as follows:
My Single Activity:
class HomeActivity : AppCompatActivity() {
// Create the three objects for the fragments
lateinit var homeFragment: HomeFragment
lateinit var visitsFragment: VisitsFragment
lateinit var profileFragment: ProfileFragment
// ViewModels
lateinit var customerViewModel: CustomerViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
// Initialize the bottom nav bar and navigation controller and then merge them
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.btm_nav)
val navigationController = findNavController(R.id.fragmentHost)
bottomNavigationView.setupWithNavController(navigationController)
// Create app bar config object so that you can rename the bar ontop with the tab name
val appBarConfiguration = AppBarConfiguration(setOf(R.id.homeFragment,R.id.visitsFragment,R.id.profileFragment))
setupActionBarWithNavController(navigationController,appBarConfiguration)
// View Model
customerViewModel = ViewModelProvider(this).get(CustomerViewModel::class.java)
customerViewModel.retrieveCustomer().observe(this, Observer { it })
}
// This function creates the menu object by inflating it with the resource we gave it (menu resource).
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_main,menu);
return true
}
// This function checks which menu item was selected and performs the task associated with the item selected.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId;
// If Log Out menu item was selected
if (id == R.id.menuLogOut){
// Sign the user out
FirebaseAuth.getInstance().signOut()
// Finish this activity
finish()
// Start the initial activity
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
// Display the message to the user
Toast.makeText(this, "Successfully Signed Out", Toast.LENGTH_SHORT).show()
return true
}
return super.onOptionsItemSelected(item)
}
}
My View Model:
class CustomerViewModel: ViewModel() {
val TAG = "CustomerViewModel"
var db = Firebase.firestore
var user = FirebaseAuth.getInstance().currentUser
var liveData = MutableLiveData<List<Customer>>()
var cusArray = arrayListOf<Customer>()
var docRef = user?.uid
fun retrieveCustomer(): MutableLiveData<List<Customer>>
{
db.collection("users").document(docRef.toString())
.get()
.addOnSuccessListener { document ->
if (document != null)
{
val data = document
// Set the data
val name = data.get("name") as String
val surname = data.get("surname") as String
val email = data.get("email") as String
val contactNo = data.get("contact no") as String
val customer = Customer(name, surname, email, contactNo)
cusArray.add(customer)
liveData.value = cusArray
Log.d(TAG, "DocumentSnapshot data: ${document.data}")
}
else
{
Log.d(TAG, "No such document")
}
}
.addOnFailureListener { exception ->
Log.d(TAG, "get failed with " + exception.message, exception)
}
return liveData
}
}
My Object Class
package com.CleanWheels.cleanwheels.DataClasses
data class Customer(
val name: String?,
val surname: String?,
val email: String?,
val contactNo: String?
)
My XML file (profile_fragment):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".Fragments.ProfileFragment">
<TextView
android:id="@+id/banner"
android:layout_width="499dp"
android:layout_height="290dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginStart="-6dp"
android:layout_marginTop="0dp"
android:layout_marginEnd="0dp"
android:background="@color/colorPrimary"
android:layout_marginLeft="-6dp"
android:layout_alignParentRight="true"
android:layout_alignParentLeft="true"
android:layout_marginRight="0dp" />
<ImageView
android:id="@+id/image"
android:layout_width="154dp"
android:layout_height="159dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="53dp"
android:layout_marginEnd="132dp"
android:layout_marginRight="132dp"
android:layout_marginBottom="78dp"
android:src="@drawable/ic_action_profile" />
<LinearLayout
android:id="@+id/layout_1"
android:layout_width="280dp"
android:layout_height="40dp"
android:layout_below="@id/banner"
android:layout_marginLeft="80dp"
android:layout_marginTop="100dp"
android:layout_marginRight="20dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Name:"
android:textSize="18sp"/>
<TextView
android:id="@+id/profileNameUI"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="18sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/layout_2"
android:layout_width="280dp"
android:layout_height="40dp"
android:layout_below="@id/layout_1"
android:layout_marginLeft="80dp"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Surname:"
android:textSize="18sp"/>
<TextView
android:id="@+id/profileSurnameUI"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="18sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/layout_3"
android:layout_width="280dp"
android:layout_height="40dp"
android:layout_below="@id/layout_2"
android:layout_marginLeft="80dp"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Email Address:"
android:textSize="18sp"/>
<TextView
android:id="@+id/profileEmailUI"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="18sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/layout_4"
android:layout_width="280dp"
android:layout_height="40dp"
android:layout_below="@id/layout_3"
android:layout_marginLeft="80dp"
android:layout_marginBottom="50dp"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Contact No:"
android:textSize="18sp" />
<TextView
android:id="@+id/profileContactUI"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_5"
android:layout_width="65dp"
android:layout_height="220dp"
android:layout_below="@id/banner"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="0dp"
android:layout_marginLeft="0dp"
android:layout_marginTop="90dp"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:layout_marginBottom="5dp"
android:layout_weight="1"
android:src="@drawable/ic_action_profile_name_ui"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_weight="1"
android:src="@drawable/ic_action_profile_surname_ui"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_weight="1"
android:src="@drawable/ic_action_profile_email_ui"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="0dp"
android:layout_weight="1"
android:src="@drawable/ic_action_profile_contact_ui"/>
</LinearLayout>
The profile_fragment class file:
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
* Use the [ProfileFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class ProfileFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_profile, container, false)
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment ProfileFragment.
*/
// TODO: Rename and change types and number of parameters
@JvmStatic
fun newInstance(param1: String, param2: String) =
ProfileFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
Then finally, the View I am trying to populate
Upvotes: 0
Views: 1365
Reputation: 386
You need to move all the logic to ProfileFragment once you navigate to ProfileFragment data will be set. Example:
ProfileFragment
class ProfileFragment : Fragment() {
private val customerViewModel: CustomerViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_profile, container, false)
val name = view.findViewById<TextView>(R.id.name)
val surname = view.findViewById<TextView>(R.id.surname)
val email = view.findViewById<TextView>(R.id.email)
val contact = view.findViewById<TextView>(R.id.contact)
//calling initially here
customerViewModel.retrieveCustomer()
customerViewModel.liveData.observe(viewLifecycleOwner, Observer {
//customer index at 0
val customer = it[0]
name.text = customer.name
surname.text = customer.surname
email.text = customer.email
contact.text = customer.contactNo
})
return view
}
CustomerViewModel.kt
class CustomerViewModel(application: Application) : AndroidViewModel(application) {
var liveData = MutableLiveData<List<Customer>>()
fun retrieveCustomer(){
//Your logic to get data from Firebase or any remote or db
val listOfCustomer = mutableListOf<Customer>()
val customer = Customer("name", "surname","email", "contqct")
listOfCustomer.add(customer)
liveData.postValue(listOfCustomer)
}
}
fragment_profile.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Name"
android:padding="8dp"
android:textSize="24dp"
/>
<TextView
android:id="@+id/surname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Surname"
android:padding="8dp"
android:textSize="24dp"
/>
<TextView
android:id="@+id/email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Name"
android:padding="8dp"
android:textSize="24dp"
/>
<TextView
android:id="@+id/contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Name"
android:padding="8dp"
android:textSize="24dp"
/>
</LinearLayout>
Upvotes: 1