android crash error: java.lang.IllegalStateException - android-studio

I have a home dash board activity containing navigation view. when the app starts it behaves normally. but when i try to click on navigation menu and open notes my app crashes showing this error message.
java.lang.IllegalStateException: Fragment NoteFragment not attached to a context
Below is my code regarding this. the exception occurs when trying to add LinearLayoutManager to recycler view in noteFragment
/**
* Fundoo Notes
* #description HomeDashBoardActivity displays all user actions.
* #file HomeDashBoardActivity.kt
* #author ksoundarya4
* #version 1.0
* #since 07/02/2020
*/
package com.bridgelabz.fundoonotes.note_module.dashboard_page.view
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.bridgelabz.fundoonotes.R
import com.bridgelabz.fundoonotes.label_module.view.LabelFragment
import com.bridgelabz.fundoonotes.note_module.dashboard_page.model.Note
import com.bridgelabz.fundoonotes.note_module.dashboard_page.viewmodel.DashBoardViewModel
import com.bridgelabz.fundoonotes.note_module.dashboard_page.viewmodel.DashBoardViewModelFactory
import com.bridgelabz.fundoonotes.note_module.note_page.view.AddNoteFragment
import com.bridgelabz.fundoonotes.repository.local_service.DatabaseHelper
import com.bridgelabz.fundoonotes.user_module.login.view.LoginActivity
import com.bridgelabz.fundoonotes.user_module.login.view.toast
import com.bridgelabz.fundoonotes.user_module.registration.model.User
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.navigation.NavigationView
class HomeDashBoardActivity : AppCompatActivity() {
private val dashBoadViewModelFactory: DashBoardViewModelFactory by lazy {
DashBoardViewModelFactory(DatabaseHelper(this))
}
private val dashBoardViewModel: DashBoardViewModel by lazy {
ViewModelProvider(this, dashBoadViewModelFactory).get(DashBoardViewModel::class.java)
}
private val toolbar: Toolbar by lazy {
findViewById<Toolbar>(R.id.toolbar)
}
private val drawerLayout: DrawerLayout by lazy {
findViewById<DrawerLayout>(R.id.drawer_layout)
}
private val navigationView: NavigationView by lazy {
findViewById<NavigationView>(R.id.nav_view)
}
private val floatingActionButton: FloatingActionButton by lazy {
findViewById<FloatingActionButton>(R.id.fab)
}
private val preferences: SharedPreferences by lazy {
this.getSharedPreferences(
"LaunchScreen",
Context.MODE_PRIVATE
)
}
private lateinit var authenticatedEmail: String
private var authenticatedUser: User? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home_dash_board)
setSupportActionBar(toolbar)
initHomeDashBoardActivity()
authenticateUser()
setClickOnFloatingActionButton()
setNavigationItemClicked()
}
private fun authenticateUser() {
dashBoardViewModel.authenticatedUser(authenticatedEmail)
dashBoardViewModel.getUser().observe(this, Observer {
observeUser(it)
})
}
private fun observeUser(user: User?) {
if (user != null)
authenticatedUser = user
}
private fun initHomeDashBoardActivity() {
getUserSharedPreferences()
setActionBarToggle()
setNoteFragment()
}
private fun setNoteFragment() {
navigationView.setCheckedItem(R.id.nav_home)
val fragment = NoteFragment()
replaceFragment(fragment)
}
private fun getUserSharedPreferences() {
val editor = preferences.edit()
val email = preferences.getString("email", "")
authenticatedEmail = email!!
editor.apply()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.home_dash_board, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.app_bar_user_info -> {
startUserProfileFragment()
toast(getString(R.string.tast_when_user_profile_clicked))
true
}
else -> super.onOptionsItemSelected(item)
}
}
override fun onBackPressed() {
callFragmentsOnBackPressed()
super.onBackPressed()
}
/**Function to set Floating Action Bar when it is clicked*/
private fun setClickOnFloatingActionButton() {
floatingActionButton.setOnClickListener {
val bundle = setNoteArguments()
replaceAddNoteFragment(bundle)
}
}
private fun setNoteArguments(): Bundle? {
val bundle = Bundle()
val note = Note()
if (authenticatedUser != null)
note.userId = authenticatedUser!!.id
bundle.putSerializable(getString(R.string.note), note)
return bundle
}
/**Function to set Navigation Items when they are clicked*/
private fun setNavigationItemClicked(): Boolean {
navigationView.setNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.nav_home -> {
replaceFragment(NoteFragment())
return#setNavigationItemSelectedListener true
}
R.id.nav_sing_out -> {
onSignOutMenuClick()
return#setNavigationItemSelectedListener true
}
R.id.nav_archive -> {
replaceFragment(ArchiveFragment())
return#setNavigationItemSelectedListener true
}
R.id.nav_delete -> {
replaceFragment(TrashFragment())
return#setNavigationItemSelectedListener true
}
R.id.nav_label -> {
replaceFragment(LabelFragment())
return#setNavigationItemSelectedListener true
}
R.id.nav_reminder -> {
replaceFragment(ReminderFragment())
return#setNavigationItemSelectedListener true
}
else -> return#setNavigationItemSelectedListener false
}
}
return true
}
private fun replaceFragment(fragment: Fragment?) {
drawerLayout.closeDrawer(navigationView)
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fragment_container, fragment!!)
transaction.commit()
}
/**Function to set Action Bar Toggle of Drawer Layout*/
private fun setActionBarToggle() {
val actionBarDrawerToggle = ActionBarDrawerToggle(
this,
drawerLayout,
toolbar,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close
)
drawerLayout.addDrawerListener(actionBarDrawerToggle)
actionBarDrawerToggle.syncState()
}
/**Function to set alert dialog when SignOut
* Menu item is clicked */
private fun onSignOutMenuClick() {
removePreference()
signOutAlertDialog()
}
private fun removePreference() {
if (preferences.contains("email")) {
val editor = preferences.edit()
editor.clear().apply()
}
}
/**Function that performs sign out alert operation*/
private fun signOutAlertDialog() {
val alertDialogBuilder = AlertDialog.Builder(this)
alertDialogBuilder.setMessage(getString(R.string.sign_out_alert_message))
alertDialogBuilder.setTitle(getString(R.string.sign_out_alert_title))
alertDialogBuilder.setCancelable(false)
alertDialogBuilder
.setPositiveButton(
getString(R.string.sign_out_alert_positive_button)
) { _, _ ->
navigateToLoginScreen()
toast(
getString(R.string.toast_when_sign_out_alert_positive_button_clicked)
)
}
alertDialogBuilder.setNegativeButton(getString(R.string.sign_out_alerst_negative_button))
{ dialog, _ ->
drawerLayout.closeDrawer(navigationView)
dialog.cancel()
}
val alertDialog = alertDialogBuilder.create()
alertDialog.show()
}
/**Function to tell fragment that back navigation is Pressed*/
private fun callFragmentsOnBackPressed() {
val fragments: List<Fragment> = supportFragmentManager.fragments
for (fragment in fragments) {
if (fragment is OnBackPressed) {
fragment.onBackPressed()
setNoteFragment()
}
}
}
/**Function to replace home dash board with AddNoteFragment*/
private fun replaceAddNoteFragment(bundle: Bundle?) {
val fragment = AddNoteFragment()
fragment.arguments = bundle
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fragment_container, fragment)
.addToBackStack(null)
.commit()
}
/**Function to navigate to LoginActivity*/
private fun navigateToLoginScreen() {
val intent = Intent(this, LoginActivity::class.java)
finish()
startActivity(intent)
}
private fun startUserProfileFragment(): Boolean {
val fragmentManager = supportFragmentManager
val reminderDialog = UserProfileDialogFragment()
reminderDialog.arguments = Bundle().apply {
putSerializable(getString(R.string.authenticated_user), authenticatedUser)
}
reminderDialog.show(fragmentManager, getString(R.string.dialog_reminder_title))
return true
}
}
This is my note fragment
package com.bridgelabz.fundoonotes.note_module.dashboard_page.view
import android.os.Bundle
import android.util.Log
import android.view.*
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.RecyclerView
import com.bridgelabz.fundoonotes.R
import com.bridgelabz.fundoonotes.note_module.dashboard_page.model.Note
import com.bridgelabz.fundoonotes.note_module.dashboard_page.view.recycler_view_strategy.RecyclerViewType
import com.bridgelabz.fundoonotes.note_module.dashboard_page.view.recycler_view_strategy.LinearRecyclerViewManager
import com.bridgelabz.fundoonotes.note_module.dashboard_page.view.recycler_view_strategy.RecyclerViewLayoutManager
import com.bridgelabz.fundoonotes.note_module.dashboard_page.view.recycler_view_strategy.StaggeredRecyclerViewtManager
import com.bridgelabz.fundoonotes.note_module.dashboard_page.viewmodel.NoteTableManagerFactory
import com.bridgelabz.fundoonotes.note_module.dashboard_page.viewmodel.SharedViewModel
import com.bridgelabz.fundoonotes.note_module.note_page.view.AddNoteFragment
import com.bridgelabz.fundoonotes.repository.local_service.DatabaseHelper
import com.bridgelabz.fundoonotes.repository.local_service.note_module.NoteTableManagerImpl
class NoteFragment : Fragment(), OnNoteClickListener {
private val noteFactory by lazy {
NoteTableManagerFactory(NoteTableManagerImpl(DatabaseHelper(requireContext())))
}
private val sharedViewModel: SharedViewModel by lazy {
requireActivity().run {
ViewModelProvider(
this,
noteFactory
).get(SharedViewModel::class.java)
}
}
private val recyclerView: RecyclerView by lazy {
requireView().findViewById<RecyclerView>(R.id.notes_recycler_view)
}
private lateinit var noteAdapter: NoteViewAdapter
private lateinit var notes: ArrayList<Note>
private var recyclerViewType = RecyclerViewType.ListView
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
setHasOptionsMenu(true)
return inflater.inflate(R.layout.fragment_note, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
sharedViewModel.getRecyclerViewType()
.observe(requireActivity(), Observer { recyclerViewType = it })
sharedViewModel.getSimpleNoteLiveData()
.observe(requireActivity(), Observer { observeNotes(it) })
}
private fun initRecyclerView() {
recyclerView.setHasFixedSize(true)
recyclerView.layoutManager = setRecyclerViewType(recyclerViewType)
recyclerView.adapter = noteAdapter
}
private fun observeNotes(noteList: ArrayList<Note>) {
Log.d("noteList", noteList.toString())
notes = noteList
noteAdapter = NoteViewAdapter(notes, this)
noteAdapter.notifyDataSetChanged()
initRecyclerView()
}
override fun onClick(adapterPosition: Int) {
val note = notes[adapterPosition]
val bundle = Bundle()
bundle.putSerializable(getString(R.string.note), note)
replaceWithAddNoteFragment(bundle)
}
override fun onLongClick(adapterPosition: Int) {
val note = notes[adapterPosition]
Toast.makeText(requireActivity(), "$note", Toast.LENGTH_SHORT).show()
}
private fun replaceWithAddNoteFragment(bundle: Bundle) {
val addNoteFragment = AddNoteFragment()
addNoteFragment.arguments = bundle
requireActivity().supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, addNoteFragment).addToBackStack(null).commit()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
(requireActivity() as AppCompatActivity).supportActionBar!!.title =
getString(R.string.menu_notes)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.app_bar_recycler_view -> {
switchRecyclerViewType()
switchIcon(item)
true
}
R.id.app_bar_search_note -> {
val searchView = item.actionView as SearchView
searchView.setOnQueryTextListener(searchQueryListener)
true
}
else -> false
}
}
private val searchQueryListener = object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
noteAdapter.filter.filter(newText)
return false
}
}
private fun switchIcon(item: MenuItem) {
if (recyclerViewType == RecyclerViewType.ListView)
item.setIcon(R.drawable.ic_grid_view_white)
else {
item.setIcon(R.drawable.ic_list_view_white)
}
}
private fun switchRecyclerViewType() {
when (recyclerViewType) {
RecyclerViewType.GridView -> {
sharedViewModel.setRecyclerViewType(RecyclerViewType.ListView)
recyclerView.layoutManager = setRecyclerViewType(recyclerViewType)
}
RecyclerViewType.ListView -> {
sharedViewModel.setRecyclerViewType(RecyclerViewType.GridView)
recyclerView.layoutManager = setRecyclerViewType(recyclerViewType)
}
}
}
private fun setRecyclerViewType(viewType: RecyclerViewType): RecyclerView.LayoutManager {
val layoutManager = RecyclerViewLayoutManager()
layoutManager.addRecyclerView(recyclerView)
return when (viewType) {
RecyclerViewType.ListView -> {
layoutManager.setRecyclerView(LinearRecyclerViewManager(requireContext()))
}
RecyclerViewType.GridView -> {
layoutManager.setRecyclerView(
StaggeredRecyclerViewtManager(
numberOfRows = 2,
orientation = 1
)
)
}
}
}
}

