lateinit property remindersViewModel has not been initialized - kotlin

I am displaying two fragments in the activity with recyclerViews. I am trying to add a new item to the recycler view but I am getting : "lateinit property remindersViewModel has not been initialized" error. I am already trying to initialise it in the fragments.
My Fragment 1:
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.bubblereminder.room.Reminders
import com.example.bubblereminder.room.RemindersListAdapter
import com.example.bubblereminder.room.RemindersViewModel
class ScheduledFragment : Fragment() {
private lateinit var reminderViewModel: RemindersViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val v = inflater.inflate(R.layout.fragment_scheduled, container, false)
return v
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val recyclerView = view?.findViewById<RecyclerView>(R.id.recycler_scheduled)
val adapter = context?.let { RemindersListAdapter(it) }
if (recyclerView != null) {
recyclerView.adapter = adapter
}
if (recyclerView != null) {
recyclerView.layoutManager = LinearLayoutManager(context)
}
this.reminderViewModel = ViewModelProvider(this).get(RemindersViewModel::class.java)
reminderViewModel.allReminders.observe(viewLifecycleOwner, Observer { reminders ->
// Update the cached copy of the words in the adapter.
reminders?.let {
if (adapter != null) {
adapter.setReminders(it)
}
}
})
}
}
My Fragment 2:
package com.example.bubblereminder
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.bubblereminder.room.Reminders
import com.example.bubblereminder.room.RemindersListAdapter
import com.example.bubblereminder.room.RemindersViewModel
class DoneFragment : Fragment() {
private lateinit var reminderViewModel: RemindersViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val v = inflater.inflate(R.layout.fragment_scheduled, container, false)
return v
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val recyclerView = view?.findViewById<RecyclerView>(R.id.recycler_scheduled)
val adapter = context?.let { RemindersListAdapter(it) }
if (recyclerView != null) {
recyclerView.adapter = adapter
}
if (recyclerView != null) {
recyclerView.layoutManager = LinearLayoutManager(context)
}
this.reminderViewModel = ViewModelProvider(this).get(RemindersViewModel::class.java)
reminderViewModel.allReminders.observe(viewLifecycleOwner, Observer { reminders ->
// Update the cached copy of the words in the adapter.
reminders?.let {
if (adapter != null) {
adapter.setReminders(it)
}
}
})
}
}
My Activity:
package com.example.bubblereminder
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.FrameLayout
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.bubblereminder.room.Reminders
import com.example.bubblereminder.room.RemindersDao
import com.example.bubblereminder.room.RemindersListAdapter
import com.example.bubblereminder.room.RemindersViewModel
import com.ramotion.circlemenu.CircleMenuView
class MainActivity : AppCompatActivity() {
private lateinit var remindersViewModel: RemindersViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupMenuEventListener()
setupFragments(R.id.fragment_container1, ScheduledFragment())
setupFragments(R.id.fragment_container2, DoneFragment())
}
private fun setupMenuEventListener() {
val circleMenu = findViewById<CircleMenuView>(R.id.circle_menu)
circleMenu.eventListener = object : CircleMenuView.EventListener() {
override fun onButtonClickAnimationEnd(view: CircleMenuView, index: Int) {
when (index) {
0 -> {
remindersViewModel.insert(Reminders(0,"Sample Reminder Text"))
val confirmToast = "Task 1 Finished"
Toast.makeText(this#MainActivity, confirmToast, Toast.LENGTH_SHORT)
.show()
}
1 -> {
val confirmToast = "Task 2 Finished"
Toast.makeText(this#MainActivity, confirmToast, Toast.LENGTH_SHORT)
.show()
}
2 -> {
val confirmToast = "Task 3 Finished"
Toast.makeText(this#MainActivity, confirmToast, Toast.LENGTH_SHORT)
.show()
}
3 -> {
val confirmToast = "Task 4 Finished"
Toast.makeText(this#MainActivity, confirmToast, Toast.LENGTH_SHORT)
.show()
}
4 -> {
val confirmToast = "Task 5 Finished"
Toast.makeText(this#MainActivity, confirmToast, Toast.LENGTH_SHORT)
.show()
}
}
}
}
}
private fun setupFragments(id:Int , frag:Fragment){
var fragmentManager = supportFragmentManager
fragmentManager.beginTransaction()
.replace(id, frag)
.commit()
}
}
I tried to initialise the view model in the activity but I was not able to.

Each remindersViewModel variable you have is completely separate, and by marking them as lateinit you're promising to set a value on them before you try to read them. You're doing that in the fragments, but you're not initialising the one in MainActivity before you call insert on it

Thanks, worked when I initialised it in OnCreate of the MainActivity :
this.remindersViewModel = ViewModelProvider(this).get(RemindersViewModel::class.java)

Related

adding onclicklistener to recycler view with viewbinding, kotlin

Trying to add an onclicklistener to the items in my recycler view, that will use an intent to open another activity. I've tried finding examples, but I can only find examples using Java or Kotlin examples that aren't using viewbinding.
package com.truuce.anotherrvtest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.GridLayoutManager
import com.truuce.anotherrvtest.databinding.ActivityHeroBinding
class HeroActivity : AppCompatActivity() {
var binding: ActivityHeroBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHeroBinding.inflate(layoutInflater)
setContentView(binding?.root)
val adapter = CardAdapter(HeroList.heroList)
binding?.heroRV?.adapter = adapter
binding?.heroRV?.layoutManager = GridLayoutManager(applicationContext, 3)
}
override fun onDestroy() {
super.onDestroy()
binding = null
}
}
package com.truuce.anotherrvtest
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.truuce.anotherrvtest.databinding.HeroCardBinding
class CardAdapter(val heroList: List<Hero>) : RecyclerView.Adapter<CardAdapter.MainViewHolder>() {
inner class MainViewHolder(val heroBinding: HeroCardBinding) :
RecyclerView.ViewHolder(heroBinding.root) {
fun bindHero(hero: Hero){
heroBinding.heroNameTV.text = hero.heroName
heroBinding.heroIV.setImageResource(hero.image)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainViewHolder {
return MainViewHolder(HeroCardBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: MainViewHolder, position: Int) {
val hero = heroList[position]
holder.bindHero(hero)
}
override fun getItemCount() = heroList.size
}
tried adding View.OnClickListener to MainViewHolder, then implemented a member. OnClick(p0: View){}, but no idea how to get it working.
You should add a functional property for a click listener in your adapter.
The Activity can set the item click listener behavior.
class CardAdapter(
val heroList: List<Hero>,
val itemClickListener: (Hero)->Unit
) : RecyclerView.Adapter<CardAdapter.MainViewHolder>() {
inner class MainViewHolder(val heroBinding: HeroCardBinding) :
RecyclerView.ViewHolder(heroBinding.root) {
fun bindHero(hero: Hero) = with(heroBinding) {
heroNameTV.text = hero.heroName
heroIV.setImageResource(hero.image)
root.setOnClickListener { itemClickListener(hero) }
}
}
//...
}
// In Activity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHeroBinding.inflate(layoutInflater)
setContentView(binding?.root)
val adapter = CardAdapter(HeroList.heroList) { hero ->
// do something with hero item when it's clicked
}
binding?.heroRV?.adapter = adapter
binding?.heroRV?.layoutManager = GridLayoutManager(applicationContext, 3)
}

Replace baseContext in Fragment

I have a little problem with baseContext in Fragment, in a nutshell, I'm making an application with Retrofit and RecyclerView, and for practice I decided to make them in Fragment,I took this code from MainActivity and then I ran into a problem that I don't know how to replace baseContext in override fun onResponse, I just replaced it with context and it still doesn't work
import androidx.lifecycle.ViewModelProvider
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.LinearLayoutManager
import com.example.myapplicationsadas.*
import kotlinx.android.synthetic.main.fragment_main.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class MainFragment : Fragment() {
lateinit var mService: RetrofitServices
lateinit var layoutManager: LinearLayoutManager
lateinit var adapter: MyMovieAdapter
companion object {
fun newInstance() = MainFragment()
}
private lateinit var viewModel: MainViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_main, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
mService = Common.retrofitService
recyclerMovieList.setHasFixedSize(true)
//layoutManager = LinearLayoutManager(this, RecyclerView.HORIZONTAL, false)
layoutManager = LinearLayoutManager(context)
recyclerMovieList.layoutManager = layoutManager
getAllMovie()
}
private fun getAllMovie() {
mService.getMovieList().enqueue(object : Callback<MutableList<Movie>>{
override fun onResponse(
call: Call<MutableList<Movie>>,
response: Response<MutableList<Movie>>
) {
adapter = MyMovieAdapter(baseContext, response.body() as MutableList<Movie>)
adapter.notifyDataSetChanged()
recyclerMovieList.adapter = adapter
}
override fun onFailure(call: Call<MutableList<Movie>>, t: Throwable) {
TODO("Not yet implemented")
}
})
}
}

How can I use notification on Fragment?

I want to use notification on Fragment. And if I touch button, notification will appear.
I use many ways, and I find one way to use it. but it is not worked. only run like this
2022-06-08 15:30:10.765 28876-28876/com.ebookfrenzy.sample D/MyFragment: startMyService: Intent: Intent { cmp=com.ebookfrenzy.sample/.ui.MyService }
And below one is mainFragment.kt
package com.ebookfrenzy.sample.ui.main
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.ebookfrenzy.sample.databinding.FragmentMainBinding
import com.ebookfrenzy.sample.ui.MyService
class MainFragment : Fragment() {
private var _binding: FragmentMainBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
companion object {
fun newInstance() = MainFragment()
private const val TAG = "MyFragment"
}
private lateinit var viewModel: MainViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentMainBinding.inflate(inflater, container, false)
binding.button.setOnClickListener { startMyService()
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
private fun startMyService() {
Intent(context, MyService::class.java).also {
Log.d(TAG, "startMyService: Intent: $it")
// Check Android Policy
context?.startForegroundService(it)
// Less than Android Oreo
context?.startService(it)
}
}
}
MyService
package com.ebookfrenzy.sample.ui
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import androidx.annotation.Nullable
import androidx.core.app.NotificationCompat
import com.ebookfrenzy.sample.BuildConfig
import com.ebookfrenzy.sample.R
class MyService : Service() {
companion object {
private const val TAG = "MyService"
}
private val FOREGROUND_ID: Int = 290348
private val foregroundNotificationBuilder: NotificationCompat.Builder
get() = NotificationCompat.Builder(this, applicationContext.packageName).
setSmallIcon(R.mipmap.ic_launcher_round).
setContentTitle("title").
setContentText("content text").
setPriority(NotificationCompat.PRIORITY_HIGH)
override fun onCreate() {
super.onCreate()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
startForegroundService()
return START_STICKY
}
#Nullable
override fun onBind(p0: Intent?): IBinder? {
return null
}
override fun onDestroy() {
super.onDestroy()
stopForeground(true)
}
private fun createNotificationChannel() {
val channelId = applicationContext.packageName
val channelName = BuildConfig.APPLICATION_ID
val channel = NotificationChannel(
channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT
)
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.createNotificationChannel(channel)
}
private fun startForegroundService() {
val notification = foregroundNotificationBuilder.build()
// when Over android oreo, need to notification channel.
createNotificationChannel()
startForeground(FOREGROUND_ID, notification)
}
}
And other codes are not corrected after created
I want to resolve this problem. Please help me...

kotlin:error in Fragment when adding the cardstackview in a tinder like app

I am following this tutorial about how to make a Tinder like app with Kotlin and using the third library CardStackView :
https://www.simplifiedcoding.net/tinder-like-swipe-cards-android/
However ,in my case ,shows up an error as follow:
Attempt to invoke virtual method 'void com.yuyakaido.android.cardstackview.CardStackView.setLayoutManager(androidx.recyclerview.widget.RecyclerView$LayoutManager)' on a null object reference
at com.gearsrun.stackviewapplication.UI.Home.HomePageFragment.onCreateView(HomePageFragment.kt:36)
HomeUserAdapter.kt:
package com.gearsrun.stackviewapplication.HomeUserClass
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.gearsrun.stackviewapplication.R
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.user_card.view.*
class HomeUserAdapter:RecyclerView.Adapter<HomeUserAdapter.HomeUserViewHolder>() {
private var homeUserList:List<HomeUserItem>?=null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeUserViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.user_card,parent,false)
return HomeUserViewHolder(itemView)
}
override fun onBindViewHolder(holder: HomeUserViewHolder, position: Int) {
val homeUserList = generateUser()
val currentItem = homeUserList[position]
Picasso.get().load(currentItem.user_img).into(holder.user_img)
holder.user_name.text = currentItem.user_name
holder.medal_num.text = currentItem.medal_num
holder.id_num.text = currentItem.userId
holder.user_intro.text = currentItem.user_intro
holder.user_give_num.text = currentItem.user_give_num
holder.user_receive_num.text = currentItem.user_receive_num
}
private fun generateUser(): ArrayList<HomeUserItem> {
val list = ArrayList<HomeUserItem>()
list.add(
HomeUserItem(
"https://i.pinimg.com/236x/8c/64/03/8c6403cc892231f15a6845e00d7433a9.jpg",
"Maria",
"200",
"510uu",
"I am from USA ,I am an engineer ,I hope to make the world a better place",
"500",
"100")
)
)
return list
}
override fun getItemCount(): Int {
return homeUserList!!.size
}
class HomeUserViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) {
val user_img : ImageView = itemView.user_img
val user_name : TextView = itemView.user_name
val medal_num : TextView = itemView.medal_num
val id_num : TextView = itemView.id_num
val user_intro : TextView = itemView.user_intro
val user_give_num : TextView = itemView.user_give_num
val user_receive_num : TextView = itemView.user_receive_num
}
}
HomePageFragment.kt
package com.gearsrun.stackviewapplication.UI.Home
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
import androidx.recyclerview.widget.DefaultItemAnimator
import com.gearsrun.stackviewapplication.HomeUserClass.HomeUserAdapter
import com.gearsrun.stackviewapplication.HomeUserClass.HomeUserItem
import com.gearsrun.stackviewapplication.R
import com.yuyakaido.android.cardstackview.CardStackLayoutManager
import com.yuyakaido.android.cardstackview.CardStackListener
import com.yuyakaido.android.cardstackview.Direction
import com.yuyakaido.android.cardstackview.SwipeableMethod
import kotlinx.android.synthetic.main.fragment_home_page.*
class HomePageFragment : Fragment(),CardStackListener {
private lateinit var layoutManager: CardStackLayoutManager
private val adapter = HomeUserAdapter()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val v = inflater.inflate(R.layout.fragment_home_page, container, false)
// v.rv_UserHome.layoutManager = LinearLayoutManager(context,LinearLayoutManager.VERTICAL,false)
layoutManager = CardStackLayoutManager(context,this).apply {
setSwipeableMethod(SwipeableMethod.AutomaticAndManual)
setOverlayInterpolator(LinearInterpolator())
}
stack_view.layoutManager = layoutManager
stack_view.adapter = adapter
stack_view.itemAnimator.apply {
if(this is DefaultItemAnimator){
supportsChangeAnimations = false
}
}
return v
}
override fun onCardDragging(direction: Direction?, ratio: Float) {
TODO("Not yet implemented")
}
override fun onCardSwiped(direction: Direction?) {
TODO("Not yet implemented")
}
override fun onCardRewound() {
TODO("Not yet implemented")
}
override fun onCardCanceled() {
TODO("Not yet implemented")
}
override fun onCardAppeared(view: View?, position: Int) {
TODO("Not yet implemented")
}
override fun onCardDisappeared(view: View?, position: Int) {
TODO("Not yet implemented")
}
}
Could you please help me take a look my code ?
Thank you so much in advance !
Move all that layoutManager and stackView stuff from onCreate to onViewCreated because during onCreate your view is not created yet and same is assured in onViewCreated.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
layoutManager = CardStackLayoutManager(context,this).apply {
setSwipeableMethod(SwipeableMethod.AutomaticAndManual)
setOverlayInterpolator(LinearInterpolator())
}
stack_view.layoutManager = layoutManager
stack_view.adapter = adapter
stack_view.itemAnimator.apply {
if(this is DefaultItemAnimator){
supportsChangeAnimations = false
}
}
}
or you can refer here

