I am trying to access a Floating Action Button inside a fragment but for some reason, I cannot. I keep getting errors. I have tried everything and nothing seems to work. Here is the code inside my fragment:
import android.os.Bundle
import android.support.design.widget.FloatingActionButton
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.FirebaseDatabase
import com.ntx_deisgns.cyberchatter.cyberchatter.Message
import com.ntx_deisgns.cyberchatter.cyberchatter.R
import kotlinx.android.synthetic.main.groups.*
import kotlinx.android.synthetic.main.groups2.*
class groups2 : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// inflater.inflate(R.layout.groups2, container, false)
val fab = R.id.fab as FloatingActionButton
fab.setOnClickListener {
if (!mainActivityEditText.text.toString().isEmpty()){
sendData()
}else{
// Toast.makeText(this, "Please enter a message", Toast.LENGTH_SHORT).show()
}
}
return inflater.inflate(R.layout.groups2, container, false)
}
private fun sendData(){
val editText = groupInput
val database = FirebaseDatabase.getInstance()
val myRef = database.getReference("message")
myRef.setValue(Message(editText.text.toString()))
val mDatabase: DatabaseReference? = null
mDatabase?.
child("messages")?.
child(java.lang.String.valueOf(System.currentTimeMillis()))?.
setValue(Message(editText.text.toString()))
//clear the text
editText.setText("")
}
companion object {
fun newInstance(): groups2 = groups2()
}
}
What am I doing wrong? Why is it so hard to access a setOnClickListener within a fragment?
UPDATE:
Here's my groups2.xml:
<?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:id="#+id/groups2_relative"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="60dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="55dp"
tools:context="com.ntx_deisgns.cyberchatter.cyberchatter.MainActivity">
<android.support.design.widget.FloatingActionButton
android:id="#+id/myFab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:clickable="true"
android:focusable="true"
android:src="#drawable/ic_send_black_24dp"
android:tint="#android:color/white"
app:fabSize="mini" />
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_toStartOf="#id/myFab">
<EditText
android:id="#+id/groupInput"
android:layout_width="match_parent"
android:layout_height="57dp"
android:hint="Please enter your text here" />
</android.support.design.widget.TextInputLayout>
<ListView
android:id="#+id/list_of_messages"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/myFab"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="16dp"
android:divider="#android:color/transparent"
android:dividerHeight="16dp" />
</RelativeLayout>
You need to inflate the view before calling findViewById on it. Accessing the floating action button before inflation is causing the null pointer exception.
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
//inflate and store view
val view = inflater.inflate(R.layout.groups2, container, false)
val fab = view.findViewById(R.id.fab) as FloatingActionButton
//If using kotlinx then above line is not needed
fab.setOnClickListener {
//do your thing...
}
return view
}
Related
The problem here is when I'm returning from my support fragment to home fragment back every time my items in the recycle viewer got doubled. Each time i am shifting fragment to fragment my recycle viewer item in the homefragment got doubled. But when, I reopen the app its all got corrected but when i click on another fragment and come back the item in recycle viewer in home fragment got doubled. Kindly help me
// **HomeFragment.kt**
package com.service.bookitapp
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.fragment_home.*
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
class HomeFragment : Fragment() {
private var param1: String? = null
private var param2: String? = null
private val arrCategory = ArrayList<CategoryModel>()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_home, container, false)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val recyclerView =view.findViewById<RecyclerView>(R.id.recyclerCategory)
arrCategory.add(CategoryModel(R.drawable.electrician,"Electrician"))
arrCategory.add(CategoryModel(R.drawable.plumber,"Plumber"))
arrCategory.add(CategoryModel(R.drawable.acservice,"AC Service"))
arrCategory.add(CategoryModel(R.drawable.carpentry,"Carpentry"))
arrCategory.add(CategoryModel(R.drawable.drop,"Pick up & Drop"))
arrCategory.add(CategoryModel(R.drawable.painting,"Painting"))
arrCategory.add(CategoryModel(R.drawable.waterfilter,"Water Filter Repair"))
arrCategory.add(CategoryModel(R.drawable.packer,"Pack and Move"))
recyclerView.layoutManager = GridLayoutManager(context,3)
val recyclerAdapter = context?.let { RecycleCategoryAdapter(it,arrCategory) }
recyclerView.adapter = recyclerAdapter
}
}
// **fragment_home.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="#FAF9F6"
android:padding="5dp"
android:orientation="vertical"
tools:context=".HomeFragment">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="UselessParent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/welcome_user"
android:textColor="#color/teal_200"
android:textSize="28sp"
android:padding="8dp"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_alignParentEnd="true"
android:src="#drawable/profile"
android:padding="4dp"
android:contentDescription="#string/app_name" />
</RelativeLayout>
<RelativeLayout
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/catg"
android:textStyle="bold"
android:textColor="#6E16e8"
android:layout_alignParentStart="true"
android:textSize="22sp"/>
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="370dp"
android:id="#+id/recyclerCategory">
</androidx.recyclerview.widget.RecyclerView>
<LinearLayout
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/offers"
android:textStyle="bold"
android:layout_marginBottom="5dp"
android:textColor="#6E16e8"
android:textSize="22sp"/>
<HorizontalScrollView
android:layout_margin="8dp"
android:layout_width="350dp"
android:layout_height="200dp"
tools:ignore="UselessParent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_width="350dp"
android:layout_height="wrap_content"
android:src="#drawable/plumbingservice"
android:contentDescription="#string/elect" />
<ImageView
android:layout_width="350dp"
android:layout_height="wrap_content"
android:contentDescription="#string/elect"
android:src="#drawable/cleanview" />
<ImageView
android:layout_width="360dp"
android:layout_height="wrap_content"
android:contentDescription="#string/elect"
android:src="#drawable/elecview" />
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
</LinearLayout>
The followig are the images
first solution, before add first item in list, call clear
arrCategory.clear()
second solution, populate your list in onCreate method of your fragment
Have you tried moving this
private val arrCategory = ArrayList<CategoryModel>(),
locally inside onViewCreated() ?
like this
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val recyclerView =view.findViewById<RecyclerView>(R.id.recyclerCategory)
val arrCategory = ArrayList<CategoryModel>() // <-- like this?
arrCategory.add(CategoryModel(R.drawable.electrician,"Electrician")
...
...
...
or you can simply initialize the list like this, removing all of it out of the onCreate()
private val arrCategory = arrayListOf<CategoryModel>(
CategoryModel(R.drawable.electrician,"Electrician"),
CategoryModel(R.drawable.plumber,"Plumber"),
CategoryModel(R.drawable.acservice,"AC Service"),
CategoryModel(R.drawable.carpentry,"Carpentry"),
CategoryModel(R.drawable.drop,"Pick up & Drop"),
CategoryModel(R.drawable.painting,"Painting"),
CategoryModel(R.drawable.waterfilter,"Water Filter Repair"),
CategoryModel(R.drawable.packer,"Pack and Move")
)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val recyclerView =view.findViewById<RecyclerView>(R.id.recyclerCategory)
recyclerView.layoutManager = GridLayoutManager(context,3)
val recyclerAdapter = context?.let { RecycleCategoryAdapter(it,arrCategory) }
recyclerView.adapter = recyclerAdapter
}
I'm trying to set the dynamic height for my recycler view, because I have the Add button below it, that adds a new item to the list.
I'm using Constraint Layout in my parent fragment. I followed this advice, and when I add first item, it shows up and the ADD button slides down as expected, but the problem is that when I add the second one it just doesn't appear.
Here is the layout of my parent fragment:
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".SecondFragment">
<Button
android:id="#+id/cancel_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="444dp"
android:text="#string/cancel"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/cancel_button2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addItemActionButton" />
<Button
android:id="#+id/cancel_button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="76dp"
android:text="#string/ok"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toRightOf="#id/cancel_button"
app:layout_constraintTop_toBottomOf="#+id/addItemActionButton"
app:layout_constraintVertical_bias="1.0" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="372dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
app:layout_constrainedHeight="true"
app:layout_constraintBottom_toTopOf="#id/addItemActionButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.41"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.065" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/addItemActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="492dp"
android:clickable="true"
android:src="#android:drawable/ic_input_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/recyclerView"
tools:ignore="SpeakableTextPresentCheck" />
</androidx.constraintlayout.widget.ConstraintLayout>
And here's the one for the recycler item layout:
<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:padding="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constrainedHeight="true">
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/textInputLayout"
android:layout_width="288dp"
android:layout_height="51dp"
android:layout_marginBottom="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.024">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/item"
android:layout_width="300dp"
android:layout_height="71dp"
android:hint="#string/item" />
</com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Here's my fragment code:
package com.example.progresstracker
import android.os.Bundle
import android.util.Log
import android.util.Log.INFO
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.progresstracker.databinding.FragmentSecondBinding
/**
* A simple [Fragment] subclass as the second destination in the navigation.
*/
class SecondFragment : Fragment() {
private var layoutManager: RecyclerView.LayoutManager? = null
private var adapter: RecyclerView.Adapter<RecyclerAdapter.ViewHolder>? = null
private var _binding: FragmentSecondBinding? = null
private var items: ArrayList<String> = ArrayList()
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentSecondBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.recyclerView.apply {
// set a LinearLayoutManager to handle Android
// RecyclerView behavior
layoutManager = LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
// set the custom adapter to the RecyclerView
adapter = RecyclerAdapter(items)
}
// linearLayoutManager = LinearLayoutManager(context)
// binding.recyclerView.layoutManager = linearLayoutManager
binding.cancelButton.setOnClickListener {
findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
}
binding.addItemActionButton.setOnClickListener {
items.add("Testing..")
adapter = RecyclerAdapter(items)
adapter?.notifyItemInserted(items.size - 1)
binding.recyclerView.adapter = adapter
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
And the adapter:
package com.example.progresstracker
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class RecyclerAdapter(private val items: ArrayList<String>) : RecyclerView.Adapter<RecyclerAdapter.ViewHolder>() {
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var item: TextView
init {
item = itemView.findViewById(R.id.item)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_item_row, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.item.text = items[position]
}
override fun getItemCount(): Int {
return items.size
}
}
i'm facing a real strange problem, my recyclerview is showing only 1 item! I have tried multiple solutions seen on the net but none of them worked.
Here is my ListFragmentImmeuble.kt:
package com.example.mydata.fragments.list
import android.app.AlertDialog
import android.os.Bundle
import android.view.*
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.mydata.R
import com.example.mydata.viewmodel.EntrepriseViewModel
import com.example.mydata.viewmodel.ImmeubleViewModel
import kotlinx.android.synthetic.main.fragment_list_entreprise.view.*
import kotlinx.android.synthetic.main.fragment_list_immeuble.view.*
class ListFragmentImmeuble : Fragment() {
private lateinit var mImmeubleViewModel: ImmeubleViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_list_immeuble, container, false)
val adapter = ListAdapterImmeuble()
val recyclerView = view.recyclerView1
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(requireContext())
mImmeubleViewModel = ViewModelProvider(this).get(ImmeubleViewModel::class.java)
mImmeubleViewModel.readAllData.observe(viewLifecycleOwner, Observer { immeuble ->
adapter.setData(immeuble)
})
view.floatingActionButton.setOnClickListener{
findNavController().navigate(R.id.action_listFragmentImmeuble_to_addFragmentImmeuble)
}
setHasOptionsMenu(true)
return view
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.delete_menu, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId==R.id.menu_delete){
deleteAllImmeubles()
}
return super.onOptionsItemSelected(item)
}
private fun deleteAllImmeubles() {
val builder = AlertDialog.Builder(requireContext())
builder.setPositiveButton("Oui"){ _, _ ->
mImmeubleViewModel.deleteAllImmeubles()
Toast.makeText(requireContext(), "Immeubles supprimés", Toast.LENGTH_SHORT).show()
}
builder.setNegativeButton("Non"){ _, _ ->
}
builder.setTitle("Supprimer la liste des immeubles? ")
builder.setMessage("Êtes vous sure de supprimer toutes les immeubles?")
builder.create().show()
}
}
and here is my ListAdapterImmeuble.kt:
package com.example.mydata.fragments.list
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.findNavController
import androidx.recyclerview.widget.RecyclerView
import com.example.mydata.R
import com.example.mydata.model.Immeuble
import kotlinx.android.synthetic.main.custom_row.view.*
class ListAdapterImmeuble : RecyclerView.Adapter<ListAdapterImmeuble.MyViewHolder>(){
private var immeubleList = emptyList<Immeuble>()
class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.custom_row,
parent, false))
}
override fun getItemCount(): Int {
return immeubleList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = immeubleList[position]
holder.itemView.id_txt.text = currentItem.idI.toString()
holder.itemView.type_et.text = currentItem.type
holder.itemView.rue_et.text = currentItem.nomRue
holder.itemView.rowLayout1.setOnClickListener{
val action =
ListFragmentImmeubleDirections.actionListFragmentImmeubleToUpdateFragmentImmeuble(currentItem)
holder.itemView.findNavController().navigate(action)
}
}
fun setData (immeuble: List<Immeuble>){
this.immeubleList = immeuble
notifyDataSetChanged()
}
}
and here is my custom_row.xml:
<?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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="24sp"
android:id="#+id/rowLayout1">
<TextView
android:id="#+id/id_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
android:textSize="40sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/type_et"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="50dp"
android:text="Immoblier"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="#+id/id_txt"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/rue_et"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:text="Boulevard X"
android:textSize="18dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="#+id/type_et"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
and here is fragment_list_immeuble.xml:
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.list.ListFragmentImmeuble">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:layout_marginBottom="24dp"
android:clickable="true"
android:focusable="true"
android:tint="#color/white"
android:src="#drawable/ic_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
I spent hours trying to find out what's wrong.. I'd be pleased if anybody could help!
I'm trying to manipulate elements from xml of a fragment, but all tries I did, result in some error. When I use root!!.qr_code.visibility = View.INVISIBLE, I got this:
What is wrong with my elements reference?
FATAL EXCEPTION: main
Process: com.example.test, PID: 26445
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.test/com.example.myapplication.MainActivity}: kotlin.KotlinNullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2946)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3081)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1831)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6810)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
Caused by: kotlin.KotlinNullPointerException
at com.example.myapplication.ui.home.HomeFragment.setElementVisibility(HomeFragment.kt:49)
at com.example.myapplication.MainActivity.onCreate(MainActivity.kt:72)
My HomeFragment: (called from onCreate in MainActivity)
package com.example.myapplication.ui.home
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.LinearLayout
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders
import com.example.myapplication.R
import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomeFragment : Fragment() {
private lateinit var homeViewModel: HomeViewModel
private var root: View? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
super.onCreate(savedInstanceState);
homeViewModel =
ViewModelProviders.of(this).get(HomeViewModel::class.java)
root = inflater.inflate(R.layout.fragment_home, container, false)
//The findViewById appears as unresolved reference.
qrcode = findViewById(R.id.qr_code) as LinearLayout
return root
}
fun setElementVisibility(permissionData: Boolean, serialData: Boolean){
//also I tried:
//qr_code.visibility = View.INVISIBLE
//which gives me the same error from above
if(!serialData){
root!!.qr_code.visibility = View.VISIBLE
root!!.failed_layout.visibility = View.VISIBLE
root!!.success_layout.visibility = View.INVISIBLE
} else if(!permissionData){
root!!.qr_code.visibility = View.INVISIBLE
root!!.failed_layout.visibility = View.VISIBLE
root!!.success_layout.visibility = View.INVISIBLE
} else if(permissionData && serialData){
root!!.qr_code.visibility = View.INVISIBLE
root!!.failed_layout.visibility = View.INVISIBLE
root!!.success_layout.visibility = View.VISIBLE
}
}
}
MainActivity call to HomeFragment:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
appBarConfiguration = AppBarConfiguration(setOf(
R.id.nav_home), drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
val homeFragment: HomeFragment = HomeFragment()
homeFragment.setElementVisibility(true, true)//this parameters won't be statics
}
My xml of fragment:
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.home.HomeFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="#+id/success_layout"
android:visibility="invisible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginVertical="50dp"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="#+id/success_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="0dp"
android:layout_marginEnd="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="0dp"
android:ems="8"
android:gravity="center"
android:text="#string/success_msg"
android:textAlignment="center"
android:textSize="24sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="#+id/failed_layout"
android:visibility="invisible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginVertical="50dp"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="#+id/failed_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="0dp"
android:layout_marginEnd="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="0dp"
android:ems="8"
android:gravity="center"
android:text="#string/failed_msg"
android:textAlignment="center"
android:textColor="#color/design_default_color_error"
android:textSize="24sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="#+id/qr_code"
android:visibility="invisible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginVertical="50dp"
android:gravity="center"
android:orientation="horizontal">
<Button
android:id="#+id/openScanner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/take_scan_qr_code" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
findViewById()is a method of the View object.
Try this :
qrcode = root.findViewById(R.id.qr_code) as LinearLayout
try this a quick solution, more details at last
class HomeFragment : Fragment(R.layout.fragment_home) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?){
super.onViewCreated(view, savedInstanceState)
setElementVisibility()
}
fun setElementVisibility(){
qr_code.visibility = View.INVISIBLE
failed_layout.visibility = View.VISIBLE
success_layout.visibility = View.INVISIBLE
}
}
So u r getting unresolve reference because as answered by bruno findviewbyId() is applied to View object. so u can use his method.
In my method u will call the function only after the view is created i.e. onViewCreated(). so u can now call directly. I called the view in fragment constructor itself. This is short and easy.
Thanks for more go through documentation.
You can't just init val homeFragment: HomeFragment = HomeFragment() and access it's view from Activity. You need to attach Fragment to activity. This is official example of usage and integration of fragments
I'm attempting to teach myself Android Development and Kotlin, and I've been stuck on this issue for a while. Because I'm relatively new, I'm almost certain it's just something I don't understand, and would really appreciate any help. parameterize_button is defined in the fragment_dashboard XML file. This XML is inflated within DashboardFragment.kt, but it still throws:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.caelussidekick, PID: 15355
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
at com.example.caelussidekick.ui.dashboard.DashboardFragment.onCreateView
Here's my XML, and I know it is parameterize_button because I haven't set any onClickListeners to any of the other buttons.
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.dashboard.DashboardFragment">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="#+id/parameterize_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/parameters_buttion" />
<TextView
android:id="#+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/outputs_header"
android:textAlignment="center"
android:textSize="20sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="#+id/dv_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/empty_string"
android:textAlignment="textEnd" />
<TextView
android:id="#+id/dv_unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/dv"
android:textAlignment="textStart" />
<Button
android:id="#+id/dv_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/dv_button" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="#+id/isp_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/empty_string"
android:textAlignment="textEnd"
android:textSize="14sp" />
<TextView
android:id="#+id/isp_unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/isp"
android:textAlignment="textStart" />
<Button
android:id="#+id/isp_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/isp_button" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
And here's my DashboardFragment.kt. This is part of the default bottom navigation activity in Android Studio, which is why a lot of the code is commented out.
package com.example.caelussidekick.ui.dashboard
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.fragment.app.Fragment
import com.example.caelussidekick.R
import androidx.appcompat.app.AppCompatActivity
import android.net.Uri
import kotlinx.android.synthetic.main.fragment_dashboard.*
class DashboardFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// dashboardViewModel =
// ViewModelProviders.of(this).get(DashboardViewModel::class.java)
val output = inflater.inflate(R.layout.fragment_dashboard, container, false)
// val textView: TextView = root.findViewById(R.id.text_dashboard)
// dashboardViewModel.text.observe(viewLifecycleOwner, Observer {
// textView.text = it
// })
this.parameterize_button.setOnClickListener{
val intent = Intent(activity, ParamActivity::class.java)
startActivity(intent)
}
return output
}
}
Thanks for any help! I'm honestly at a loss. I've looked on stackoverflow extensively, and have tried moving the button to the main activity, using nullable modifiers, and making it a field in the class, but nothing has worked.
Synthetic view bindings are not valid until onCreateView() returns - it doesn't know about your output inflated View until it is actually set as the view on the Fragment.
Therefore you can move your code to onViewCreated(), which is the method that happens immediately after onCreateView() (you should generally not be doing anything but inflating your view in onCreateView()):
class DashboardFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_dashboard, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
this.parameterize_button.setOnClickListener{
val intent = Intent(activity, ParamActivity::class.java)
startActivity(intent)
}
}
}
var parametrizedbtn = view.findViewById<Button>(R.id.parameterize_button)
parmetrizedbtn.setOnClickLIstener{
val intent = Intent(view.context,ParamActivity::class.java)
startActivity(intent)
}
may work for your