There's likely that you are pressing twice the button or somehow the navigate call triggers twice.

Related

Kotlin E/RecyclerView: No adapter attached; skipping layout (Adapter doesnt work)

I am using RecyclerView in my app. But I'm getting this error in the Logcat. Here is my Codes;
My Fragment
package com.ahmetkaan.kediy.Fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
import androidx.navigation.Navigation
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.ahmetkaan.kediy.R
import com.ahmetkaan.kediy.adapter.NotesAdapter
import com.ahmetkaan.kediy.database.NotesDatabase
import com.ahmetkaan.kediy.databinding.FragmentHomeBinding
import com.ahmetkaan.kediy.entities.Notlar
import kotlinx.coroutines.launch
import java.util.*
import kotlin.collections.ArrayList
class Home : BaseFragment() {
lateinit var binding : FragmentHomeBinding
var arrNotes = ArrayList<Notlar>()
var notesAdapter: NotesAdapter = NotesAdapter()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.layoutManager = StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL)
launch {
context?.let {
val notes = NotesDatabase.getDatabase(it).noteDao().getAllNotes()
notesAdapter.setData(notes)
arrNotes = notes as ArrayList<Notlar>
binding.recyclerView.adapter = notesAdapter
}
}
binding.searchView.setOnQueryTextListener( object : SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(p0: String?): Boolean {
return true
}
override fun onQueryTextChange(p0: String?): Boolean {
var tempArr = ArrayList<Notlar>()
for (arr in arrNotes){
if (arr.not!!.toLowerCase(Locale.getDefault()).contains(p0.toString())){
tempArr.add(arr)
}
}
notesAdapter.setData(tempArr)
notesAdapter.notifyDataSetChanged()
return true
}
})
notesAdapter.setOnClickListener(onClicked)
binding.notEkle.setOnClickListener {
val action = HomeDirections.actionHome2ToNotOlustur()
Navigation.findNavController(requireActivity(), R.id.fragmentContainerView).navigate(action)
}
binding.calendar.setOnClickListener {
val action = HomeDirections.actionHome2ToCalendar2()
Navigation.findNavController(requireActivity(), R.id.fragmentContainerView).navigate(action)
}
}
private val onClicked = object :NotesAdapter.OnItemClickListener {
override fun onClicked(notesId: Int) {
val fragment: Fragment
val bundle = Bundle()
bundle.putInt("noteId", notesId)
fragment = NotOlustur.newInstance()
fragment.arguments = bundle
val action = HomeDirections.actionHome2ToNotOlustur()
Navigation.findNavController(requireActivity(), R.id.fragmentContainerView)
.navigate(action)
}
}
}
My Adapter
package com.ahmetkaan.kediy.adapter
import android.graphics.BitmapFactory
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.cardview.widget.CardView
import androidx.core.graphics.drawable.toDrawable
import androidx.recyclerview.widget.RecyclerView
import com.ahmetkaan.kediy.R
import com.ahmetkaan.kediy.entities.Notlar
import kotlin.collections.ArrayList
class NotesAdapter() :
RecyclerView.Adapter<NotesAdapter.NotesViewHolder>() {
var listener:OnItemClickListener? = null
var arrList = ArrayList<Notlar>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotesViewHolder {
return NotesViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.item_notlar,parent,false)
)
}
override fun getItemCount(): Int {
return arrList.size
}
fun setData(arrNotesList: List<Notlar>){
arrList = arrNotesList as ArrayList<Notlar>
}
fun setOnClickListener(listener1: OnItemClickListener){
listener = listener1
}
override fun onBindViewHolder(holder: NotesViewHolder, position: Int) {
holder.itemView.findViewById<TextView>(R.id.theNotC).text = arrList[position].not
holder.itemView.findViewById<TextView>(R.id.dateTimeC).text = arrList[position].dateTime
if (arrList[position].impPathBackground != null){
holder.itemView.findViewById<ImageView>(R.id.backgroundC).setImageBitmap(BitmapFactory.decodeFile(arrList[position].impPathBackground))
} else {
holder.itemView.findViewById<ImageView>(R.id.backgroundC).setImageDrawable(R.drawable.ronin.toDrawable())
}
if (arrList[position].impPathBackground != null){
holder.itemView.findViewById<ImageView>(R.id.backgroundC).setImageBitmap(BitmapFactory.decodeFile(arrList[position].impPathLogo))
} else {
holder.itemView.findViewById<ImageView>(R.id.backgroundC).setImageDrawable(R.drawable.logo1.toDrawable())
}
holder.itemView.findViewById<CardView>(R.id.cardView).setOnClickListener {
listener!!.onClicked(arrList[position].id!!)
}
}
class NotesViewHolder(view:View) : RecyclerView.ViewHolder(view){
}
interface OnItemClickListener{
fun onClicked(noteId:Int)
}
}
I searched a lot on the internet but I didn't understand much because they are all in java language. It didn't work even though I tried what I understood. Unlike others, I used CoroutineScope(launch) I think it was because of it, but I'm not sure. What should i do?
Setting the adapter should be in the main thread. But you wrapped it in launch.
binding.recyclerView.adapter = notesAdapter

