How to pass Firebase Realtime database images from reyclerview to image view in another activity. KOTLIN - kotlin

I have Firebase Realtime Database images displayed in a reyclerview. When users click that image, I want it to send the image to another activity's IMAGEVIEW and open that activity at the same time.
These are pictures of an example I saw on Youtube
As you can see in the second picture. It sent the data from the recyclerview to the imageview in the activity and opened that activity.
My 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) {
holder.imageView.setOnClickListener {
val intent = Intent(mContext, PreviewActivity::class.java)
intent.putExtra("abstract", abstractList[position].abstract.toString())
mContext.startActivity(intent)
}
holder.download_btn.setOnClickListener { }
Glide.with(mContext)
.load(abstractList[position].abstract)
.into(holder.imageView)
}
override fun getItemCount(): Int {
return abstractList.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imageView: ImageView = itemView.findViewById(R.id.abstractImageView)
val download_btn: Button = itemView.findViewById(R.id.abstractDownloadBtn)
}
companion object {
private const val Tag = "RecyclerView"
}
Activity to receive image
class PreviewActivity : AppCompatActivity() {
private lateinit var previewImage: ImageView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_preview)
previewImage = findViewById(R.id.preview_image)
val previewImage: ImageView = findViewById(R.id.preview_image)
val bundle :Bundle? = intent.extras
val preview = bundle!!.getString("abstract")
}
Data model
class Abstract(var abstract: String? = null) {
}
I've tried running this code, but it doesn't show my image in the next activity. The Logcat doesn't give me any error, because according to it my code is running perfectly except that it's not showing the image in the next activity. I must be missing something, but I don't know what it is.

You have to set the image url to ImageView using Glide in second activity like this:
class PreviewActivity : AppCompatActivity() {
private lateinit var previewImage: ImageView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_preview)
previewImage = findViewById(R.id.preview_image)
val previewImage: ImageView = findViewById(R.id.preview_image)
val bundle :Bundle? = intent.extras
val preview = bundle!!.getString("abstract")
Glide.with(this)
.load(preview)
.into(previewImage)
}

Related

How can I change recyclerview item background color permanent and transact new Fragment?

I want to change the color of recyclervView item that I clicked(so user can understand that already checked the detail of the item) and go detail fragment page. However this background color change must be permanent should I store it in livedata of recycler view items. I share my codes at the end I am new to android programming so please explain your solution for beginner and my english level is not good. Thanks for everything.
class AdapterRecycler() :
RecyclerView.Adapter<AdapterRecycler.ViewHolder>()
class ViewHolder(view: View, listener: onItemClickListener) : RecyclerView.ViewHolder(view) {
val name: TextView = view.findViewById(R.id.gameId)
val score: TextView = view.findViewById(R.id.scoreId)
val genre: TextView = view.findViewById(R.id.genres)
val layout1: RelativeLayout = view.findViewById(R.id.rowlayout)
init {
// Define click listener for the ViewHolder's View.
//val textView : TextView = view.findViewById(R.id.gameId)
itemView.setOnClickListener {
layout1.setBackgroundColor(Color.rgb(224,224,224))
listener.onItemClick(adapterPosition)
}
}
}
// Create new views (invoked by the layout manager)
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
// Create a new view, which defines the UI of the list item
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.text_row_item, viewGroup, false)
return ViewHolder(view, listenerItems)
}
class Games : Fragment() {
...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
...
adapter.setOnItemClickListener(object : AdapterRecycler.onItemClickListener {
override fun onItemClick(position: Int) {
// Fragment transaction to detail page
requireActivity().supportFragmentManager.beginTransaction()
.replace(R.id.fragmentContainerView2, Details()).commit()
}
})
}
Should I store a boolean value in here to save item checked status?
data class Game(val name : String, val score : Int, val genres : Array<String>)
I tried solution at my codes and I get transaction but not the color changes of item layout.
I think it will be good if you'll update your Game model, after it became checked. Something like this:
data class Game(.., var isChecked: Boolean = false)
And inside your AdapterRecycler.onItemClickListener realization call ViewModel function to update isChecked value:
fun onItemChecked(position: Int) {
val item = TODO("get item by position from your live data")
item.isChecked = !item.isChecked
}
In addition, you should override your ViewHolder to setup a background rely on your isCheked value (it will be the same as must be after ViewHolder notify calls):
class ViewHolder(view: View, listener: onItemClickListener) : RecyclerView.ViewHolder(view) {
...
fun bind(item: Game) {
val backColor = if (item.isChecked) Color.GREEN else Color.BLUE
layout1.setBackgroundColor(Color.rgb(224,224,224))
}
}
Call bind function from your AdapterRecycler.onBindViewHolder this way:
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position), callback)
}
Don't forget to notify your adapter.
Guys thanks to your replies I reviewed my code and got solution.
Here is my edit at the code:
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
...
val color = if (_data[position].isChecked) Color.rgb(224,224,224) else Color.WHITE
viewHolder.layout1.setBackgroundColor(color)
...
}
That way I change the color of recyclerview item color since I change the fragments make the viewmodel at activity based and used it shared viewModel between fragments
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: GamesViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
...
viewModel = ViewModelProvider(this)[GamesViewModel::class.java]
...
}
Then I added the boolean variable to my model.
data class Game(val name : String, val score : Int, val genres : Array<String>, var isChecked : Boolean = false)
Then I change the liveData's attribute of isChecked at the click listener.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter.setOnItemClickListener(object : AdapterRecycler.onItemClickListener {
override fun onItemClick(position: Int) {
viewModel= ViewModelProvider(requireActivity()).get(GamesViewModel::class.java)
val item = viewModel.liveData.value!!.get(position)
item.isChecked = true
// toGo next fragment
requireActivity().supportFragmentManager.beginTransaction()
.replace(R.id.fragmentContainerView2, Details()).commit()
}
})
VoilĂ  we got the perfect result thanks for helping me, have a great day.

