Getting error findViewById when initiate recyclerview in a fragment - android

I have tested this code in another project where I didn't use fragment and wrote it in MainActivity.kt, it works. But a problem comes when I make another project using fragment so I write it in a new class (HerbalFragment.kt). It's getting error in "findViewById" for initiate Recyclerview and also getting error in "this". Here is my code (HerbalFragment.kt)
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
/**
* A simple [Fragment] subclass.
*/
class HerbalFragment : Fragment() {
private lateinit var rvHerbal: RecyclerView
private var list: ArrayList<Herbal> = arrayListOf()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
super.onViewCreated(view, savedInstanceState)
return inflater.inflate(R.layout.fragment_herbal, container, false)
rvHerbal = findViewById(R.id.rv_herbal)
rvHerbal.setHasFixedSize(true)
list.addAll(HerbalData.listData)
showRecyclerList()
}
private fun showRecyclerList() {
rvHerbal.layoutManager = LinearLayoutManager(this)
val listHerbalAdapter = ListHerbalAdapter(list)
rvHerbal.adapter = listHerbalAdapter
}
}[![enter image description here][1]][1]
Help me please, thanks before

As far as i have noticed your code is unreachable,
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
super.onViewCreated(view, savedInstanceState)
return inflater.inflate(R.layout.fragment_herbal, container, false)
// unreachable code you are already return the view so below code will never execute
rvHerbal = findViewById(R.id.rv_herbal)
rvHerbal.setHasFixedSize(true)
list.addAll(HerbalData.listData)
showRecyclerList()
}
To fix this issue you need to change your code as i have suggested.
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_herbal, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// do what ever you want here like find view ids and etc...
rvHerbal = findViewById(R.id.rv_herbal)
rvHerbal.setHasFixedSize(true)
list.addAll(HerbalData.listData)
showRecyclerList()
}
}
private fun showRecyclerList() {
rvHerbal.layoutManager = LinearLayoutManager(activity!!)
val listHerbalAdapter = ListHerbalAdapter(list)
rvHerbal.adapter = listHerbalAdapter
}

You do not have to find view if you use the kotlin data binding by this easy method
add import to this (fragment_herbal is your xml layout view file name)
import kotlinx.android.synthetic.main.fragment_herbal.*
then
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_herbal, container, false)
}
then use your view item without findviewbyid
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
rvHerbal.setHasFixedSize(true)
list.addAll(HerbalData.listData)
showRecyclerList()
}

Related

erorr when trying to reach view with findviewbyId

class main_fragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_main_fragment, container, false)
val viewPager = view.findViewById<ViewPager>(R.id.viewPager)
viewPager.adapter = PageAdapter(childFragmentManager)
val tabLayout = view.findViewById<TabLayout>(R.id.tabLayout)
tabLayout.setupWithViewPager(viewPager)
}
}
i am getting an erorr Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type View?
can anyone help me?
class main_fragment : Fragment() {
val view: View
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_main_fragment, container, false)
val viewPager = view.findViewById<ViewPager>(R.id.viewPager)
viewPager.adapter = PageAdapter(childFragmentManager)
val tabLayout = view.findViewById<TabLayout>(R.id.tabLayout)
tabLayout.setupWithViewPager(viewPager)
return view
}
}
override onViewCreated method
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState)
and then use view parameter from this function

Difference between onCreateView and onViewCreated in Fragment - Kotlin