E/RecyclerView: No adapter attached; skipping layout(Kotlin)

I have a trouble with a error "E/RecyclerView: No adapter attached; skipping layout" for 2 days...
Please help me what causes this error...
I already checked that getItemCount function return 1 result(Because the ProductEntity database only have 1 data)
Thank you in advance!!
[ProductActivity.kt]
package com.example.trymakeapp
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.trymakeapp.databinding.ActivityProductBinding
import com.example.trymakeapp.databinding.ItemProductBinding
import com.example.trymakeapp.db.AppDatabase
import com.example.trymakeapp.db.ProductDao
import com.example.trymakeapp.db.ProductEntity
class ProductActivity : AppCompatActivity() {
private lateinit var binding: ActivityProductBinding
private lateinit var db: AppDatabase
private lateinit var productDao: ProductDao
private lateinit var productList : ArrayList<ProductEntity>
private lateinit var adapter : ProductRecyclerViewAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityProductBinding.inflate(layoutInflater)
setContentView(binding.root)
db = AppDatabase.getInstance(this)!!
productDao = db.getProductDao()
getAllProductList()
}
private fun getAllProductList() {
Thread {
productList = ArrayList(productDao.getAll())
setRecyclerView()
}.start()
println("#####")
}
private fun setRecyclerView() {
runOnUiThread {
adapter = ProductRecyclerViewAdapter(productList)
binding.recyclerView.adapter = adapter
binding.recyclerView.layoutManager = LinearLayoutManager(this#ProductActivity)
}
}
}
[ProductRecyclerViewAdapter.kt]
package com.example.trymakeapp
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.trymakeapp.databinding.ItemProductBinding
import com.example.trymakeapp.db.ProductEntity
import java.util.ArrayList
class ProductRecyclerViewAdapter(private val productList : ArrayList<ProductEntity>)
: RecyclerView.Adapter<ProductRecyclerViewAdapter.MyViewHolder>() {
inner class MyViewHolder(binding: ItemProductBinding) :
RecyclerView.ViewHolder(binding.root) {
val product_idx = binding.productIdx
val product_name = binding.productName
val product_price = binding.productPrice
val product_img = binding.productImg
val root = binding.root
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val binding : ItemProductBinding =
ItemProductBinding.inflate(LayoutInflater.from(parent.context),
parent, false)
return MyViewHolder(binding)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val productData = productList[position]
holder.product_idx.text = productData.idx
holder.product_name.text = productData.name
holder.product_price.text = productData.price.toString()
}
override fun getItemCount(): Int {
return productList.size
}
}
[MainActivity.kt]
...
...
btn3.setOnClickListener {
val intent = Intent(this, ProductActivity::class.java)
startActivity(intent)
}
Try to move the initialization in the onCreate method:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityProductBinding.inflate(layoutInflater)
setContentView(binding.root)
db = AppDatabase.getInstance(this)!!
productDao = db.getProductDao()
binding.recyclerView.layoutManager = LinearLayoutManager(this)
adapter = ProductRecyclerViewAdapter(arrayListOf())
binding.recyclerView.adapter = adapter
getAllProductList()
}
And edit your setRecyclerView method like this (You can remove the adapter and productList global variables):
private fun setRecyclerView(productList: ArrayList<ProductEntity>) {
runOnUiThread {
binding.recyclerView.adapter = ProductRecyclerViewAdapter(productList)
}
}
EDIT
To handle the fact that data are not displayed. Try to use LiveData to observe its changes:
#Dao
interface ProductDao {
#Query("select * from ProductEntity")
fun getAll() : LiveData<List<ProductEntity>>
}
Then observe changes in the getAll method using observe:
private fun getAllProductList() {
productDao.getAll().observe(this) {
setRecyclerView(ArrayList(it))
}
}

