0

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 enter image description here

4
  • Can you share profile fragment code. actually you need to write all the code there because data related to profile view model. Commented Sep 5, 2020 at 10:22
  • The profile fragment code is empty. I haven't done anything in there yet because I was not sure where to set the data. Could you show me an example of how I would set it in the fragment please? Commented Sep 5, 2020 at 10:27
  • to give some example I need to understand better the problem. From which layout and fragment, above screen short is displayed Commented Sep 5, 2020 at 10:30
  • from the fragment called profile_fragment. I have added it now in the question above. Commented Sep 5, 2020 at 11:36

1 Answer 1

1

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>
Sign up to request clarification or add additional context in comments.

1 Comment

THANK YOU SO MUCH! I have spend hours on youtube trying to learn this and I found no material on doing this, even for such a simple display. I am grateful! One last thing, while the data loads I would like to add a spinner or progress bar to make it look smoother. Where would I add this?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.