Update firestore data from populated recycler View

I want to update firestore data which I have got in a Recycler view.
Recycler View Activity Code
class AdminActivity : AppCompatActivity() {
private val dB = Firebase.firestore
private lateinit var userRecyclerView: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.title = "Admin Panel"
userRecyclerView = findViewById(R.id.user_list)
userRecyclerView.layoutManager = LinearLayoutManager(this)
userRecyclerView.setHasFixedSize(true)
val query = dB.collection("users")
val options = FirestoreRecyclerOptions.Builder<User>().setQuery(query, User::class.java)
.setLifecycleOwner(this).build()
//adapter
val adapter = object : FirestoreRecyclerAdapter<User, UserViewHolder>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val view = LayoutInflater.from(this#AdminActivity)
.inflate(R.layout.user_item, parent, false)
return UserViewHolder(view)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int, model: User) {
val nameTv: TextView = holder.itemView.findViewById(R.id.name_textview)
val idTv: TextView = holder.itemView.findViewById(R.id.id_textview)
val phoneTv: TextView = holder.itemView.findViewById(R.id.phone_textview)
nameTv.text = model.name
idTv.text = model.id
phoneTv.text = model.phone
holder.itemView.setOnClickListener {
val intent = Intent(baseContext, AdminViewActivity::class.java)
startActivity(intent)
}
}
}
userRecyclerView.adapter = adapter
}
}
I want to update the data when i click on the holder.
Only update the data of the user whose recycler view I clicked.
Firestore Database Image

RecyclerView doesn't display data but onBindViewHolder never called

I'm using recyclerView to display my data but anything is displaying. The onBindViewHolder is never called and the onCreateViewHolder also.
I initialize the adapter in the viewModel with the data which I got from room but anything is displaying. The data in the viewModel is there when I want give it to the adaptater.
There's the adaptater,
class CountryInfoAdapter : RecyclerView.Adapter<TextItemViewHolder>() {
var data = listOf<DevByteCountryProperty>()
set(value) {
field = value
notifyDataSetChanged()
}
override fun getItemCount() = data.size
override fun onBindViewHolder(holder: TextItemViewHolder, position: Int) {
val item = data[position]
holder.textView.text = item.name.toString()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextItemViewHolder {
//The inflater knows how to create views from XML layout. The context is the context of the RecyclerView.
val layoutInflater = LayoutInflater.from(parent.context)
val view = layoutInflater.inflate(R.layout.text_item_view, parent, false) as TextView
Timber.i("Data from adaptater : ${data.toString()}")
return TextItemViewHolder(view)
}
}
There is the Fragment,
class CountryInfoFragment : Fragment() {
private lateinit var viewModel: CountryInfoViewModel
private lateinit var viewModelFactory: CountryInfoViewModelFactory
private lateinit var binding: FragmentCountryInfoBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
binding = DataBindingUtil.inflate(inflater,
R.layout.fragment_country_info,container,false)
val application = requireNotNull(this.activity).application
viewModelFactory = CountryInfoViewModelFactory(application)
viewModel = ViewModelProvider(this,viewModelFactory).get(CountryInfoViewModel::class.java)
binding.viewModel = viewModel
val adapter = CountryInfoAdapter()
viewModel.countriesProperty.observe(viewLifecycleOwner, Observer {
it?.let {
adapter.data = it
}
})
binding.countryList.adapter = adapter
binding.lifecycleOwner = viewLifecycleOwner
setHasOptionsMenu(true)
return binding.root
}
}
Please try below code, setting up layout manager before assigning adapter to recyclerView
binding.countryList.layoutManager = LinearLayoutManager(this)
binding.countryList.adapter = adapter