I know this question has been asked many times but just wanted to have some more clarity.
So I wanted to create a simple fragment with a button that should change the fragment when clicked - very simple and basic one.
hence I create a function, and called it on onCreateView. Nothing happeded.
Then I created onViewCreated after onCreateView and called the same function in it.
It Worked.
My Question is What exactly made it work ?
here is the code
class homeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
hello()
}
fun hello()
{
val button = view?.findViewById<Button>(R.id.button_login)
button?.setOnClickListener{
val action = homeFragmentDirections.actionHomeFragmentToLoginFragment()
findNavController().navigate(action)
Toast.makeText(context,"wao",Toast.LENGTH_LONG).show()
}
}
}
As per your comments, you did something like this:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_home, container, false)
hello() // the method has already returned a View, so this call is never reached.
}
So, when you call hello() in onCreateView after the return statement,
the method has no effect because of the return statement.
Since onViewCreated is called after the onCreateView,
the underlying View is no more null in your hello function.
If you still want to use onCreateView, you can do something like this:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val fragmentView = inflater.inflate(R.layout.fragment_home, container, false)
hello(fragmentView)
return fragmentView
}
fun hello(buttonHolderView: View?) {
val button = buttonHolderView?.findViewById<Button>(R.id.button_login)
button?.setOnClickListener {
val action = homeFragmentDirections.actionHomeFragmentToLoginFragment()
findNavController().navigate(action)
Toast.makeText(context, "wao", Toast.LENGTH_LONG).show()
}
}
You need to inflate the view before calling the function:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val fragmentHome = inflater.inflate(R.layout.fragment_home, container, false)
hello(fragmentHome)
return fragmentHome;
}
Change your hello function:
fun hello(view: View)
{
....

BottomSheetDialogFragment.viewBinding

I struggle to do a property delegate for ViewBinding on BottomSheets.
The general Idea is similar to this
For Fragments i use something like this
fun <T : ViewBinding> Fragment.viewBinding(viewBindingFactory: (View) -> T) =
FragmentViewBindingDelegate(this, viewBindingFactory)
On BottomSheetsDialogFragments which are Fragments it does not accept the delegate.
fun <T : ViewBinding> BottomSheetDialogFragment.viewBinding(viewBindingFactory: (View) -> T) =
FragmentViewBindingDelegate(this, viewBindingFactory)
The Lifecycle of BottomSheets would be the same as on regular Fragments, so i would not expect any problems.
Anyone came up with a solution on this ?
You can still use the FragmentViewBindingDelegate and extension from Gabor.
You just also need to inflate the view inside onCreateView().
For example:
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.zhuinden.fragmentviewbindingdelegatekt.viewBinding
class ExampleBottomSheet : BottomSheetDialogFragment() {
//Using ::bind here since the view is already inflated in onCreateView()
private val binding by viewBinding(YourCustomViewBinding::bind)
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.your_custom_view, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//Use binding here or wherever you need it
}
}
Implement ViewBinding in BottomSheetFragment like this (Works for me):
class CustomBottomSheet : BottomSheetDialogFragment() {
private lateinit var binding: CustomBottomSheetBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = CustomBottomSheetBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//onClick listener
binding.button.setOnClickListener {
Toast.makeText(context, "Clicked", Toast.LENGTH_LONG).show()
}
}
}
This works:
class CampaignBottomSheet : BottomSheetDialogFragment() {
private var _binding: MenuCampaignsBinding? = null
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = MenuCampaignsBinding.inflate(layoutInflater)
binding.startCampaign.setOnClickListener { println("__print::CampaignBottomSheet") }
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
Unlike Fragment class, BottomSheetDialogFragment doesn't have a constructor that accepts layout resource.
You can create a custom dialog for it. Basically, copy everything from AppCompatDialogFragment and BottomSheetDialogFragment.

Android: Problem using recycler view in fragment

I am using RecyclerView in Fragment ImagesliderFragment First it gives an expection of "recyclerview must not be null" so on stackover flow I got an answer that you should intialized your recyclerview by using following line
frag_rv = view.findViewById(R.id.frag_rv) as RecyclerView
But problem is that it gives me error on view. that only safe or non null asserted calls are allowed also my RecyclerView is not resolving can anyone explain me this what is the problem ?
ImagesliderFragment
class ImagesliderFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
inflater.inflate(R.layout.fragment_imageslider, container, false)
frag_rv = view.findViewById(R.id.frag_rv) as RecyclerView
frag_rv.layoutManager = LinearLayoutManager(context, LinearLayout.HORIZONTAL, false)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
}
Try this
class ImagesliderFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val myView = inflater.inflate(R.layout.fragment_imageslider, container, false)
val frag_rv = myView.findViewById(R.id.frag_rv) as RecyclerView
frag_rv.layoutManager = LinearLayoutManager(context, LinearLayout.HORIZONTAL, false)
return myView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
}
Also now no need to do findViewById()
SAMPLE CODE
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
// import here your layout file like this
import kotlinx.android.synthetic.main.fragment_imageslider.view.*
class ImagesliderFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val myView = inflater.inflate(R.layout.fragment_imageslider, container, false)
myView.frag_rv.layoutManager = LinearLayoutManager(context, LinearLayout.HORIZONTAL, false)
return myView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
}
}
You could change your onCreateView method to:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
) =
inflater.inflate(R.layout.fragment_imageslider, container, false).apply {
frag_rv = findViewById(R.id.frag_rv) as RecyclerView //val frag_rv if it's not declared elsewhere
frag_rv.layoutManager = LinearLayoutManager(context, LinearLayout.HORIZONTAL, false)
}
This way the view is inflated(via inflater.inflate) and you are using it to find the RecyclerView.
You should only use the onCreateView method to inflate the view and bind the iew in the onViewCreated method
class ImagesliderFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?) = inflater.inflate(R.layout.fragment_imageslider, container, false)!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val frag_rv = view.findViewById<RecyclerView>(R.id.frag_rv) frag_rv.layoutManager = LinearLayoutManager(context, LinearLayout.HORIZONTAL,
false)
}
}
Before you use view.findViewById you have to initialize it, also use val before frag_rv like the following.
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// here you have to initialize your view
View view = inflater.inflate(R.layout.fragment_imageslider, container, false)
val frag_rv = view.findViewById(R.id.frag_rv) as RecyclerView
frag_rv.layoutManager = LinearLayoutManager(context, LinearLayout.HORIZONTAL, false)
return view
}