How to detect a swipe without detecting a tap in kotlin

I have been programming an app in kotlin. This app allows a user to swipe through an imageView and plays a sound when a user taps the screen. The onSwipeTouchListener class below is the onTouchListener for my imageView. I am using the onSwipeTouchListener to also listen for taps so that the app can play a sound when the user taps the screen. The issue is when a user swipes, the program detects a tap as well as a swipe. This results in the app playing a sound when it is not supposed to.
If someone could help me with this bug I'd much appreciate it.
here is my code:
package com.example.articulate_r
import android.animation.Animator
import android.content.Context
import android.media.MediaPlayer
import android.net.Uri
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.widget.ImageView
import android.widget.TextView
open class OnSwipeTouchListener(
private val ctx: Context,
private val imageView: ImageView,
private val textView: TextView,
private val firstAnimatorRight: Animator,
private val secondAnimatorRight: Animator,
private val firstAnimatorLeft: Animator,
private val secondAnimatorLeft: Animator
) : View.OnTouchListener {
private val gestureDetector: GestureDetector
companion object {
private val SWIPE_THRESHOLD = 100
private val SWIPE_VELOCITY_THRESHOLD = 100
}
init {
gestureDetector = GestureDetector(ctx, GestureListener())
}
override fun onTouch(v: View, event: MotionEvent): Boolean {
return gestureDetector.onTouchEvent(event)
}
private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
lateinit private var audioPlayer1 : MediaPlayer
override fun onDown(e: MotionEvent): Boolean {
playAudio(audioFiles[counter])
return true
}
override fun onFling(
e1: MotionEvent,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
var result = false
try {
val diffX = e2.x - e1.x
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight()
} else {
onSwipeLeft()
}
result = true
}
} catch (exception: Exception) {
exception.printStackTrace()
}
return result
}
}
var images = arrayOf(R.drawable.minecow, R.drawable.minepig,R.drawable.minechick)
var imageNames = arrayOf("Cows", "Pigs", "Chickens")
var audioFiles = arrayOf(R.raw.cows_and, R.raw.pigs_and, R.raw.chickens_and)
var counter = 0
open fun onSwipeRight() {
println("swiped right")
if (counter == 0) {
counter = images.size - 1
}
else {
counter--
}
animateRight(images[counter])
textView.text = imageNames[counter]
println(counter)
}
open fun onSwipeLeft() {
println("swiped left")
if (counter == images.size - 1) {
counter = 0
}
else {
counter++
}
animateLeft(images[counter])
textView.text = imageNames[counter]
println(counter)
}
private fun playAudio(audioFile: Int) {
var audioPlayer = MediaPlayer.create(ctx, audioFile)
audioPlayer.setVolume(100f,100f)
audioPlayer.start()
}
private fun animateLeft(drawableImage: Int) {
firstAnimatorLeft.setTarget(imageView)
secondAnimatorLeft.setTarget(imageView)
firstAnimatorLeft.setDuration(250)
secondAnimatorLeft.setDuration(250)
firstAnimatorLeft.start()
firstAnimatorLeft.addListener(
object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) {
}
override fun onAnimationEnd(animation: Animator) {
imageView.setImageDrawable(ctx.getDrawable(drawableImage))
secondAnimatorLeft.start()
}
override fun onAnimationCancel(animation: Animator) {}
override fun onAnimationRepeat(p0: Animator?) {}
}
)
}
private fun animateRight(drawableImage: Int) {
firstAnimatorRight.setTarget(imageView)
secondAnimatorRight.setTarget(imageView)
firstAnimatorRight.setDuration(250)
secondAnimatorRight.setDuration(250)
firstAnimatorRight.start()
firstAnimatorRight.addListener(
object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) {
}
override fun onAnimationEnd(animation: Animator) {
imageView.setImageDrawable(ctx.getDrawable(drawableImage))
secondAnimatorRight.start()
}
override fun onAnimationCancel(animation: Animator) {}
override fun onAnimationRepeat(p0: Animator?) {}
}
)
}
}