Kotlin OnItemClickListener for a RecyclerView inside a Fragment

The problem is related to the fact that I don't manage to implement a OnItemClick listener for a RecyclerView that is located in a "mainFragment" by implementing the OnClickListener in the Adapter.
I would like my application (kotlin) to launch another fragment ("deletePage" in the code bellow) everytime an itemView (an ImageView) from the RecyclerView is clicked, this fragment would display the same photo in big.
My Adapter code is the following one:
class MyAdapter : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
private var photo = emptyList<Photo>()
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.row_layout, parent, false)
)
}
override fun getItemCount(): Int {
return photo.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.itemView.longitude.text = photo[position].latitude
holder.itemView.latitude.text = photo[position].longitude
holder.itemView.imageView.load(photo[position].photo)
}
fun setData(photo: List<Photo>) {
this.photo = photo
notifyDataSetChanged()
}
}
And my mainFragment code is the following one:
class MainFragment : Fragment(){
private lateinit var myView: MyViewModel
private val adapter by lazy { MyAdapter() }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_main, container, false)
//Recyclerview
val adapter = MyAdapter()
val recyclerView = view.recycler_view
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(requireContext())
myView = ViewModelProvider(this).get(MyViewModel::class.java)
myView.readPhoto.observe(viewLifecycleOwner, Observer {photo ->
adapter.setData(photo)
})
setHasOptionsMenu(true)
return view
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_database, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when {
item.itemId == R.id.deleteAll -> findNavController().navigate(R.id.deletePage)
item.itemId == R.id.refresh -> {
Toast.makeText(activity, "yep", Toast.LENGTH_SHORT).show()
instertDataToDatabase()
}
}
if (item.itemId == R.id.deleteAll) {
}
return super.onOptionsItemSelected(item)
}
}
The objective is that when you click on an item of the RecyclerView the "findNavController().navigate(R.id.deletePage)" fragment is displayed but everytime I try to implement a solution the application crashes when clicking at an item of the RecyclerView. Right now the navigation works by the click on a button in the Menu at the toolbar but is not the ideal solution.
Any sort of help or advice would be very much appreciated!
Firstly you need to give click listener of your itemView in onBindViewHolder
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.itemView.longitude.text = photo[position].latitude
holder.itemView.latitude.text = photo[position].longitude
holder.itemView.imageView.load(photo[position].photo)
holder.itemView.setOnClickListener { navigateToFragment() }
}
For the navigation somehow you should have a context instance.
Here is the possible solutions that came up to my mind:
Give navigator instance to adapter
class Navigator(fragment: Fragment) {
private val fragmentRef = WeakReference(fragment)
fun navigate(){
// make your navigations here with using fragmentRef.get()
}
}
In your fragment:
private val navigator = Navigator(this)
...
val adapter = MyAdapter(navigator)
In your adapter:
class MyAdapter(private val navigator: Navigator) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
fun navigateToFragment(){
navigator.navigate()
}
Make interface for callback
2.1. Implement that interface in fragment and give adapter the interface instance
interface Navigable{
fun navigate()
}
In your fragment:
class MainFragment : Fragment(), Navigable{
...
override fun navigate(){
// make your navigation
}
val adapter = MyAdapter(navigator)
In your adapter:
class MyAdapter(private val navigable: Navigable) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
fun navigateToFragment(){
navigable.navigate()
}
2.2. Make the interface, but do not pass reference, use findFragment in adapter
In your adapter: override onAttachedToRecyclerView to find fragment
private lateinit var navigable: Navigable
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
navigable = recyclerView.findFragment<Fragment>() as Navigable
}
fun navigateToFragment(){
navigable.navigate()
}