How do I correctly use Kotlin to call a blank fragment from the Home fragment?

class HomeFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
val v = inflater.inflate(R.layout.fragment_home, container, false)
val fab = v.findViewById(R.id.fab) as FloatingActionButton
fab.setOnClickListener {
val blankFragment = BlankFragment()
val manager = childFragmentManager
manager.beginTransaction().replace(R.id.frame_container, blankFragment, blankFragment.tag).commit()
// System.out.println("You have reached the floating action button")
}
return v
}
}
Getting a no view found error. I may have issues with the R.id.frame_content but Kotlin doesn't immediately identify all id values...
This may not be the best way and I apologize for the horrible formatting I does this while answer out on my phone and it's hard to get it perfect. Anyways In the activity that holds your fragments, such as MainActivity.kt add...
supportFragmentManager.beginTransaction.add(R.id.fragment_home, HomeFragment.newInstance, "HomeFragment").commit()
In your HomeFragment.kt change the following.
class HomeFragment: Fragment(){
companion object {
fun newInstance(): HomeFragment{
return HomeFragment() }
fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater!!.inflate(R.layout.fragment_home, container, false)
val activity = activity
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val clickListener = View.OnClickListener { view ->
when (view.getId()) {
R.id.fab -> NextFragment()
}
}
fab.setOnClickListener(clickListener)
}
NextFragment(){
val fragManager = activity?.supportFragmentManager
fragManager?.beginTransaction()?.replace(R.id.frame_container, BlankFragment.newInstance(), "blankFragment")?.commit()
}
Make sure you make the same changes to BlankFragment.kt
class BlankFragment: Fragment(){
companion object {
fun newInstance(): BlankFragment{
return BlankFragment() }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater!!.inflate(R.layout.fragment_blank, container, false)
val activity = activity
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//Do some stuff with your views in BlankFragment here
}
}

Categories

Resources