Getting Unresolved Reference from Singleton Class

I am working with android studio and in Kotlin. I am working with a Singleton class so my confusion is that my getInstance function is not being called when I am trying to add that into my setupRecyclerView function and it keeps saying it is an unresolved reference. I also have the issue that my NewsListActivity.SimpleItemRecyclerViewAdapter also keeps getting an unresolved reference when I try to reference it. Any help would be greatly appreciated.
package edu.uw.amjadz.material_news
import android.content.Context
import android.graphics.Bitmap
import android.util.LruCache
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.toolbox.ImageLoader
import com.android.volley.toolbox.Volley
class Singleton private constructor(context: Context){
private var INSTANCE: edu.uw.amjadz.material_news.Singleton? = null
fun getInstance(context: Context): edu.uw.amjadz.material_news.Singleton {
if(INSTANCE == null){
INSTANCE = Singleton(context)
}
return INSTANCE as edu.uw.amjadz.material_news.Singleton
}
val requestQueue: RequestQueue by lazy {
Volley.newRequestQueue(context.applicationContext)
}
val imageLoader: ImageLoader by lazy {
ImageLoader(requestQueue,
object : ImageLoader.ImageCache{
private val cache = LruCache<String, Bitmap>(20)
override fun getBitmap(url: String?): Bitmap {
return cache.get(url)
}
override fun putBitmap(url: String?, bitmap: Bitmap?) {
cache.put(url, bitmap)
}
}
)
}
fun <T> add(req: Request<T>){
requestQueue.add(req)
}
}
private fun setupRecyclerView(recyclerView: RecyclerView) {
recyclerView.setAdapter(null)
val key = getString(R.string.NEWS_API_KEY)
val url = "https://newsapi.org/v2/everything?q=bitcoin&from=2018-10-01&sortBy=publishedAt&apiKey=$key"
val jsonObjectRequest = JsonObjectRequest(
Request.Method.GET, url, null,
Response.Listener { response ->
recyclerView.adapter = NewsListActivity.SimpleItemRecyclerViewAdapter(this, DummyContent.parseData(response.toString()), twoPane)
},
Response.ErrorListener { error ->
}
)
Singleton.getInstance(this).add(jsonObjectRequest)
if (twoPane){
recyclerView.layoutManager = LinearLayoutManager(this)
} else {
recyclerView.layoutManager = GridLayoutManager(this, 2)
}
}
}
class SimpleItemRecyclerViewAdapter(
private val parentActivity: NewsListActivity,
private val values: List<DummyContent.DummyItem>,
private val twoPane: Boolean
) :
RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder>() {
private val onClickListener: View.OnClickListener
init {
onClickListener = View.OnClickListener { v ->
val item = v.tag as DummyContent.DummyItem
if (twoPane) {
val fragment = NewsDetailFragment().apply {
arguments = Bundle().apply {
putString(NewsDetailFragment.ARG_ITEM_ID, item.id)
}
}
parentActivity.supportFragmentManager
.beginTransaction()
.replace(R.id.news_detail_container, fragment)
.commit()
} else {
val intent = Intent(v.context, NewsDetailActivity::class.java).apply {
putExtra(NewsDetailFragment.ARG_ITEM_ID, item.id)
}
v.context.startActivity(intent)
}
}
}

Studio shows an error when I try to startActivity() from Recycler View Adapter

Building my first app and hitting an error I can't figure out. I have a recycler view that shows a list of cards. I want to click the card and open another activity.
Here is my code:
import android.content.Context
import android.content.Intent
import android.support.v4.content.ContextCompat.startActivity
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import kotlinx.android.synthetic.main.list_tank_item.view.*
class TankAdapter(val context: Context, val tanks: List<Tank>) : RecyclerView.Adapter<TankAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, p1: Int): ViewHolder {
val view = LayoutInflater.from(context).inflate(R.layout.list_tank_item, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return tanks.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val tank = tanks[position]
holder.setData(tank, position)
}
inner class ViewHolder(itemview: View) : RecyclerView.ViewHolder(itemview) {
var currentTank: Tank? = null
var currentPosition: Int = 0
init {
itemView.setOnClickListener{
val intent = Intent(context, TankOverviewActivity::class.java)
var tank_id = currentTank._id.toString()
intent.putExtra("tank_id", tank_id)
startActivity(intent)
}
itemView.imgEdit.setOnClickListener{
Toast.makeText(context, currentTank!!.tank_name + " Edit button clicked!", Toast.LENGTH_LONG).show()
}
}
fun setData(tank: Tank?, position: Int) {
itemView.txvTankName.text = tank!!.tank_name
itemView.txvTankCapacity.text = tank!!.tank_capacity
itemView.txvTankType.text = tank!!.tank_type
this.currentTank = tank
this.currentPosition = position
}
}
}
And here a screen of of android studio:
Android Studio problem
What am I doing wrong?
Try as follow
import ...
//use your context as member of your class put private as modifier
class TankAdapter(private val context: Context, val tanks: List<Tank>) : RecyclerView.Adapter<TankAdapter.ViewHolder>() {
...
inner class ViewHolder(itemview: View) : RecyclerView.ViewHolder(itemview) {
...
init {
itemView.setOnClickListener {
...
//call startActivity from context
context.startActivity(intent)
}
...
}
...
}
}

Resources