I have a recycler view and a XML file for the recycler view. I have used the recycler views inside the fragment layout. I want to access the textview id from the fragment activity for using fragment transactions.
var titleTextView = view.findViewById<TextView>(R.id.tvTitle)
val subjectFragment = SubjectFragment()
println(titleTextView.text)
the above code provides a null pointer exception
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.samachar, PID: 7038
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.CharSequence android.widget.TextView.getText()' on a null object reference
at com.example.samachar.NewsFragment.onViewCreated(NewsFragment.kt:86)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2987)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:546)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3138)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3072)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:502)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:248)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1435)
at android.app.Activity.performStart(Activity.java:8024)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3475)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
I/Process: Sending signal. PID: 7038 SIG: 9
I want to use the fragment manager to use the transactions and switch layouts
// var fragment = parentFragmentManager?.beginTransaction()
// fragment?.replace(R.id.newsFrameLayout, subjectFragment)
// fragment?.commit()
but I cannot seem to access the textview id from the fragment class.
<?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/newsItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="16dp"
android:paddingVertical="12dp">
<TextView
android:id="#+id/tvTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="#string/title_eg"
android:textColor="#color/purple_200"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tvDescription"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="#string/description_eg"
android:textSize="12sp"
android:textColor="#color/black"
android:maxLines="2"
android:justificationMode="inter_word"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvTitle" />
<TextView
android:id="#+id/tvCategory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/teal_700"
android:padding="2dp"
android:text="#string/category_eg"
android:textColor="#color/white"
android:textSize="10sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvDescription" />
<TextView
android:id="#+id/tvPublishedDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/pub_date_eg"
android:textSize="10sp"
app:layout_constraintBottom_toBottomOf="#+id/tvCategory"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>
This is the xml layout used in the recycler view of the app
EDIT***
Solved it by using the onClickListener on textview in the adapter class onBindViewHolder function and used activity context for calling the supportFragmentManager.
You should have some item click listner in your adapter class this way:
interface ItemClickListener {
fun onClick(dataYouWantInFragment:String) // or of any type
}
Then you should ask for the interface implementation of your fragment in your adapter class like below:
class YourRVAdapter(private val listener:ItemClickListener) {
override fun onBindViewHolder(holder:YourViewHolder,position:Int) {
holder.bindData(dataForPosition(position),listener)
}
class YourViewHolder(private val view:View) : RecyclerView.ViewHolder(view) {
private val tvTitle = view.findViewById<TextView>(R.id.tvTitle)
fun bindData(data:String,listener:ItemClickListener) {
tvTitle.text = data
view.setOnClickListener {
listener.onClick(tvTitle.text.toString())// pass the data you want in fragment
}
}
}
// If you used binding,
class YourViewHolder(private val binding:YourBinding) : RecyclerView.ViewHolder(binding.root) {
fun bindData(data:String,listener:ItemClickListener) {
binding.tvTitle.text = data
binding.root.setOnClickListener {
listener.onClick(tvTitle.text.toString())// pass the data you want in fragment
}
}
}
}
in your fragment class, you should implement that listener interface like below:
class YourFragmentClass() : ItemClickListener {
override fun onCreateView(...) {
..
recyclerView.adapter = YourRVAdapter(this)
..
}
override fun onClick(dataYouWant:String) {
// use this data for your fragment transaction
childFragmentManager.beginTransaction().add/replace()....commit()
}
}
Now, you should be able to get the onClick() callback in your fragment class with you desired data when you click on a recycler view item.
When you use a recyclerview there isn't a unique tvtitle id available. For each item in the recyclerview there is a tvtitle.
Although you can aceess each of them from the recyclerview adapter.
If you want to access any item of recyclerview then you need to create a event at onBindViewHolder .
Use interface or lambda funtion for getting every view inside activity or fragment.
if you want views when click event happen then implement clickListener.
Related
my application is giving the below error that you mentioned above and it says there is an error on line 69, but you have tried all the solutions and could not fix it. You are new to programming and trying to learn, so you are asking for help from experienced people like us.
Can you please help me?
Error Message:
AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.kotlincountries, PID: 15240
kotlin.UninitializedPropertyAccessException: lateinit property binding has not been initialized
at com.example.kotlincountries.adapter.CountryAdapter.onCountryClicked(CountryAdapter.kt:69)
at com.example.kotlincountries.databinding.ItemCountryBindingImpl$OnClickListenerImpl.onClick(ItemCountryBindingImpl.java:173)
at android.view.View.performClick(View.java:7506)
at android.view.View.performClickInternal(View.java:7483)
at android.view.View.-$$Nest$mperformClickInternal(Unknown Source:0)
at android.view.View$PerformClick.run(View.java:29334)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7872)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
I have enabled two options in my gradle file.
buildFeatures {
viewBinding = true
dataBinding = true
}
I checked the connections in the XML file.
<layout
xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="country"
type="com.example.kotlincountries.model.Country" />
<variable
name="listener"
type="com.example.kotlincountries.adapter.CountryClickListener" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="150dp"
android:onClick="#{listener::onCountryClicked}"
android:orientation="horizontal">
<TextView
android:id="#+id/countryUuidText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:text="#{String.valueOf(country.uuid)}">
</TextView>
<ImageView
android:id="#+id/imageView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:padding="3dp"
android:downloadUrl="#{country.imageUrl}">
</ImageView>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_vertical"
android:layout_weight="3">
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{country.countryName}"
android:padding="5dp"
android:textSize="18sp"
android:textStyle="bold">
</TextView>
<TextView
android:id="#+id/region"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{country.countryRegion}"
android:textSize="16sp"
android:padding="5dp">
</TextView>
</LinearLayout>
</LinearLayout>
</layout>
I checked the data I fetched in my adapter class.
class CountryAdapter(val countryList:ArrayList<Country>): RecyclerView.Adapter<CountryAdapter.CountryViewHolder>(),CountryClickListener {
private lateinit var binding : ItemCountryBinding
class CountryViewHolder(var view:ItemCountryBinding) :RecyclerView.ViewHolder(view.root) {
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CountryViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ItemCountryBinding.inflate(inflater, parent, false)
return CountryViewHolder(binding)
}
override fun getItemCount(): Int {
return countryList.size
}
override fun onBindViewHolder(holder: CountryViewHolder, position: Int) {
holder.view.country=countryList[position]
holder.view.listener=this
}
fun updateCountryList(newCountryList:List<Country>){
countryList.clear()
countryList.addAll(newCountryList)
notifyDataSetChanged()
}
override fun onCountryClicked(v: View) {
val uuid=binding.countryUuidText.text.toString().toInt()
val action=FeedFragmentDirections.actionFeedFragmentToCountryFragment(uuid)
Navigation.findNavController(v).navigate(action)
}
}
Could you please help me? I couldn't find a solution even though I checked the connections in my XML file, verified the data in my adapter class.
Error message is clear that binding variable which is declared as lateinit is not initialised and tried to use it in your adapter class .
and if you will check your code of adapter (as location mentioned in error) you will get that problem is in onCreateViewHolder
So just change in onCreateViewHolder method of adapter
From
val binding = ItemCountryBinding.inflate(inflater, parent, false)
To
binding = ItemCountryBinding.inflate(inflater, parent, false)
i have just removed val as you have already declared binding
I'm working on a dynamicViews (not sure if that's the right word for creating a view from a json file).
I'm getting the schema from a JSON file, I've stepped up the recycleView and its adapter, so far so good, each Recycleview item (must or not) contain a number of EditText whose number is unknown in advance, so based on the Json file, I have to inflate inside.
I searched a lot but the similar solution I found for Heterogene Recycleview: the idea was to use separate layout and inflate each of them according to your needs inside onCreateViewHolder but the developer who published the solution knew in advance what is the combination of all possible views and he just switch.
class Adapter_base_Display(private val listener: Display_Fragment,
activity: FragmentActivity ,
liste_display : ArrayList<DisplaySections>)
: RecyclerView.Adapter<Base_DisplayViewHolder>() {
private val activityIns = activity
private val liste_display_Recycle_adapter = liste_display
interface Base_DisplayListener {
fun onClickeddisplay(position: Int)
}
private val items = ArrayList<DisplaySections>()
fun setItems(items: ArrayList<DisplaySections>) {
this.items.clear()
this.items.addAll(items)
notifyDataSetChanged()
}
fun clear() {
val size: Int = items.size
items.clear()
notifyItemRangeRemoved(0, size)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Base_DisplayViewHolder {
val binding: ItemDisplayBinding =
ItemDisplayBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return Base_DisplayViewHolder(
binding,
listener as Base_DisplayListener,
activityIns,
parent,
liste_display_Recycle_adapter)
}
override fun getItemCount(): Int = items.size
override fun onBindViewHolder(holder: Base_DisplayViewHolder, position: Int) =
holder.bind(items[position])
}
class Base_DisplayViewHolder(
private val itemBinding: ItemDisplayBinding,
private val listener: Adapter_base_Display.Base_DisplayListener,
private val activityIns: FragmentActivity,
private var parent: ViewGroup,
private val items: ArrayList<DisplaySections>,
) : RecyclerView.ViewHolder(itemBinding.root),
View.OnClickListener {
init {
itemBinding.root.setOnClickListener(this)
}
fun bind(item: DisplaySections) {
itemBinding.textView2.text = item.name
}
override fun onClick(v: View?) {
listener.onClickeddisplay(adapterPosition)
}
}
The EditText I want to inflate multiple time
<EditText
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/edittext_isplay"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp"
android:text="TextView"
android:maxLines="3"
android:textColor="#color/black"
android:textSize="18sp" />
data class DisplaySections(
val id : Int,
val name : String,
val createdAt : String,
val updatedAt : String,
val displayTypeId : Int,
val displayCustomFields : List<DisplayCustomFields> // Contains the elements that will be displayed as EditText
The Base layout-Recycleview Item which is common for all scenarios
<LinearLayout
android:id="#+id/parent_edittext" // ALl EditText container
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="#+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
<LinearLayout
android:id="#+id/camera_linear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:id="#+id/addphoto"
android:layout_width="316dp"
android:layout_height="250dp"
android:layout_gravity="center"
android:layout_marginTop="#dimen/_20sdp"
android:src="#drawable/ajouter_photo"
app:tint="#color/clear_grey" />
<TextView
android:id="#+id/camera_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Ajouter des photos"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="#+id/plus_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/_20sdp"
android:gravity="center"
android:orientation="vertical"
android:visibility="visible">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/my_photo_recycle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
I going to post the solution I found.
To solve this problem, we absolutely must use a nested RecyclerView;
As I said above, I want to display a list of items with the same common layout (Imageview + Textview), but the tricky part here is the dynamic part of each item.
For recap:
Each element (may or may not) contain N-1 (EditText), it depends on what it gets from a json file.
if you want to solve this problem by creating multiple Viewholder and switch depending on which "ViewHolderType" you are wrong !, you will just create an infinite layout files, it doesn't make sense.
if you create more than one (EditText) and only change the visibility it may work, but if you get for example 100 EditText from the Json file you are not going to manually create 100 Edittext.
if you want to programmatically generate an EditText, you will affect every item in your view Recycle since you cannot create view inside OnbindViewHolder function.
the only way I found to solve this problem is to create a parent-child RecycleView whenever there is an (EditText) you send it to the child adapter and you keep your parent element safe in the parent adapter.
You can also put a condition (NULL tester) inside the Parent-OnbindViewholder whenever there is no data, you just don't call Child-adapter.
I hope this solution will be useful to anyone who has had this problem, and if you have another solution I will be very happy to test them.
**The XMl file where from calling method of view Model**
<variable
name="viewModelDetail"
type="com.joyor.viewmodel.HomeViewModel" />
</data>
<ImageView
android:id="#+id/profile"
android:layout_width="#dimen/_30sdp"
android:layout_height="match_parent"
android:layout_marginEnd="#dimen/_5sdp"
android:onClick="#{viewModelDetail.onProfileClick}"
android:padding="#dimen/_5sdp"
android:src="#drawable/ic_profile"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
....
......
.......
View Model Class implementation where on click for invoke method
class HomeViewModel : ViewModel() {
var isProfileClick: MutableLiveData<Boolean> = MutableLiveData()
fun onProfileClick(view:View) {
isProfileClick.value = true
}
}
How to invoke method for imageView on click in MVVM to invoke viewModel method
Make this changes to your onClick attribute
android:onClick="#{() -> viewModelDetail.onProfileClick}"
Also in your Activity/Fragment class make sure you are setting ViewModel property and call execute pending bindings, like below.
binding.viewModel = viewModel
binding.lifecycleOwner = this
binding.executePendingBindings()
I have a ViewPager2 which I'm using with a RecyclerView Adapter. I'm binding the children of each viewpager item via the ViewHolder and everything is working okay.
I have a bunch of elements in this ViewPager item XML, some RadioButton components and a Button. I want this button to move it to the next item.
I know how to do that externally, assigning a sibling to the ViewPager2 and then setting a click-listener in the activity and then comparing currentItem of the ViewPager with the adapter's total item count.
I want the "Move to next" button inside the ViewPager as I want to change it based on the inputs supplied to the RadioButton components.
I'm currently stuck at failing getting the ViewPager item's button in the activity to set the click-listener. Is there any workaround to get the child element via the adapter itself?
Here's the activity_quiz.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=".ui.quiz.view.QuizActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/quiz_list"
android:layout_width="match_parent"
android:layout_height="600dp"
android:clipToPadding="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="16dp"
tools:listitem="#layout/quiz_item" />
</androidx.constraintlayout.widget.ConstraintLayout>
The quiz_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:orientation="vertical"
android:padding="#dimen/bigSpacing"
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/question"/>
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/choices">
<RadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/choice_1"/>
<RadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/choice_2"/>
<RadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/choice_3"/>
<RadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/choice_4"/>
</RadioGroup>
<Button
android:id="#+id/result_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Next question" />
</LinearLayout>
The MyAdapter class (kotlin)
class MyAdapter: RecyclerView.Adapter<MyAdapter.MyViewHolder> {
override fun onCreateViewHolder(...) {
...
}
override fun getItemCount(): Int {
...
}
override fun onBindViewHolder(...) {
...
}
class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
fun bind(someData: SomeData) {
itemView.question.text = somedata.question
itemView.choice_1.text = somedata.choice_1
itemView.choice_2.text = somedata.choice_2
itemView.choice_3.text = somedata.choice_3
itemView.choice_4.text = somedata.choice_4
val answerKey = someData.answerKey
var rightOrWrong = ""
itemView.choices.setOnCheckedChangeListener {_, checkedID ->
val checkedIndex: Int = itemView.choices.indexOfChild(itemView.choices.findViewById(checkedID))
if(checkedIndex + 1 == answerKey.toInt()) {
rightOrWrong = "Correct! Next Question."
} else {
rightOrWrong = "Incorrect :/ Next Question."
}
itemView.result_button.text = rightOrWrong
}
}
}
And the QuizActivity.kt file
class QuizActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_quiz)
val myAdapter = MyAdapter()
quiz_list.adapter = myAdapter
// quiz_list.result_button.setOnClickListener {
// No idea how to get the children correctly, as this one throws errors
// }
}
}
First, why do you want to use RecyclerView.Adapter<MyAdapter.MyViewHolder> as an adapter for viewpager2? There is FragmentStateAdapter a built-in class implementation of PagerAdapter that uses a Fragment to manage each page, which is recommended for viewpager2.
Second, you are not inflating the views in MyViewHolder, I don't know if you left them intentionally for this post.
You cant access child views like this quiz_list.result_button.setOnClickListener {} while using something like RecyclerView, Viewpagger. You can access them in the ViewHolder after you inflate them, you can set any listener there aswell
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 3 years ago.
So I have recycler view with the data from public API. I have activity_main.xml just for the FrameLayout, fragment_main.xml for the recyclerView and user_row.xml for the user row in the recycler view. When I start the app it does not even load up and shuts down with error saying:
" java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference "
This is the MainActivity. Its just for the fragment call
class MainActivity : AppCompatActivity(), BlankFragment.OnFragmentInteractionListener {
lateinit var blankFragment: BlankFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
blankFragment = BlankFragment.newInstance()
supportFragmentManager
.beginTransaction()
.add(R.id.fragmentContainer,blankFragment)
.addToBackStack(blankFragment.toString())
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
as you can see the error is caused by the Button click. The button is for calling another fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
detailBtn.setOnClickListener {
detailFragment = DetailFragment.newInstance(idTV.text.toString().toInt())
fragmentManager!!.beginTransaction()
.replace(R.id.fragmentContainer, detailFragment)
.addToBackStack(BlankFragment.toString())
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
I have tried doing
val btn: Button = detailBtn!!
but the error changed to the NullPointerException
Its maybe because the detailBtn is in another layout, but I am not sure and I don't know how I would fix it.
Here`s the main_activity.xml layout
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:id="#+id/fragmentContainer"
android:layout_height="match_parent">
</FrameLayout>
Here's the fragment_main.xml layout
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
and here's the user_row layout with the Button and with the idTextView (idTV)
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:onClick="itemClicked"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:layout_marginLeft="16dp"
android:id="#+id/idTV"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="#+id/usernameTV"
tools:text="ID"
android:textSize="25sp"
android:textColor="#D32F2F"
android:padding="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_marginLeft="16dp"
android:id="#+id/usernameTV"
app:layout_constraintStart_toEndOf="#+id/idTV"
app:layout_constraintTop_toTopOf="parent"
tools:text="Userame"
android:textSize="25sp"
android:textColor="#000"
android:padding="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:text="+"
android:textSize="35sp"
android:layout_marginRight="16dp"
android:id="#+id/detailBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#E91E63"/>
<View
app:layout_constraintTop_toBottomOf="#id/usernameTV"
android:layout_width="match_parent"
android:layout_height="3px"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:background="#000"/>
</android.support.constraint.ConstraintLayout>
Please add full code before asking the question. I'd be interested to see where you made findViewById(R.id.buttonId) call in your fragment. NullPointerException generally occurs in code if forget to make findViewById call on the view. It also occurs if you made the findViewById call, but the view you're trying to find is in different layout/view hierarcy. I'd be able to help you if you post the full code.(I do not have commenting privileges as of yet)
Your detailBtn is part of a RecyclerView cell. Therefore it's not yet attached to the view hierarchy and might not even be unique in it.
You'd have to define the OnClickListener with your RecyclerView.Adapter pass the information to the fragment.
adapter.setOnClickListener { idTV ->
detailFragment = DetailFragment.newInstance(idTV.text.toString().toInt())
fragmentManager!!.beginTransaction()
.replace(R.id.fragmentContainer, detailFragment)
.addToBackStack(BlankFragment.toString())
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
class Adapter : RecyclerView.Adapter() {
private lateinit var listener: (TextView) -> Unit
fun setOnClickListener(listener: (TextView) -> Unit) {
this.listener = listener
}
override fun onCreateViewHolder(parent: ViewGroup, type: Int): ViewHolder {
val viewHolder = ...
viewHolder.itemView.run {
detailBtn.setOnClickListener {
listener(idTV)
}
}
return viewHolder
}
}