I am facing Crash in Firebase Crashlytics on bind method but unable to find the root cause. I have added a Null check but still, the issue not fixed.
Firebase Crash Report
Fatal Exception: java.util.NoSuchElementException: Collection is empty.
at kotlin.collections.CollectionsKt___CollectionsKt.first(_Collections.kt:184)
at com.transferhome.contacts.ContactsAdapter.bind(ContactsAdapter.kt:25)
at com.transferhome.contacts.ContactsBaseAdapter.onBindViewHolder(ContactsBaseAdapter.kt:38)
at com.transferhome.contacts.ContactsBaseAdapter.onBindViewHolder(ContactsBaseAdapter.kt:19)
at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6781)
at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6823)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5752)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6019)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5858)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5854)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2230)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1557)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:612)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3924)
at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3336)
at android.view.View.measure(View.java:22216)
at androidx.constraintlayout.widget.ConstraintLayout.internalMeasureChildren(ConstraintLayout.java:1227)
at androidx.constraintlayout.widget.ConstraintLayout.onMeasure(ConstraintLayout.java:1572)
at android.view.View.measure(View.java:22216)
at androidx.viewpager.widget.ViewPager.onMeasure(ViewPager.java:1638)
at android.view.View.measure(View.java:22216)
at androidx.constraintlayout.widget.ConstraintLayout.onMeasure(ConstraintLayout.java:1676)
at android.view.View.measure(View.java:22216)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6671)
at androidx.coordinatorlayout.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:733)
at com.google.android.material.appbar.HeaderScrollingViewBehavior.onMeasureChild(HeaderScrollingViewBehavior.java:95)
at com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior.onMeasureChild(AppBarLayout.java:1556)
at androidx.coordinatorlayout.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:803)
at android.view.View.measure(View.java:22216)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6671)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:143)
at android.view.View.measure(View.java:22216)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6671)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1539)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:823)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:702)
at android.view.View.measure(View.java:22216)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6671)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:22216)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6671)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1539)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:823)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:702)
at android.view.View.measure(View.java:22216)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6671)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:831)
at android.view.View.measure(View.java:22216)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2589)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1631)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1885)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1515)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7266)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:981)
at android.view.Choreographer.doCallbacks(Choreographer.java:790)
at android.view.Choreographer.doFrame(Choreographer.java:721)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:967)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:101)
at android.os.Looper.loop(Looper.java:166)
at android.app.ActivityThread.main(ActivityThread.java:7529)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)
ContactsAdapter.kt
class ContactsAdapter ( private val onItemSelect: (contact: Contact) -> Unit )
: ContactsBaseAdapter<ItemContactFavListBinding>() {
var contactFavSignal = MutableLiveData<Contact>().apply { }
override fun bind(contact: Contact, holder: ContactVH<ItemContactFavListBinding>) {
val binding = holder.binding
binding.contactName.text = contact.name
binding.contactNumber.text = contact.numbers.first().phone
binding.imgContactHeart.setOnClickListener(View.OnClickListener {
val backgroundImageName = (binding.imgContactHeart.getTag()).toString()
if(backgroundImageName.equals("2")) {
binding.imgContactHeart.setImageResource(R.drawable.heart_selected_yellow)
EventBus.getDefault().post(CustomEvent(contact,true));
binding.imgContactHeart.setTag("1")
binding.imgContactHeart.setImageResource(R.drawable.heart_selected_yellow)
}else if(backgroundImageName.equals("1")) {
binding.imgContactHeart.setImageResource(R.drawable.heart_selected_yellow)
EventBus.getDefault().post(CustomEvent(contact,false));
binding.imgContactHeart.setTag("2")
binding.imgContactHeart.setImageResource(R.drawable.heart)
}
})
var num = contact.numbers.first().phone
if(num.contains(" "))
num = num.replace(" ","")
if(num.startsWith("0"))
num = num.removePrefix("0")
if(num.startsWith("+"))
num = num.removePrefix("+")
var isFav:Boolean=false
for (x in 0..FavoritesFragment.listFavNumbers.size-1)
{
var num2 = FavoritesFragment.listFavNumbers[x]
if(num2.endsWith(num))
isFav=true
}
if(isFav)
{
binding.imgContactHeart.setTag("1")
binding.imgContactHeart.setImageResource(R.drawable.heart_selected_yellow)
}
else
{
binding.imgContactHeart.setTag("2")
binding.imgContactHeart.setImageResource(R.drawable.heart)
}
showContactProfileImage(contact, binding.contactImage)
holder.binding.root.setOnClickListener {
onItemSelect.invoke(contact)
}
}
override fun provideBinding(inflater: LayoutInflater, parent: ViewGroup): ItemContactFavListBinding {
return ItemContactFavListBinding.inflate(inflater, parent, false)
}
}
ContactBaseAdater.kt
abstract class ContactsBaseAdapter<T : ViewDataBinding> :
PagedListAdapter<Contact, ContactsBaseAdapter.ContactVH<T>>(object : DiffUtil.ItemCallback<Contact>() {
override fun areItemsTheSame(oldItem: Contact, newItem: Contact): Boolean {
return oldItem.name == newItem.name || oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Contact, newItem: Contact): Boolean {
return oldItem.name == newItem.name
}
} ) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContactVH<T> {
return ContactVH(provideBinding(LayoutInflater.from(parent.context), parent))
}
override fun onBindViewHolder(holder: ContactVH<T>, position: Int) {
val contact = getItem(position)
if (contact != null) {
bind(contact, holder)
}
}
abstract fun bind(contact: Contact, holder: ContactVH<T>)
abstract fun provideBinding(inflater: LayoutInflater, parent: ViewGroup): T
class ContactVH<T : ViewDataBinding>(val binding: T) : RecyclerView.ViewHolder(binding.root)
fun showContactProfileImage(contact: Contact, imageHolder: ImageView?) {
UiUtils.showContactProfileImage(contact, imageHolder)
}
}
item_contact_fav_list.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<RelativeLayout android:layout_width="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="#+id/contact_image"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_alignParentLeft="true"
android:contentDescription="#null"/>
<LinearLayout android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="vertical"
android:weightSum="2"
android:layout_toLeftOf="#+id/img_contact_heart"
android:layout_toRightOf="#+id/contact_image"
android:layout_marginLeft="5dp">
<TextView
android:id="#+id/contact_name"
android:textSize="16sp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="middle"
android:focusable="false"
android:textColor="#color/colorBlack"
android:layout_marginTop="3dp"
tools:text="Contact Name"/>
<TextView
android:id="#+id/contact_number"
android:textSize="15sp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="1"
android:singleLine="true"
android:textColor="#android:color/darker_gray"
tools:text="Contact Name"
android:layout_marginLeft="5dp"
/>
</LinearLayout>
<ImageView
android:layout_alignParentRight="true"
android:id="#+id/img_contact_heart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/heart"
android:layout_centerVertical="true"
/>
</RelativeLayout>
</layout>
Let's take a look at the stacktrace:
Fatal Exception: java.util.NoSuchElementException: Collection is empty.
at kotlin.collections.CollectionsKt___CollectionsKt.first(_Collections.kt:184)
at com.transferhome.contacts.ContactsAdapter.bind(ContactsAdapter.kt:25)
Most probably, the line referred to is this one:
binding.contactNumber.text = contact.numbers.first().phone
the call to first() in particular. If contact.numbers is empty, first() will throw a NoSuchElementException. Your code does not handle this case.
The easiest solution would be to set the text to null if there are no numbers:
binding.contactNumber.text = contact.numbers.firstOrNull()?.phone
Why would you add a nullcheck if the exception was not a NullPointerException?
Related
I have 2 activities. Which I tried to convert into fragments but somehow, the code I use for the activities won't work within fragments. I get a bunch of errors.
The first activity is a card where when clicked a random text will appear and the card is flipping.
The second activity is a timer with a 3th party progress bar that the fragment gives an error.
Now my question is, how can I use 2 activities within a tabLayout since I cannot convert the activity code into a fragment?
I have been searching the internet for hours but I can only find that you can use fragments within a tabLayout.
Is there a tutorial on how to create a tabLayout with 2 activities?
I also followed the tutorial https://mkyong.com/android/android-tablayout-example/ but that didn't work.
This is my Timer activity:
Kotlin:
class NewTimerActivity : AppCompatActivity() {
enum class TimerState {
Stopped, Paused, Running
}
private lateinit var timer: CountDownTimer
private var timerLengthSeconds: Int = 30
private var timerState = TimerState.Stopped
private var secondsRemaining = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_new_timer)
val display = supportActionBar
display?.title = ""
display?.setDisplayHomeAsUpEnabled(true)
val fab_start = findViewById<Button>(R.id.fab_start)
val fab_pause = findViewById<Button>(R.id.fab_pause)
val fab_stop = findViewById<Button>(R.id.fab_stop)
fab_start.setOnClickListener {
startTimer()
timerState = TimerState.Running
updateButtons()
}
fab_pause.setOnClickListener {
timer.cancel()
timerState = TimerState.Paused
updateButtons()
}
fab_stop.setOnClickListener {
timer.cancel()
onTimerFinished()
updateButtons()
}
}
override fun onResume() {
super.onResume()
initTimer()
}
override fun onPause() {
super.onPause()
if (timerState == TimerState.Running) {
timer.cancel()
} else if (timerState == TimerState.Paused) {
}
PrefUtil.setPreviousTimerLengthSeconds(timerLengthSeconds, this)
PrefUtil.setSecondsRemaining(secondsRemaining, this)
PrefUtil.setTimerState(timerState, this)
}
fun initTimer() {
timerState = PrefUtil.getTimerState(this)
if (timerState == TimerState.Stopped)
setNewTimerLength()
else
setPreviousTimerLength()
secondsRemaining = if (timerState == TimerState.Running || timerState == TimerState.Paused)
PrefUtil.getSecondsRemaining(this).toInt()
else
timerLengthSeconds
if (timerState == TimerState.Running)
startTimer()
updateButtons()
updateCountdownUI()
}
private fun onTimerFinished() {
var progress_countdown = findViewById<ProgressBar>(R.id.progress_countdown)
timerState = TimerState.Stopped
setNewTimerLength()
progress_countdown.progress = 0
PrefUtil.setSecondsRemaining(timerLengthSeconds, this)
secondsRemaining = timerLengthSeconds
updateButtons()
updateCountdownUI()
}
private fun startTimer() {
timerState = TimerState.Running
timer = object : CountDownTimer((secondsRemaining * 1000).toLong(), 1000) {
override fun onFinish() = onTimerFinished()
override fun onTick(millisUntilFinished: Long) {
secondsRemaining = (millisUntilFinished / 1000).toInt()
updateCountdownUI()
}
}.start()
}
private fun setNewTimerLength() {
var progress_countdown = findViewById<ProgressBar>(R.id.progress_countdown)
var lengthInMinutes = PrefUtil.getTimerLength(this)
timerLengthSeconds = ((lengthInMinutes * 60L).toInt())
progress_countdown.max = timerLengthSeconds.toInt()
}
private fun setPreviousTimerLength() {
var progress_countdown = findViewById<ProgressBar>(R.id.progress_countdown)
timerLengthSeconds = PrefUtil.getPreviousTimerLengthSeconds(this).toInt()
progress_countdown.max = timerLengthSeconds.toInt()
}
private fun updateCountdownUI() {
var progress_countdown = findViewById<ProgressBar>(R.id.progress_countdown)
val textView_Countdown = findViewById<TextView>(R.id.timer_textview)
val minutesUntilFinished = secondsRemaining / 60
val secondsInMinutesUntilFinished = secondsRemaining - minutesUntilFinished * 60
val secondsStr = secondsInMinutesUntilFinished.toString()
textView_Countdown.text = "$minutesUntilFinished:${
if (secondsStr.length == 2) secondsStr
else "0" + secondsStr}"
progress_countdown.progress = (timerLengthSeconds - secondsRemaining).toInt()
}
private fun updateButtons() {
val fab_start = findViewById<Button>(R.id.fab_start)
val fab_pause = findViewById<Button>(R.id.fab_pause)
val fab_stop = findViewById<Button>(R.id.fab_stop)
when (timerState) {
TimerState.Running -> {
fab_start.isEnabled = false
fab_pause.isEnabled = true
fab_stop.isEnabled = true
}
TimerState.Stopped -> {
fab_start.isEnabled = true
fab_pause.isEnabled = false
fab_stop.isEnabled = false
}
TimerState.Paused -> {
fab_start.isEnabled = true
fab_pause.isEnabled = false
fab_stop.isEnabled = true
}
}
}
}
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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/achtergrondnowhite"
tools:context=".NewTimerActivity">
<TextView
android:id="#+id/timer_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:text="30"
android:textColor="#FFF"
android:textSize="70dp" />
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/Theme.KlimaatAmbitieGame.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/Theme.KlimaatAmbitieGame.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="#+id/progress_countdown"
style="#style/Widget.MaterialProgressBar.ProgressBar"
android:layout_width="306dp"
android:layout_height="306dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="52dp"
android:layout_marginTop="215dp"
android:layout_marginEnd="52dp"
android:layout_marginBottom="210dp"
android:minWidth="306dp"
android:minHeight="306dp"
app:mpb_indeterminateTint="#color/white"
app:mpb_progressBackgroundTint="#color/white"
app:mpb_progressTint="#color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/fab_stop"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom|end"
android:layout_marginStart="274dp"
android:layout_marginEnd="27dp"
android:layout_marginBottom="131dp"
android:background="#color/black"
android:minWidth="50dp"
android:minHeight="50dp"
android:text="Stop"
android:textColor="#color/white"
app:srcCompat="#drawable/ic_stop" />
<Button
android:id="#+id/fab_pause"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom|center"
android:layout_marginStart="156dp"
android:layout_marginTop="#dimen/bigger_fab_margin"
android:layout_marginEnd="151dp"
android:layout_marginBottom="131dp"
android:background="#color/black"
android:minWidth="150dp"
android:minHeight="50dp"
android:text="Pause"
android:textColor="#color/white"
app:srcCompat="#drawable/ic_pause" />
<Button
android:id="#+id/fab_start"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom|start"
android:layout_marginStart="45dp"
android:layout_marginTop="#dimen/bigger_fab_margin"
android:layout_marginEnd="280dp"
android:layout_marginBottom="133dp"
android:background="#color/black"
android:minWidth="100dp"
android:minHeight="50dp"
android:text="Start"
android:textColor="#color/white" />
</RelativeLayout>
PrefUtil
class PrefUtil {
companion object {
fun getTimerLength(context: Context): Double {
//placeholder
return 0.5
}
//private var defValue: Long
private const val PREVIOUS_TIMER_LENGTH_SECONDS_ID = "com.resoconder.timer.previous_timer_length"
fun getPreviousTimerLengthSeconds(context: Context): Long {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
return preferences.getLong(PREVIOUS_TIMER_LENGTH_SECONDS_ID, 0)
}
fun setPreviousTimerLengthSeconds(seconds: Int, context: Context) {
val editor = PreferenceManager.getDefaultSharedPreferences(context).edit()
editor.putLong(PREVIOUS_TIMER_LENGTH_SECONDS_ID, seconds.toLong())
editor.apply()
}
private const val TIMER_STATE_ID = "com.resocoder.timer.timer_state"
fun getTimerState(context: Context): NewTimerActivity.TimerState {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
val ordinal = preferences.getInt(TIMER_STATE_ID, 0)
return NewTimerActivity.TimerState.values()[ordinal]
}
fun setTimerState(state: NewTimerActivity.TimerState, context: Context) {
val editor = PreferenceManager.getDefaultSharedPreferences(context).edit()
val ordinal = state.ordinal
editor.putInt(TIMER_STATE_ID, ordinal)
editor.apply()
}
private const val SECONDS_REMAINING_ID = "com.resoconder.timer.previous_timer_length"
fun getSecondsRemaining(context: Context): Long {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
return preferences.getLong(SECONDS_REMAINING_ID, 0)
}
fun setSecondsRemaining(seconds: Int, context: Context) {
val editor = PreferenceManager.getDefaultSharedPreferences(context).edit()
editor.putLong(SECONDS_REMAINING_ID, seconds.toLong())
editor.apply()
}
}
}
And this is my Card activity:
Kotlin:
class StartKaartActivity : AppCompatActivity() {
lateinit var front_anim:AnimatorSet
lateinit var back_anim:AnimatorSet
var isFront = false
#SuppressLint("ResourceType")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_start_kaart)
//Set Backbutton Bar
val display = supportActionBar
display?.title = ""
display?.setDisplayHomeAsUpEnabled(true)
display?.setDisplayUseLogoEnabled(true)
display?.setLogo(R.drawable.logo)
val scale = applicationContext.resources.displayMetrics.density
val tvstartkaart = findViewById<TextView>(com.fotf.klimaatambitiegame.R.id.tvstartkaart)
val tvstartkaartachterkant = findViewById<TextView>(com.fotf.klimaatambitiegame.R.id.tvstartkaartachterkant)
tvstartkaart.cameraDistance = 8000 * scale
tvstartkaartachterkant.cameraDistance = 8000 * scale
front_anim = AnimatorInflater.loadAnimator(applicationContext, R.anim.font_animation) as AnimatorSet
back_anim = AnimatorInflater.loadAnimator(applicationContext, R.anim.back_animation) as AnimatorSet
val Carts = arrayOf("" +
"Random Text",
)
tvstartkaart.setOnClickListener() {
if (isFront) {
front_anim.setTarget(tvstartkaart)
back_anim.setTarget(tvstartkaartachterkant)
front_anim.start()
back_anim.start()
isFront = false
} else {
val random = Carts.random()
tvstartkaart.setText(random)
front_anim.setTarget(tvstartkaartachterkant)
back_anim.setTarget(tvstartkaart)
front_anim.start()
back_anim.start()
isFront = true
}
};
}
}
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"
android:background="#drawable/achtergrondnowhite"
tools:context=".StartKaartActivity">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="176dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="177dp"
android:paddingHorizontal="10dp"
android:text="Klik op de kaart om een nieuwe kaart te krijgen. \n\nGeef het goede antwoord op de vraag en verdien een houder."
android:textColor="#color/white"
android:textSize="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tvstartkaart"
android:layout_width="350dp"
android:layout_height="450dp"
android:layout_marginTop="28dp"
android:background="#drawable/kaartstartvoorkant"
android:gravity="left|center"
android:padding="15dp"
android:paddingHorizontal="10dp"
android:text=""
android:textColor="#color/black"
android:textSize="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.491"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView" />
<TextView
android:id="#+id/tvstartkaartachterkant"
android:layout_width="350dp"
android:layout_height="450dp"
android:layout_marginTop="28dp"
android:background="#drawable/kaartstartachterkant"
android:gravity="left|center"
android:padding="15dp"
android:paddingHorizontal="10dp"
android:textColor="#color/black"
android:textSize="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.491"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
I'm using Recycler view to show items in my Fragment named Recent History. I want to display user data from firebase to my recent history Fragment. But the recycler view is not showing on the fragment. Please Help me out in this. What did I do wrong here? or what's the solution so that my fragment shows the recycler view.
Recent History Fragment Code:
`
class recent_history : Fragment(R.layout.fragment_recent_history) {
private var binding: FragmentRecentHistoryBinding? = null
private lateinit var auth: FirebaseAuth
var database: FirebaseDatabase? = null
var databaseReference: DatabaseReference? = null
private lateinit var userArrayList: ArrayList<User>
private lateinit var myAdapter: AdapterClass
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentRecentHistoryBinding.inflate(inflater, container, false)
return binding!!.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
auth = FirebaseAuth.getInstance()
database = FirebaseDatabase.getInstance()
databaseReference = database?.reference!!.child("Users").child("result")
userArrayList= arrayListOf()
myAdapter=AdapterClass(userArrayList)
binding?.recyclerview.apply {
binding?.recyclerview?.adapter = myAdapter
var linearLayoutManager = LinearLayoutManager(activity)
binding?.recyclerview?.layoutManager = linearLayoutManager
binding?.recyclerview?.setHasFixedSize(true)
}
getData()
}
override fun onDestroy() {
super.onDestroy()
binding = null
}
private fun getData() {
val user = auth.currentUser
databaseReference?.child(user?.uid!!)
databaseReference!!.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
for (data in snapshot.children) {
var model = data.getValue(User::class.java)
userArrayList.add(model!!)
}
}
}
override fun onCancelled(error: DatabaseError) {
Log.e("cancel", error.toString())
}
})
}
}
`
Fragment Recent History Layout
<?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"
android:background="#color/white"
tools:context=".recent_history">
<TextView
android:id="#+id/profiletitle"
android:layout_width="389dp"
android:layout_height="46dp"
android:layout_marginStart="4dp"
android:layout_marginTop="28dp"
android:fontFamily="monospace"
android:text="Recent Search History"
android:textAlignment="center"
android:textColor="#color/Twit"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</TextView>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="220dp"
android:layout_height="664dp"
android:layout_marginBottom="100dp"
android:orientation="vertical"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/profiletitle"
tools:listitem="#layout/adapterview">
</androidx.recyclerview.widget.RecyclerView>
</androidx.constraintlayout.widget.ConstraintLayout>
I'm sending data to firebase from another Fragment named keyword Fragment.
Code of keyword fragment:
class keywordfrag : Fragment() {
private var binding: FragmentKeywordfragBinding? = null
private lateinit var auth: FirebaseAuth
var database: FirebaseDatabase? = null
var databaseReference: DatabaseReference? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentKeywordfragBinding.inflate(inflater, container, false)
return binding!!.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
auth = FirebaseAuth.getInstance()
database = FirebaseDatabase.getInstance()
val user = auth.currentUser
databaseReference?.child(user?.uid!!)
databaseReference = database?.getReference("Users")?.child("result")
binding?.analyzebtn?.setOnClickListener {
sendData()
}
}
override fun onDestroy() {
super.onDestroy()
binding = null
}
private fun sendData() {
val keywordtext = binding?.userenteredkeyword?.text.toString().trim()
val timestamp = Timestamp(System.currentTimeMillis())
val timendate = timestamp.toString().trim()
// val username=auth.currentUser?.uid.toString().trim()
// val email=auth.currentUser?.email.toString().trim()
if (TextUtils.isEmpty(keywordtext)) {
binding?.userenteredkeyword?.error = "keyword can not be Empty"
} else {
val model = User(keywordtext, timendate)
val user = auth.currentUser
databaseReference?.child(user?.uid!!)?.setValue(model)
binding?.userenteredkeyword?.setText("")
val currentUser = auth.currentUser
val currentUserdb = databaseReference?.child((currentUser?.uid!!))
currentUserdb?.child("keywordtext")?.setValue(keywordtext)
currentUserdb?.child("timendate")?.setValue(timendate)
}
}
}
Adapter Class:
package com.example.emotela_finalyearproject
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.emotela_finalyearproject.databinding.AdapterviewBinding
import kotlin.collections.ArrayList
class AdapterClass(var list:ArrayList<User>) :RecyclerView.Adapter<AdapterClass.ViewHolder>() {
class ViewHolder(val binding: AdapterviewBinding) : RecyclerView.ViewHolder(binding.root) {
var keyword = binding.keywordtv
var timenddate=binding.timendatetv
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = AdapterviewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
with(holder) {
with(list[position]) {
keyword.text = this.keywordtext
timenddate.text= this.timendate
}
}
}
}
Adapter view Layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:cardElevation="8dp"
app:cardCornerRadius="8dp"
android:layout_margin="16dp">
<LinearLayout
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginVertical="6dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="336dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="#+id/keywordtitle"
android:layout_width="141dp"
android:layout_height="35dp"
android:fontFamily="monospace"
android:text="searched word: "
android:textSize="10sp"
android:textStyle="bold">
</TextView>
<TextView
android:id="#+id/keywordtv"
android:layout_width="143dp"
android:layout_height="36dp"
android:fontFamily="monospace"
android:textSize="10sp">
</TextView>
<TextView
android:id="#+id/timeanddatetitle"
android:layout_width="160dp"
android:layout_height="36dp"
android:fontFamily="monospace"
android:text="Time and Date: "
android:textSize="10sp"
android:textStyle="bold">
</TextView>
<TextView
android:id="#+id/timendatetv"
android:layout_width="171dp"
android:layout_height="48dp"
android:fontFamily="monospace"
android:textSize="10sp">
</TextView>
<LinearLayout
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginVertical="6dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="336dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:orientation="vertical">
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
Result in Emulator:
You need to calll
imageAdapter.notifyDataSetChanged()
after you fetch the data from firebase.
AutoCompleteTextView is Replace with Spinner. AutoCompleteTextview inside TextInputLayout in Xml.
Data Fill using Custom ArrayAdapter in AutoCompeleteTextView but Data is not Show in AutoComplete TextView dropdowm.
MainActivity.kt
val numberList = ArrayList<Serve>()
numberList.add(Serve("101"))
numberList.add(Serve("101/2"))
numberList.add(Serve("201"))
numberList.add(Serve("202/3"))
numberList.add(Serve("205/1"))
val adapterSeveNo = CustomArrayAdapter(this,serveNo)
binding.autoCTVServeNo.setAdapter(adapterSeveNo)
binding.autoCTVServeNo.setOnItemClickListener { adapterView, view, i, l ->
val selectedItem = adapterView.getItemAtPosition(i).toString()
Toast.makeText(this,selectedItem,Toast.LENGTH_LONG).show()
}
activity.main.xml
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/tilListNumber"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
app:boxBackgroundMode="outline"
app:endIconMode="clear_text"
android:hint="Select Number.*"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btnProductNext">
<AutoCompleteTextView
android:id="#+id/autoCTVServeNo"
android:layout_width="match_parent"
android:layout_height="60dp"
android:paddingStart="10dp"
android:paddingLeft="10dp"
android:inputType="none"/>
</com.google.android.material.textfield.TextInputLayout>
CustomArrayAdapter.kt
class CustomArrayAdapter( context: Context, val serveNo : ArrayList<Serve>) : ArrayAdapter<Serve>(context,0,serveNo) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val binding = DropDownItemBinding.inflate(inflater)
val ser = serveNo.get(position)
binding.tvDropDown.text = ser.serveNo
return binding.root
}
}
drop_down_item.xml
<TextView
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/tvDropDown"
android:padding="16dp"
android:maxLines="1"
android:ellipsize="end"
android:textAppearance="#style/TextAppearance.MaterialComponents.Subtitle1">
</TextView>
AutoCompleteTextview drop down is not data fill from ArrayList using ArrayAdapter in Viewbinding.
I've made an app with 4 fragments, each of which represents the app page. Now, inside one of the fragments I've got a ToggleButton. I am trying to get OnClickListener so that it changes the button's background colour once clicked. I'm coding this in my MainActivity.kt and not in the Fragments. However, it crashes the app without logcat.
package com.example.myassignment
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.example.myassignment.Fragments.DestinationsFragment
import com.example.myassignment.Fragments.HelpFragment
import com.example.myassignment.Fragments.HomeFragment
import com.example.myassignment.Fragments.SettingsFragment
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fragment_settings.*
class MainActivity : AppCompatActivity() {
private val helpFragment = HelpFragment()
private val settingsFragment = SettingsFragment()
private val homeFragment = HomeFragment()
private val destinationsFragment = DestinationsFragment()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
replaceFragment(homeFragment)
bottom_navigation.setOnNavigationItemSelectedListener{
when(it.itemId){
R.id.ic_home -> replaceFragment(homeFragment)
R.id.ic_destinations -> replaceFragment((destinationsFragment))
R.id.ic_help -> replaceFragment(helpFragment)
R.id.ic_settings -> replaceFragment(settingsFragment)
}
true
}
// This is the onclick for the button which is inside a fragment (SettingsFragment)
btnReset.setOnClickListener { resetColour() }
}
// Function for the onclick function
private fun resetColour() {
btnReset.setBackgroundColor(Color.parseColor("#3E3E3E"))
}
private fun replaceFragment(fragment: Fragment){
if (fragment !=null){
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fragment_container, fragment)
transaction.commit()
}
}
}
And here's my SettingsFragment code (I haven't changed anything)
package com.example.myassignment.Fragments
import android.graphics.Color
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.myassignment.R
import kotlinx.android.synthetic.main.fragment_settings.*
// 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 [SettingsFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class SettingsFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_settings, 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 SettingsFragment.
*/
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(param1: String, param2: String) =
SettingsFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
Here's the XML for the fragment, the button I'm trying to change is btnReset
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".Fragments.SettingsFragment"
android:background="#color/black">
<TextView
android:id="#+id/txtSettings"
android:layout_width="323dp"
android:layout_height="102dp"
android:layout_marginTop="16dp"
android:background="#color/orange"
android:gravity="center"
android:text="Settings"
android:textAlignment="center"
android:textColor="#color/black"
android:textSize="60sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/txtNotifications"
android:layout_width="223dp"
android:layout_height="48dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="12dp"
android:layout_marginRight="12dp"
android:background="#color/grey"
android:gravity="center"
android:text="Notifications"
android:textAlignment="center"
android:textColor="#color/black"
android:textSize="20sp"
app:layout_constraintEnd_toStartOf="#+id/btnNotifications"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txtSettings" />
<TextView
android:id="#+id/txtNightMode"
android:layout_width="223dp"
android:layout_height="48dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="12dp"
android:layout_marginRight="12dp"
android:background="#color/grey"
android:gravity="center"
android:text="Night Mode"
android:textAlignment="center"
android:textColor="#color/black"
android:textSize="20sp"
app:layout_constraintEnd_toStartOf="#+id/btnNightMode"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txtNotifications" />
<TextView
android:id="#+id/txtWIFI"
android:layout_width="223dp"
android:layout_height="48dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="12dp"
android:layout_marginRight="12dp"
android:background="#color/grey"
android:gravity="center"
android:text="WI-FI Only"
android:textAlignment="center"
android:textColor="#color/black"
android:textSize="20sp"
app:layout_constraintEnd_toStartOf="#+id/btnWIFI"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txtNightMode" />
<ToggleButton
android:id="#+id/btnNotifications"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="44dp"
android:layout_marginRight="44dp"
android:text="ToggleButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txtSettings"
android:background="#color/cyan"
/>
<ToggleButton
android:id="#+id/btnNightMode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="44dp"
android:layout_marginRight="44dp"
android:checked="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btnNotifications"
android:background="#color/cyan"
/>
<ToggleButton
android:id="#+id/btnWIFI"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="44dp"
android:layout_marginRight="44dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btnNightMode"
android:background="#color/cyan"/>
<Button
android:id="#+id/btnReset"
android:layout_width="337dp"
android:layout_height="154dp"
android:layout_marginTop="24dp"
android:text="Reset"
android:background="#color/cyan"
android:backgroundTint="#color/orange"
android:textColor="#color/black"
android:textSize="50sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txtWIFI" />
</androidx.constraintlayout.widget.ConstraintLayout>
----- Edit -----
New SettingsFragment code:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
btnReset.setOnClickListener { resetColour() }
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_settings, container, false)
}
private fun resetColour() {
btnReset.setBackgroundColor(Color.parseColor("3E3E3E"))
}
Here's the logcat
2021-02-17 08:20:32.594 11717-11717/com.example.myassignment E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myassignment, PID: 11717
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.myassignment.Fragments.SettingsFragment.onCreateView(SettingsFragment.kt:40)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2600)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
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)
This line is your problem.
btnReset.setOnClickListener { resetColour() }
btnReset lives in your fragment, but you are trying to reference it from your activity. Try moving that code to the fragment which inflates the view that btnReset lives in.
See the line import kotlinx.android.synthetic.main.fragment_settings.* in your activity class? This is what made it seem like btnReset was a valid property to reference in your activity. You should delete that line.
Lastly, it's very unlikely that this 'crashed without logcat'. You probably have some sort of filter on your logcat that's preventing you from seeing the crash.
I am using Retrofit2 to make a GET to github api but response.body() returns empty. I actually check the endpoints on Postman and it returns a body. I don't know what I am doing wrong that is causing this. I have included in the posts below my interface, viewmodel and my layout.
API interface
const val BASE_URL = "https://api.github.com/"
private val retrofit =
Retrofit.Builder().addConverterFactory(ScalarsConverterFactory.create()).baseUrl(
BASE_URL
).build()
object GithubUserApi {
val retrofitService: GithubApiService by lazy {
retrofit.create(GithubApiService::class.java)
}
}
interface GithubApiService {
#GET("search/users?sort=repositories&order=desc")
fun searchUsers(
#Query("q") query: String,
#Query("page") page: Int,
#Query("per_page") itemsPerPage: Int
): Call<String>
}
ViewModel
class OverviewViewModel : ViewModel() {
private val _response = MutableLiveData<String>()
val response: LiveData<String>
get() = _response
init {
getGithubUsers()
}
private fun getGithubUsers() {
GithubUserApi.retrofitService.searchUsers("location:LOCATION", 1, 50).enqueue(
object : Callback<String> {
override fun onFailure(call: Call<String>, t: Throwable) {
_response.value = "Failure: " + t.message
}
override fun onResponse(call: Call<String>, response: Response<String>) {
_response.value = response.body()
}
}
)
}
}
layout
<?xml version="1.0" encoding="utf-8"?>
<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">
<data>
<variable
name="overviewViewModel"
type="com.example.OverviewViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.overview.OverviewFragment">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{overviewViewModel.response}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Allow Data Binding to Observe LiveData with the lifecycle of the fragment/activity.
binding.lifecycleOwner = this
That is what solved the problem for me... What an oversight!