The app Crashes when i add -notifyDataSetChanged()- the code run perfect and get the posts in the database but

this code is inside a fragment I have a recycler view and the array list all set
the code runs perfect and get the posts in the database and get the Log messages i have entered until I add this line
postAdapter!!.notifyDataSetChanged()
which is line 81 on my code I have Bolded it so you know what I talk about
am new to coding so any small help will help me
package com.example.foonection.Fragments
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.foonection.AddNewPostActivity
import com.example.foonection.Post
import com.example.foonection.PostAdapter
import com.example.foonection.R
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener
import kotlinx.android.synthetic.main.fragment_feed_seller.view.*
import java.util.ArrayList
/**
* A simple [Fragment] subclass.
*/
class FeedSellerFragment : Fragment() {
private var postAdapter: PostAdapter? = null
private var postList: MutableList<Post>? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_feed_seller, container, false)
var recyclerView: RecyclerView? = null
recyclerView = view.findViewById(R.id.timeline_view_feed)
val linearLayoutManger = LinearLayoutManager(context)
linearLayoutManger.reverseLayout = true
linearLayoutManger.stackFromEnd = true
recyclerView.layoutManager = linearLayoutManger
postList = ArrayList()
postAdapter = context?.let { PostAdapter(it,postList as ArrayList<Post>) }
recyclerView.adapter = postAdapter
retrievePosts()
view.add_post_feed_btn.setOnClickListener {
Log.d("Log","Add Post btn Clicked")
val intent = Intent(context, AddNewPostActivity::class.java)
startActivity(intent)
}
return view
}
private fun retrievePosts(){
Log.d("Log","Trying To Retrieve Posts")
val postsRef = FirebaseDatabase.getInstance().reference.child("Posts")
postsRef.addValueEventListener(object : ValueEventListener{
override fun onDataChange(p0: DataSnapshot) {
postList?.clear()
if (p0.exists())
{
Log.d("Log","p0 is existed")
for (snapshot in p0.children)
{
Log.d("Log","for loop snapshot")
val post = snapshot.getValue(Post :: class.java)
postList!!.add(post!!)
**postAdapter!!.notifyDataSetChanged()**
}
}
}
override fun onCancelled(p0: DatabaseError) {
}
})
}
}
call notifyDataSetChanged like this
postAdapter?.let{
it.notifyDataSetChanged()
}