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)
}
}
}
Related
I'm trying to show images from my Firebase Realtime Database storage. I've done this before with a previous version of my app, but the difference is how I implemented it. My adapter and arraylist class are exactly the same, but instead of using an activity I switched to using fragments.
What I essentially did was copy my old work and make the appropriate changes so I wouldn't run into errors, but unfortunately I ran into some. My images from Firebase are not showing up at all and I'm not sure what is the problem.
Adapter Class
class AbstractAdapter(private val mContext: Context, private val abstractList: ArrayList<Abstract>) : RecyclerView.Adapter<AbstractAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.abstract_image_view, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
Glide.with(mContext)
.load(abstractList[position].abstract)
.into(holder.imageView)
}
override fun getItemCount(): Int {
return abstractList.size
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var imageView: ImageView = itemView.findViewById(R.id.abstractImageView)
}
companion object {
private const val Tag = "RecyclerView"
}
}
Data class
class Abstract {
var abstract: String? = null
constructor() {}
constructor(abstract: String?) {
this.abstract = abstract
}
}
Fragment in which images will be shown
class AbstractWallpapers: Fragment(), PurchasesUpdatedListener {
private lateinit var subscribeAbstract: Button
private var billingClient: BillingClient? = null
lateinit var recyclerView: RecyclerView
lateinit var abstractlist: ArrayList<Abstract>
private var recyclerAdapterAbstract: AbstractAdapter? = null
private var myRef3: DatabaseReference? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_abstract_wallpaper, container, false)
recyclerView = requireView().findViewById(R.id.abstract_recyclerView)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView = view.findViewById(R.id.abstract_recyclerView)
val layoutManager = LinearLayoutManager(requireActivity())
recyclerView.layoutManager = layoutManager
recyclerView.setHasFixedSize(true)
myRef3 = FirebaseDatabase.getInstance().reference
abstractlist = ArrayList()
ClearAll()
GetDataFromFirebase()
subscribeAbstract = view.findViewById(R.id.abstract_subscribe_btn)
subscribeAbstract.setOnClickListener {
subscribeAbstract()
}
// Establish connection to billing client
//check subscription status from google play store cache
//to check if item is already Subscribed or subscription is not renewed and cancelled
billingClient = BillingClient.newBuilder(requireActivity()).enablePendingPurchases().setListener(this).build()
billingClient!!.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
val queryPurchase = billingClient!!.queryPurchases(BillingClient.SkuType.SUBS)
val queryPurchases = queryPurchase.purchasesList
if (queryPurchases != null && queryPurchases.size > 0) {
handlePurchases(queryPurchases)
} else {
saveSubscribeValueToPref(false)
}
}
}
override fun onBillingServiceDisconnected() {
Toast.makeText(requireActivity(), "Service Disconnected", Toast.LENGTH_SHORT).show()
}
})
//item subscribed
if (subscribeValueFromPref) {
subscribeAbstract.visibility = View.GONE
} else {
subscribeAbstract.visibility = View.VISIBLE
}
}
// Code related to Firebase
#SuppressLint("NotifyDataSetChanged")
private fun GetDataFromFirebase() {
val query: Query = myRef3!!.child("Abstract")
query.addListenerForSingleValueEvent(object : ValueEventListener {
#SuppressLint("NotifyDataSetChanged")
override fun onDataChange(snapshot: DataSnapshot) {
for (dataSnapshot: DataSnapshot in snapshot.children) {
val abstract = Abstract()
abstract.abstract = dataSnapshot.child("abstract").value.toString()
abstractlist.add(abstract)
}
recyclerAdapterAbstract = abstractlist.let { AbstractAdapter(requireActivity(), it) }
recyclerView.adapter = recyclerAdapterAbstract
recyclerAdapterAbstract!!.notifyDataSetChanged()
}
override fun onCancelled(error: DatabaseError) {}
})
if (recyclerAdapterAbstract != null) recyclerAdapterAbstract!!.notifyDataSetChanged()
}
private fun ClearAll() {
abstractlist.clear()
abstractlist = ArrayList()
}
I fixed my problem. It turns out my rules in Firebase Realtime Database rules for read were set to false instead. My code works perfect. It was only a stupid error on my part.
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?) {}
}
)
}
}
I have made an app that uses an API to make a request and then shows the results in a RecyclerView.
I was following a tutorial and in it they used a differCallback and a liveData so the lists updates and such. However whenever the user makes a second search, the recyclerView should only show the new results but the previous results don't dissapear and the new results just appear below the previous search.
I have debugged it for quite some time now but I don't seem to understand where the list is made and where sure it be updated (or in this case cleared).
I tried using .clear() for the diff (Asynclistdiffer), creating a new list in the onBindViewHolder and then clearing that list every time the "search" is called but without any luck. As im still a beginner I don't have a clue on where or what is happening, all your helo will be greatly appreciated
this is my adapter:
class RecipePreviewAdapter : RecyclerView.Adapter<RecipePreviewAdapter.RecipePreviewViewHolder>() {
inner class RecipePreviewViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
private val differCallback = object : DiffUtil.ItemCallback<Recipe>() {
override fun areItemsTheSame(oldItem: Recipe, newItem: Recipe): Boolean {
return oldItem.sourceUrl == newItem.sourceUrl
}
override fun areContentsTheSame(oldItem: Recipe, newItem: Recipe): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this, differCallback)
lateinit var recipeList: MutableList<Recipe>
var isRecipeListInitialized = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecipePreviewViewHolder {
return RecipePreviewViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.item_recipe_preview,
parent,
false
)
)
}
override fun onBindViewHolder(holder: RecipePreviewViewHolder, position: Int) {
recipeList = differ.currentList.toMutableList()
isRecipeListInitialized = true
// Log.d(TAG, recipeList.toString())
val recipe = recipeList[position]
holder.itemView.apply {
Glide.with(this).load(recipe.image).into(ivRecipeImagePreview)
tvRecipeTitlePreview.text = recipe.title
tvTimeToMakeTVPreview.text = "${recipe.readyInMinutes} minutes"
tvSummaryPreview.text = Jsoup.parse(recipe.summary).text()
setOnClickListener {
onItemClickListener?.let { it(recipe) }
}
}
}
override fun getItemCount(): Int {
return differ.currentList.size
}
And this is where I call it:
class SearchRecipeFragment : Fragment(R.layout.fragment_search_recipe) {
lateinit var viewModel: RecipeViewModel
lateinit var recipeAdapter: RecipePreviewAdapter
val TAG = "SearchRecipeFragment"
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = (activity as RecipesActivity).viewModel
setupRecyclerView()
recipeAdapter.setOnItemClickListener {
val bundle = Bundle().apply {
putSerializable("recipe", it)
}
findNavController().navigate(
R.id.action_searchRecipeFragment_to_recipeFragment,
bundle
)
}
etSearch.setOnKeyListener(View.OnKeyListener { _, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN) {
if (etSearch.text.toString().isNotEmpty()) {
viewModel.searchRecipe(etSearch.text.toString())
}
return#OnKeyListener true
}
false
})
viewModel.searchRecipeLiveData.observe(viewLifecycleOwner, Observer { response ->
when (response) {
is Resource.Success -> {
hideProgressBar()
response.data?.let { recipeResponse ->
recipeAdapter.differ.submitList(recipeResponse.results.toList())
}
}
is Resource.Error -> {
hideProgressBar()
response.message?.let { message ->
Log.e(TAG, "An error occurred: $message")
Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG)
.show()
}
}
is Resource.Loading -> {
showProgressBar()
}
}
})
}
Ans this is the part of the ViewModel that I'm not really sure what it does
private fun handleSearchRecipeResponse(response: Response<SearchRecipeResponse>): Resource<SearchRecipeResponse> {
if (response.isSuccessful) {
response.body()?.let { resultResponse ->
searchRecipesPage++
if (searchRecipesResponse == null) {
searchRecipesResponse = resultResponse
} else {
val oldRecipes = searchRecipesResponse?.results
val newRecipes = resultResponse.results
oldRecipes?.addAll(newRecipes)
}
return Resource.Success(searchRecipesResponse ?: resultResponse)
}
}
return Resource.Error(response.message())
}
too late but it is because of "searchRecipesResponse". You have to set it to "null" and reset searchRecipesPage to 1 for each new search in etSearch.setOnKeyListener().
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.
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)
}
...
}
...
}
}