I am attempting to adapt an ArrayList to an AutoCompleteTextView in a Fragment. I have had this working on another program, where I am applying the adapter in the MainActivity.
The error I am getting is:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.AutoCompleteTextView.setAdapter(android.widget.ListAdapter)' on a null object reference
My Fragment code - newFlightFrament.kt:
package com.android.joncb.flightlogbook
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.widget.ArrayAdapter
import com.android.joncb.flightlogbook.ExtFunctions.CreateList
import com.android.joncb.flightlogbook.dto.AirlineDTO
import com.google.gson.GsonBuilder
import kotlinx.android.synthetic.main.fragment_new_flight.*
private const val ARG_PARAM1 = "airlines"
class newFlightFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var airlineNameOnly = ArrayList<String>()
private var airlineFSCodeOnly = ArrayList<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
// Log.e("args", param1)
println(param1)
val gson = GsonBuilder().create()
val tempList :List<AirlineDTO> = gson.fromJson(param1,Array<AirlineDTO>::class.java).toList()
val airlines :ArrayList<AirlineDTO> = arrayListOf(AirlineDTO())
airlines.addAll(tempList)
airlineNameOnly = CreateList(airlines, "airlineName")!!
airlineFSCodeOnly = CreateList(airlines, "FS")!!
}
// val adapter = context?.let {
// ArrayAdapter<String>(
// it,
// android.R.layout.simple_list_item_1,
// airlineNameOnly
// )
// }
val adapter = ArrayAdapter<String>(requireActivity().baseContext,android.R.layout.simple_list_item_1,airlineNameOnly)
actxtAirlineName.setAdapter(adapter)
}
}
My Fragment XML - fragment_new_flight.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
android:background="#color/colorPrimary"
tools:context=".newFlightFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/lblNewFlightInstruction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="#dimen/abPadding"
android:text="#string/lblNewFltInstr"
android:textSize="#dimen/medFont"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/abPadding"
android:paddingVertical="8dp"
android:text="#string/airline_name"
android:textSize="#dimen/medFont"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/lblNewFlightInstruction" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/abPadding"
android:paddingVertical="8dp"
android:text="#string/fsCode"
android:textSize="#dimen/medFont"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/actxtAirlineName" />
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/abPadding"
android:paddingVertical="8dp"
android:text="#string/fltNumber"
android:textSize="#dimen/medFont"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/etxtFSCode" />
<AutoCompleteTextView
android:id="#+id/actxtAirlineName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="#string/airline_name"
android:paddingStart="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/textView3"
app:layout_constraintTop_toTopOf="#+id/textView" />
.
.
.
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
I am getting the error when I setAdapter:
actxtAirlineName.setAdapter(adapter)
Note in my commented out section above this call I have tried another approach, which results in the same error.
I can confirm that the ArrayList airlineNameOnly is populated correctly.
Any ideas are good ideas.
Thanks.
You forget override onCreateView
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_new_flight, container, false)
}
Change onCreate to onViewCreated, when onCreate call view doesn't inflate
I cannot see where you inflated your fragment's view. Perhaps there's the issue?
Change your code according to mine
First include this
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout. fragment_new_flight, container, false)
}
arguments?.let {
param1 = it.getString(ARG_PARAM1)
// Log.e("args", param1)
println(param1)
val gson = GsonBuilder().create()
val tempList :List<AirlineDTO> = gson.fromJson(param1,Array<AirlineDTO>::class.java).toList()
val airlines :ArrayList<AirlineDTO> = arrayListOf(AirlineDTO())
airlines.addAll(tempList)
airlineNameOnly = CreateList(airlines, "airlineName")!!
airlineFSCodeOnly = CreateList(airlines, "FS")!!
// val adapter = context?.let {
// ArrayAdapter<String>(
// it,
// android.R.layout.simple_list_item_1,
// airlineNameOnly
// )
// }
val adapter = ArrayAdapter<String>(requireActivity().baseContext,android.R.layout.simple_list_item_1,airlineNameOnly)
actxtAirlineName.setAdapter(adapter)
}
}
Hope it will work Thankew! Happy coding!
Related
The following problem occurred with me after migration from viewPager to viewPager2 - when I open my app, the tablyout indicator is missing by default. But if you make some swiping, the indicator will appears! Looks weird, because I made everything correct. There are my simplified Kotlin-code:
class ScheduleWeekFragment : ScheduleBaseFragment<ScheduleWeekViewModel>(ScheduleWeekViewModel::class) {
private val viewBinding by viewBinding(FragmentWeekBinding::bind)
private var titles: Array<String>? = null
// listeners
private val viewPagerListener = object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
viewModel.updateDayTitle(position)
}
}
// observers
private val selectedDayObserver = Observer<Int> {
viewBinding.viewPager2.currentItem = it
}
// lifecycle
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
titles = context?.resources?.getStringArray(R.array.schedule_fragment_day_abbreviations)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
inflater.inflate(R.layout.fragment_week, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewBinding.viewPager2.adapter = ScheduleViewPagerAdapter(this)
viewBinding.viewPager2.setPageTransformer(ZoomOutPageTransformer)
TabLayoutMediator(viewBinding.tabLayout, viewBinding.viewPager2) { tab, position ->
tab.text = titles?.getOrNull(position)
}.attach()
// observers
viewModel.viewPagerPosition.observe(viewLifecycleOwner, selectedDayObserver)
// listeners
viewBinding.viewPager2.registerOnPageChangeCallback(viewPagerListener)
}
override fun onDestroyView() {
viewBinding.viewPager2.unregisterOnPageChangeCallback(viewPagerListener)
super.onDestroyView()
}
}
And there is my simplified xml-code:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="#+id/fragmentWeek"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.tabs.TabLayout
android:id="#+id/tabLayout"
style="#style/TabLayout1"
android:layout_width="match_parent"
android:layout_height="40dp"
android:verticalScrollbarPosition="left"
app:layout_constraintEnd_toEndOf="#+id/viewPager2"
app:layout_constraintStart_toStartOf="#+id/viewPager2"
app:layout_constraintTop_toBottomOf="#+id/scheduleToolbar"
app:tabGravity="start"
app:tabMode="scrollable"
android:background="#color/white"
tools:ignore="SpeakableTextPresentCheck" />
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/viewPager2"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:background="#color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tabLayout"
tools:ignore="SpeakableTextPresentCheck" />
</androidx.constraintlayout.widget.ConstraintLayout>
The problem was inside my observer:
private val selectedDayObserver = Observer<Int> {
// viewBinding.viewPager2.currentItem = it // wrong!
viewBinding.viewPager2.setCurrentItem(it, false) // correct!
}
I didn't find why in the official docs, but difference exists: the first variant works good with viewpager1, but for viewpager2, be careful and use the second complex variant.
I'm trying to use fragments to not burden my application with too many activities.
In my mainActivity there is a map, I then created a fragment where there are editText fields, I would like to use these editText to insert numbers to be used as parameters to pass to a function created in another class called navFun.
I tried to write the code but I don't understand why I get these errors when using findViewById:
Unresolved reference: findViewById
this is my fragment code
package uk.co.lorenzopulcinelli.navigationdrawer
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import java.lang.Exception
// 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 [CreatePathFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class CreatePathFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
val mainActivity: MainActivity = MainActivity()
val navFun: NavFun = NavFun(mainActivity.context, mainActivity.mapView)
private lateinit var editTextLatitudineP1: EditText
private lateinit var editTextLongitudineP1: EditText
private lateinit var editTextLatitudineP2: EditText
private lateinit var editTextLongitudineP2: EditText
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? {
// create path between editText points
editTextLatitudineP1 = findViewById<EditText>(R.id.editTextLatitudineP1)
editTextLongitudineP1 = findViewById<EditText>(R.id.editTextLongitudineP1)
editTextLatitudineP2 = findViewById<EditText>(R.id.editTextLatitudineP2)
editTextLongitudineP2 = findViewById<EditText>(R.id.editTextLongitudineP2)
val b = findViewById<Button>(R.id.location)
b.setOnClickListener{
try {
Log.d("Path", "Clicked")
val p1lati: Double = editTextLatitudineP1.text.toString().toDouble()
val p1long: Double = editTextLongitudineP1.text.toString().toDouble()
val p2lati: Double = editTextLatitudineP2.text.toString().toDouble()
val p2long: Double = editTextLongitudineP2.text.toString().toDouble()
println("latitudine: $p2lati, longitudine: $p2long")
navFun.routePath(p1lati, p1long, p2lati, p2long)
mainActivity.mapView.invalidate()
} catch (e: Exception) {
Toast.makeText(context, "Error when entering coordinates", Toast.LENGTH_SHORT).show()
}
}
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_create_path, 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 CreatePathFragment.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
CreatePathFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
and this is my fragment xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
tools:context=".CreatePathFragment"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/crea_percorso"
android:textColor="#color/black"
android:textSize="40sp"
android:textStyle="bold" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/inserisci_le_coordinate_dei_punti_tra_cui_vuoi_creare_un_percorso" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/latitudine_punto_di_partenza" />
<EditText
android:id="#+id/editTextLatitudineP1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:ems="10"
android:hint="#string/latitudine_p1"
android:inputType="numberSigned|numberDecimal" />
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/longitudine_punto_di_partenza" />
<EditText
android:id="#+id/editTextLongitudineP1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:ems="10"
android:hint="#string/longitudine_p1"
android:inputType="numberSigned|numberDecimal" />
<TextView
android:id="#+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/latitudine_punto_di_arrivo" />
<EditText
android:id="#+id/editTextLatitudineP2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:ems="10"
android:hint="#string/latitudine_p2"
android:inputType="numberSigned|numberDecimal" />
<TextView
android:id="#+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/longitudine_punto_di_arrivo" />
<EditText
android:id="#+id/editTextLongitudineP2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:ems="10"
android:hint="#string/longitudine_p2"
android:inputType="numberSigned|numberDecimal" />
<Button
android:id="#+id/location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/crea_percorso"
/>
</LinearLayout>
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_create_path, container, false)
// create path between editText points
editTextLatitudineP1 = view.findViewById<EditText>(R.id.editTextLatitudineP1)
editTextLongitudineP1 = view.findViewById<EditText>(R.id.editTextLongitudineP1)
editTextLatitudineP2 = view.findViewById<EditText>(R.id.editTextLatitudineP2)
editTextLongitudineP2 = view.findViewById<EditText>(R.id.editTextLongitudineP2)
val b = findViewById<Button>(R.id.location)
b.setOnClickListener{
try {
Log.d("Path", "Clicked")
val p1lati: Double = editTextLatitudineP1.text.toString().toDouble()
val p1long: Double = editTextLongitudineP1.text.toString().toDouble()
val p2lati: Double = editTextLatitudineP2.text.toString().toDouble()
val p2long: Double = editTextLongitudineP2.text.toString().toDouble()
println("latitudine: $p2lati, longitudine: $p2long")
navFun.routePath(p1lati, p1long, p2lati, p2long)
mainActivity.mapView.invalidate()
} catch (e: Exception) {
Toast.makeText(context, "Error when entering coordinates", Toast.LENGTH_SHORT).show()
}
}
// Inflate the layout for this fragment
return view
}
You must create your view first and than call findViewById on that view.
findViewById will not work inside onCreateView, because at that time the UI is being created, so the views are not initialized yet.
try to link the views inside onViewCreated instead. <-- you can import it using ctrl+O
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
editTextLatitudineP1 = findViewById<EditText>(R.id.editTextLatitudineP1)
//.....the rest of your code
}
i want to transfer data from activity to fragment but i get "Error inflating class fragment" I have searched for solution for that problem but still can't.
this is my full code of FirstFragment.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
// 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 [FirstFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class FirstFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
private lateinit var communicator: Communicator
private lateinit var myTextView: TextView
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
val view = inflater.inflate(R.layout.fragment_first, container, false)
myTextView = view.findViewById<View>(R.id.profile_name_text) as TextView
// Gets the data from the passed bundle
val bundle = arguments
val message = bundle!!.getString("mText")
// Sets the derived data (type String) in the TextView
myTextView.text = message
return view
}
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 FirstFragment.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
FirstFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
my function at Home.kt
fun getData() {
val mFragmentManager = supportFragmentManager
val mFragmentTransaction = mFragmentManager.beginTransaction()
val mFragment = FirstFragment()
val mBundle = Bundle()
val testText = "My Name is Jack"
mBundle.putString("mText",testText)
mFragment.arguments = mBundle
mFragmentTransaction.add(R.id.fragmentContainerView, mFragment).commit()
}
at the fragment_first.xml i want to put the text into the TextView
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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=".Home">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/linear_Layout_home_1"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="30dp"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:paddingStart="15dp"
android:paddingEnd="15dp"
android:paddingTop="10dp"
android:orientation="horizontal"
android:background="#drawable/rounded_blue_shape"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="#+id/profile_name_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/nama_pengguna"
android:textStyle="bold"
android:textSize="15sp"
android:textColor="#color/cloudy"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
this is code of activity_home.xml
<androidx.constraintlayout.widget.ConstraintLayout 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=".Home">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/navigation"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<fragment
android:id="#+id/fragmentContainerView"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/my_nav"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Can anybody help me please?
Base on documentation:
Note: when manually calling setGraph() with arguments, you must not use the app:navGraph attribute when creating the NavHostFragment in XML as that will internally call setGraph() without any arguments, resulting in your graph and start destination being created twice.
docs
You've already defined app: navGraph on your activity(Fragment Container) so you can't call navController. SetGraph from java/kotlin.
Try with remove app:navGraph from Fragment Container
You can pass the data using fragment constructor like this:
fun getData() {
val mFragmentManager = supportFragmentManager
val mFragmentTransaction = mFragmentManager.beginTransaction()
val testText = "My Name is Jack"
val mFragment = FirstFragment(testText)
mFragmentTransaction.add(R.id.fragmentContainerView, mFragment).commit()
}
And fetch it in the fragment like this:
class FirstFragment(private val someText: String): Fragment() {
private lateinit var myTextView: TextView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_first, container, false)
myTextView = view.findViewById<View>(R.id.profile_name_text) as TextView
// Sets the derived data (type String) in the TextView
myTextView.text = someText
return view
}
}
Also seeing your fragment_first.xml layout, you might wanna put it like this:
<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">
<TextView
android:id="#+id/profile_name_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/nama_pengguna"
android:textStyle="bold"
android:textSize="15sp"
android:textColor="#color/cloudy"/>
</RelativeLayout>
Not sure what caused your issue. But noticed you are using Jetpack navigation.
And you're trying to pass data to the start destination of the graph.
Here is an official doc for dealing with your case:
Pass data to the start destination.
And below are some of the code I tried myself, just for your reference:
I think in your MainActivity.kt, you would have something like this:
val navController = findNavController(R.id.fragmentContainerView)
navController.setGraph(R.navigation.my_nav, Bundle().apply {
putString("name", "My name is xx")
})
And in the first fragment, retrieve the parameter:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val name = arguments?.get("name")
Log.w("xx", "$name")
Edit: I updated the findNavController(R.id.fragmentContainerView) and navController.setGraph(R.navigation.my_nav according to the ids in your code.
I wanna align vertically all of items in RecyclerView like ListView but I'm confused to set them.
In other words, They are seen horizontally : https://i.stack.imgur.com/ossLb.jpg
item's image is here : https://i.stack.imgur.com/sjDws.png
Main Activity(CalendarActivity.kt) gets Fragment(HomeFragment) which gets item's information.
CalendarActivity (Main Activity)
L HomeFragment (items are shown in here)
L item (note_layout.xml)
Many solutions I've seen are Add this RecyclerView.layoutManager = LinearLayoutManager(this) in MainActivity.
Even if I added in CalendarActivity, It returns error : kotlin.UninitializedPropertyAccessException: lateinit property binding has not been initialized
And In HomeFragment, I added binding.recyclerViewNotes.layoutManager = LinearLayoutManager(activity) in onCreateView, but It returns same error.
It is related to ViewBinding of course. But what I wanna say is I didn't search way with reference.
What shoud I do in this situation? I'm stuck here.
Someone help please? 🤕
CalendarActivity.kt
class CalendarActivity : AppCompatActivity() {
val TAG: String = "CalenderActivity"
//private lateinit var binding: FragmentHomeBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_calendar)
Log.d(TAG, "CalendarActivity - onCreate() called")
//binding = FragmentHomeBinding.inflate(layoutInflater)
//binding.recyclerViewNotes.layoutManager = LinearLayoutManager(this)
//setContentView(binding.root)
val navController = Navigation.findNavController(this, R.id.fragment)
NavigationUI.setupActionBarWithNavController(this, navController)
}
override fun onSupportNavigateUp(): Boolean {
Log.d(TAG, "CalendarActivity - onSupportNavigateUp() called")
return NavigationUI.navigateUp(
Navigation.findNavController(this, R.id.fragment),
null
)
}
}
HomeFragment.kt
class HomeFragment : BaseFragment() {
private lateinit var binding: FragmentHomeBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
//binding.recyclerViewNotes.layoutManager = LinearLayoutManager(activity)
binding = FragmentHomeBinding.inflate(inflater)
return binding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
binding.recyclerViewNotes.setHasFixedSize(true)
binding.recyclerViewNotes.layoutManager = StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL)
launch {
context?.let {
val notes = NoteDatabase(it).getNoteDao().getAllNotes()
binding.recyclerViewNotes.adapter = NotesAdapter(notes)
}
}
binding.buttonAdd.setOnClickListener {
val action = HomeFragmentDirections.actionAddNote()
Navigation.findNavController(it).navigate(action)
}
}
}
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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=".ui.HomeFragment"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view_notes"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/button_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="20dp"
android:layout_marginBottom="40dp"
android:clickable="true"
android:src="#drawable/ic_add" />
</LinearLayout>
note_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:id="#+id/text_date"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_weight="2"
android:text="2021/01/01"
android:textColor="#111111"
android:textSize="12sp" />
<TextView
android:id="#+id/text_view_title"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="4"
android:layout_marginTop="5dp"
android:text="Title"
android:textStyle="bold"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Headline" />
</LinearLayout>
If you need more detailed information, please comment! thank you!
You have already assigned a LinearLayoutManager in your XML, and that's the type that looks like ListView.
So just delete this line where you are changing it to a staggered grid, which is not what you want:
binding.recyclerViewNotes.layoutManager = StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL)
Change your code to this
binding.recyclerViewNotes.layoutManager = StaggeredGridLayoutManager(1,
StaggeredGridLayoutManager.VERTICAL)
or You can also use LinearLayoutManager instead of StaggeredGridLayoutManager
binding.recyclerViewNotes.layoutManager = new LinearLayoutManager(this);
I have tried many different tutorials and haven't been able to relate any to my application. My application in a gist displays a user's medication that they are taking. Here is my data class...
import java.util.HashMap
class LocalMedication {
var m_medicationName: String? = null
var m_medicationQty: String? = null
var m_medicationType: String? = null
var m_medicationExpDate: String? = null
var m_medicationStatus: Boolean = false
constructor() {}
constructor(medicationName: String, medicationQty: String, medicationType: String, medicationExpDat : String, medicationStatus : Boolean) {
this.m_medicationName = medicationName
this.m_medicationType = medicationType
this.m_medicationQty = medicationQty
this.m_medicationExpDate = medicationExpDat
this.m_medicationStatus = medicationStatus
}
fun toMap(): Map<String, Any> {
val result = HashMap<String, Any>()
result.put("medicationName", m_medicationName!!)
result.put("medicationType", m_medicationType!!)
result.put("medicationQty", m_medicationQty!!)
result.put("medicationExpDate", m_medicationExpDate!!)
result.put("medicationStatus", m_medicationStatus!!)
return result
}
}
Here is my view holder class
package com.example.home_med.viewHolder
import android.view.View
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.home_med.R
class medicationViewHolder(view: View) : RecyclerView.ViewHolder(view) {
var medicationName: TextView
var medicationType: TextView
var medicationQty: TextView
init {
medicationName = view.findViewById(R.id.rv_medicationName)
medicationType = view.findViewById(R.id.rv_medicationType)
medicationQty = view.findViewById(R.id.rv_medicationQty)
}
}
Here is my fragment
class LocalMedication : Fragment() {
private var adapter: FirestoreRecyclerAdapter<LocalMedication, medicationViewHolder>? = null
private var firestoreDB: FirebaseFirestore? = null
private var firestoreListener: ListenerRegistration? = null
private var medList = mutableListOf<LocalMedication>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//setContentView(R.layout.activity_main)
firestoreDB = FirebaseFirestore.getInstance()
val recyclerView = recyclerview as? RecyclerView
val mLayoutManager = LinearLayoutManager(context)
recyclerView?.layoutManager = mLayoutManager
recyclerView?.itemAnimator = DefaultItemAnimator()
loadMedication()
firestoreListener = firestoreDB!!.collection("notes")
.addSnapshotListener(EventListener { documentSnapshots, e ->
if (e != null) {
Log.e(TAG, "Listen failed!", e)
return#EventListener
}
medList = mutableListOf()
if (documentSnapshots != null) {
for (doc in documentSnapshots) {
val note = doc.toObject(LocalMedication::class.java)
note.m_medicationName = doc.id
medList.add(note)
}
}
adapter!!.notifyDataSetChanged()
recyclerView?.adapter = adapter
})
}
override fun onDestroy() {
super.onDestroy()
firestoreListener!!.remove()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val binding: FragmentLocalMedicationBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_local_medication, container, false)
binding.viewMedicationButton.setOnClickListener { v: View ->
v.findNavController().navigate(LocalMedicationDirections.actionLocalMedicationToViewMedication())
}
binding.addMedicationButton.setOnClickListener { v: View ->
v.findNavController().navigate(LocalMedicationDirections.actionLocalMedicationToAddMedication())
}
binding.homeButton.setOnClickListener { v: View ->
v.findNavController().navigate(LocalMedicationDirections.actionLocalMedicationToHome2())
}
setHasOptionsMenu(true)
return binding.root
}
private fun loadMedication() {
val query = firestoreDB!!.collection("notes")
val response = FirestoreRecyclerOptions.Builder<LocalMedication>()
.setQuery(query, LocalMedication::class.java)
.build()
adapter = object : FirestoreRecyclerAdapter<LocalMedication, medicationViewHolder>(response) {
override fun onBindViewHolder(holder: medicationViewHolder, position: Int, model: LocalMedication) {
val note = medList[position]
holder.medicationName.text = note.m_medicationName
holder.medicationType.text = note.m_medicationType
holder.medicationQty.text = note.m_medicationQty
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): medicationViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.recyclerview_item, parent, false)
return medicationViewHolder(view)
}
override fun onError(e: FirebaseFirestoreException) {
Log.e("error", e!!.message)
}
}
adapter!!.notifyDataSetChanged()
recyclerview?.adapter = adapter
}
public override fun onStart() {
super.onStart()
adapter!!.startListening()
}
public override fun onStop() {
super.onStop()
adapter!!.stopListening()
}
}
Here is my recyclerViewItem XML file
<LinearLayout 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:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/rv_medicationName"
style="#style/word_title"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:background="#android:color/holo_orange_light"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/rv_medicationQty"
style="#style/word_title"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:background="#android:color/holo_orange_light"
app:layout_constraintStart_toEndOf="#+id/rv_medicationName"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/rv_medicationType"
style="#style/word_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:background="#android:color/holo_orange_light"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/rv_medicationQty"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
Here is my localMedications XML file
<layout 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"
tools:context=".LocalMedication">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="32dp"
android:text="LOCAL MEDICATION"
android:textSize="36sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.478"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="543dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:background="#android:color/darker_gray"
app:layout_constraintBottom_toTopOf="#+id/homeButton"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView"
tools:listitem="#layout/recyclerview_item" />
<Button
android:id="#+id/viewMedicationButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="100dp"
android:layout_marginBottom="100dp"
android:text="View Med"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<Button
android:id="#+id/addMedicationButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="100dp"
android:layout_marginBottom="100dp"
android:text="Add Medication"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="#+id/homeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:layout_marginTop="59dp"
android:layout_marginEnd="30dp"
android:layout_marginBottom="103dp"
android:text="Home"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/viewMedicationButton"
app:layout_constraintStart_toEndOf="#+id/addMedicationButton"
app:layout_constraintTop_toBottomOf="#+id/addMedicationButton"
app:layout_constraintVertical_bias="0.972" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Here is what my database looks like...
Datatbase
Any help or guidance would be great. It runs the application, but in the Logs, it says "RecyclerView: No adapter attached; skipping layout"
The problem in your code lies in the fact that the names of the fields in your LocalMedication class are different than the name of the properties in your database. You have in your LocalMedication class a field named m_medicationName while in your database I see it as medicationName and this is not correct. The names must match. Behind the scene, Kotlin is creating a Java class with a getter named getM_medicationName() so Firebase is looking in the database for a field named m_medicationName and not medicationName.
There are two ways in which you can solve this problem. The first one would be to remove the data in your database and add it again using field names (m_medicationName, m_medicationQty etc) that exist in your LocalMedication class.
If you are not allowed to use the first solution, then the second approach will be to use annotations in front of your public fields. So you should use the PropertyName annotation in front of every field. So in your LocalMedication class, a field should look like this:
#get:PropertyName("medicationName")
#set:PropertyName("medicationName")
public var m_medicationName: String? = null
As explained in my answer from the following post:
I am trying to get the correct reference to my Firebase Database child and set the values in my RecyclerView but I am having some issues
It's for Firebase realtime database but the same rules apply to Cloud Firestore.