RecyclerView onClick in kotlin

I'm new android learner, I'm trying to make a RecyclerView contains of List of (Stories Title, and Stories images).
When you click on an item in the RecyclerView it should open a new activity called ChildrenStoriesPreview contains of ScrollView which have ImageView to put the Story Image in it and TextView to put the Text of the Story in it.
the problem is that I don't know how to set ocItemClickListener to know which item is clicked and how the new activity will contain information depending on this item? Could you please help me?
here is my Main.kt
class MainChildrenStories : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_children_stories)
var childrenStoriesArraylist = ArrayList<ChildrenStoriesRecyclerView>()
childrenStoriesArraylist.add(ChildrenStoriesRecyclerView("Story1", R.drawable.pic1))
childrenStoriesArraylist.add(ChildrenStoriesRecyclerView("Story2", R.drawable.pic2))
childrenStoriesArraylist.add(ChildrenStoriesRecyclerView("Story3", R.drawable.pic3))
children_stories_recyclerview.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL, false)
val childrenStoriesAdapter = ChildrenStoriesAdapter(childrenStoriesArraylist)
children_stories_recyclerview.adapter = childrenStoriesAdapter
childrenStoriesAdapter.setOnItemClickListener(object : ChildrenStoriesAdapter.ClickListener {
override fun onClick(pos: Int, aView: View) {
//The App Crash here
if (pos == 0){
my_text_view.text = "Story number 1"
my_imageview.setImageResource(R.drawable.pic1)
}else if (pos == 1){
my_text_view.text = "Story number 2"
my_imageview.setImageResource(R.drawable.pic2)
}
val intent = Intent(this#MainChildrenStories, ChildrenStoryPreview::class.java)
startActivity(intent)
}
})
}
}
MyRecyclerView Class
data class ChildrenStoriesRecyclerView(var mStoryName: String, var mStoryImage: Int)
My RecyclerView Adapter Class
class ChildrenStoriesAdapter(var myArrayList: ArrayList<ChildrenStoriesRecyclerView>) :
RecyclerView.Adapter<ChildrenStoriesAdapter.ViewHolder>() {
lateinit var mClickListener: ClickListener
fun setOnItemClickListener(aClickListener: ClickListener) {
mClickListener = aClickListener
}
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): ViewHolder {
val v = LayoutInflater.from(p0.context).inflate(R.layout.children_stories_list, p0, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return myArrayList.size
}
override fun onBindViewHolder(p0: ViewHolder, p1: Int) {
var infList = myArrayList[p1]
p0.storyName.text = infList.mStoryName
p0.storyImage.setImageResource(infList.mStoryImage)
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
override fun onClick(v: View) {
mClickListener.onClick(adapterPosition, v)
}
val storyName = itemView.findViewById(R.id.txtStoryName) as TextView
val storyImage = itemView.findViewById(R.id.imageViewChildrenStories) as ImageView
init {
itemView.setOnClickListener(this)
}
}
interface ClickListener {
fun onClick(pos: Int, aView: View)
}
}
My new Activity To show Details of the Story
class ChildrenStoryPreview : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_children_story_preview)
}
}
Pass the Event Listener to Adapter constructor also to viewholder to catch view holder (items) clicks.
class ChildrenStoriesAdapter(var myArrayList: ArrayList<ChildrenStoriesRecyclerView>
var clickListener:MyClickListener?) :
RecyclerView.Adapter<ChildrenStoriesAdapter.ViewHolder>() {
...
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): ViewHolder {
val v = LayoutInflater.from(p0.context).inflate(R.layout.children_stories_list, p0, false)
return ViewHolder(v, clickListener)
}
...
inner class ViewHolder(itemView: View, clickListener:MyClickListener?) :
RecyclerView.ViewHolder(itemView) {
itemView.setOnClickListener { clickListener?.myClickedFun(...) }
...
class ChildrenStoryPreview : AppCompatActivity(), MyClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_children_story_preview)
}
override fun myClickedFun(...) {
...
}
}
Later init adapter like
..
val childrenStoriesAdapter = ChildrenStoriesAdapter(childrenStoriesArraylist, this)