I am building app for android tv but having issue on manually selecting main fragment. I want click on header item to change main fragment rather than changing on focus using fragment factory.
Code
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
isHeadersTransitionOnBackEnabled = true
val listRowPresenter = ListRowPresenter(FocusHighlight.ZOOM_FACTOR_SMALL)
mRowsAdapter = ArrayObjectAdapter(listRowPresenter)
adapter = mRowsAdapter
mainFragmentRegistry.registerFragment(PageRow::class.java, PageRowFragmentFactory())
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
loadData()
headersSupportFragment.setOnHeaderViewSelectedListener { viewHolder, row ->
//Only Focus View. Don't change main fragment
}
headersSupportFragment.setOnHeaderClickedListener { viewHolder, row ->
//Change main fragment here
//No documentation provided what to write here
}
}
fun loadData() {
val headerItem1 = HeaderItem(1, "HEADER_NAME_1")
val pageRow1 = PageRow(headerItem1)
mRowsAdapter.add(pageRow1)
val headerItem2 = HeaderItem(2, "HEADER_NAME_2")
val pageRow2 = PageRow(headerItem2)
mRowsAdapter.add(pageRow2)
}
Factory
private class PageRowFragmentFactory : BrowseSupportFragment.FragmentFactory<Fragment>() {
override fun createFragment(rowObj: Any?): Fragment {
val row = rowObj as Row
return when (row.headerItem.id) {
1L -> SampleFragmentA()
2L -> SampleFragmentB()
else -> throw IllegalArgumentException(String.format("Invalid row %s", rowObj))
}
}
}
Related
my situation
my situaion
my goal
The first one here is what I want.
https://lh3.googleusercontent.com/tI4J5bPX5O1_T8EBo9jEchcWjFgDWvoo1WiivnlHNBAeSlekyZwzQY5oDfUSixVCTQfAVDqTfOTQgMIdmc1l_dAyD-V7sCBXqMUkGSezaf-pcpMSjuuF=w1064-v0
Recyclerview's itemView and ImageView are shared. But when the imageView is shared, it overlaps the toolbar. And it doesn't feel as expansive as I would like it to be.
The structure of my activity and fragment is as follows.
activity(fragmentViewPager(RecyclerViewFragment(RecyclerView))) -> detailFragment
RecyclerViewFragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
enterTransition = Hold()
parentFragment?.postponeEnterTransition()
view.doOnPreDraw {
parentFragment?.startPostponedEnterTransition()
}
}
Adapter
inner class BodyViewHolder(private val binding: ItemBodyPictureBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: AstroPicture) {
with(binding.root.context) {
val viewName = getString(R.string.shared_view).plus(layoutPosition)
ViewCompat.setTransitionName(binding.cardContainer, viewName)
val imageName = getString(R.string.shared_picture).plus(layoutPosition)
ViewCompat.setTransitionName(binding.ivThumbs, imageName)
}
binding.astroPicture = item
binding.executePendingBindings()
}
}
private fun navigateToDetail(item: AstroPicture, view: View) {
val cardView = view.findViewById<CardView>(R.id.card_container)
val imageView = view.findViewById<ImageView>(R.id.iv_thumbs)
val extras = FragmentNavigatorExtras(
cardView to cardView.transitionName,
imageView to imageView.transitionName
)
view.findNavController().navigate(
R.id.navigate_to_detail_from_pager,
bundleOf(
"item" to item,
"view" to cardView.transitionName,
"image" to imageView.transitionName
),
null,
extras
)
}
DetailFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initTransitionElement()
}
private fun initTransitionElement() {
sharedElementEnterTransition = MaterialContainerTransform().apply {
duration = 3050
drawingViewId=R.id.nav_host
isElevationShadowEnabled = true
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initTransitionName()
}
private fun initTransitionName() {
arguments?.getString("view").let {
ViewCompat.setTransitionName(binding.coordinatorLayout, it)
}
arguments?.getString("image").let {
ViewCompat.setTransitionName(binding.ivImage, it)
}
}
I found this video, is there anything I can do about it?
As shown in the video, I want the image to fit the size of the view and feel expanded.
https://youtu.be/iuvmnxTRgRM?t=1127
I have this fragment in which I store my 'favorite items' and I can delete them when I click on a button if I want to. The implementation works well until I get to the last item and it doesn't disappear unless I go to another fragment and then come back (as in, the item is deleted but the recycler view still shows it unless I update the fragment myself).
How can I make the last item disappear right away? Setting notifyDataSetChanged() after the deleteHandler in the adapter does not seem to work.
This is the fragment where I have the items:
class FavoritesFragment : Fragment() {
private val mfavoriteViewModel by viewModels<FavoriteViewModel>()
private lateinit var binding: FragmentFavoritesBinding
private val deleteHandler: (Favorites) -> Unit = {
mfavoriteViewModel.deleteFavorite(it)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
binding = FragmentFavoritesBinding.inflate(layoutInflater)
//recyclerview
val adapter = FavoritesAdapter(deleteHandler)
binding.rvFavList.layoutManager = LinearLayoutManager(context)
binding.rvFavList.adapter = adapter
//favoriteViewModel
mfavoriteViewModel.readAllData.observe(viewLifecycleOwner, { favorite ->
if (favorite.isEmpty()) {
binding.emptyState.text = getString(R.string.emptyState)
binding.emptyState.visibility = View.VISIBLE
} else {
adapter.setData(favorite)
binding.emptyState.visibility = View.GONE
}
})
return binding.root
}
}
The adapter:
class FavoritesAdapter(val deleteHandler: (Favorites) -> Unit) :
RecyclerView.Adapter<FavoritesAdapter.ViewHolder>() {
private var favoriteList = emptyList<Favorites>()
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val binding = FavItemBinding.bind(itemView)
val favTitle: TextView = binding.tvFavsTitle
val favItem: ImageButton = binding.btnFavs
val favImg: ImageView = binding.ivFavs
fun bind(favorites: Favorites) {
Picasso.get().load(favorites.image).into(favImg)
favTitle.text = favorites.title
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.fav_item, parent, false)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(favoriteList[position])
//delete favorite item
holder.favItem.setOnClickListener {
deleteHandler(favoriteList[position])
}
}
override fun getItemCount(): Int {
return favoriteList.size
}
fun setData(favorite: List<Favorites>) {
this.favoriteList = favorite
notifyDataSetChanged()
}
}
This is the favorite's viewmodel:
class FavoriteViewModel(application: Application) : AndroidViewModel(application) {
val readAllData: LiveData<List<Favorites>>
private val repository: FavoritesRepository
init {
val favoriteDao = FavoriteDatabase.getDatabase(application).favoriteDao()
repository = FavoritesRepository(favoriteDao)
readAllData = repository.readAllData
}
fun addFavorite(favorite: Favorites) {
viewModelScope.launch(Dispatchers.IO) {
repository.addFavorite(favorite)
}
}
fun deleteFavorite(favorite: Favorites) {
viewModelScope.launch(Dispatchers.IO) {
repository.deleteFavorite(favorite)
}
}
fun deleteAllFavorites() {
viewModelScope.launch(Dispatchers.IO) {
repository.deleteAllFavorites()
}
}
}
Here in your observer:
mfavoriteViewModel.readAllData.observe(viewLifecycleOwner, { favorite ->
if (favorite.isEmpty()) {
binding.emptyState.text = getString(R.string.emptyState)
binding.emptyState.visibility = View.VISIBLE
} else {
adapter.setData(favorite)
binding.emptyState.visibility = View.GONE
}
})
When the list goes from one item to zero items, in the if block you show an empty message, but you fail to update the adapter data or hide the RecyclerView so it will continue to show what it did before. You should move the adapter.setData(favorite) outside the if/else.
Clear your favourites list before setting the new items in it. You can do this in your setData() function. Like this,
fun setData(favorite: List<Favorites>) {
if (favouriteList.isNotEmpty()) {
favouriteList.clear()
}
this.favoriteList = favorite
notifyDataSetChanged()
}
I want to pass data to fragment so when items in recycler adapter clicked it pass item name (sample[position].text1) fetched from firebase to fragment. I tried bundle, interface but getting error in both methods.I searched on internet but not find anything which solve my problem. mainActivity(splash screen) is only Activity in my App rest are fragments.
I used inner class method, I'm getting result but in another fragment where this adapter attached and I don't want it there.
Problem: pass sample[position].text1 to fragment so I can pass it to db.collection("here") to fetch data from Firebase.
Adapter
class dashboard_gridlayout_adapter(
private val sampledata: ArrayList<daxhboard_gridlayout_data>
): Adapter<dashboard_gridlayout_adapter.dashboard_viewholder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): dashboard_viewholder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.dashboard_gridlayout_single_item_design, parent, false)
return dashboard_viewholder(itemView)
}
override fun onBindViewHolder(holder: dashboard_viewholder, position: Int) {
Glide.with(holder.itemView).load(sampledata[position].imageResource)
.placeholder(R.drawable.ic_baseline_history_icon)
.into(holder.imageView)
holder.textView.text = sampledata[position].text1
holder.itemView.setOnClickListener {
val appCompatActivity = it.context as AppCompatActivity
appCompatActivity.supportFragmentManager.beginTransaction()
.replace(R.id.Activity_frag_container, service_providers_list())
.addToBackStack(null)
.commit()
}
}
override fun getItemCount() = sampledata.size
inner class dashboard_viewholder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imageView: ImageView = itemView.dashboard_adapter_image
val textView: TextView = itemView.dashboard_adapter_text
}
}
Fragment
class service_providers_list : Fragment(){
private var db = FirebaseFirestore.getInstance()
private lateinit var service_list_recycler: RecyclerView
var servlist = ArrayList<service_provider_list_data>()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.service_providers_list, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
getserviceproviderdata()
service_list_recycler = service_provider_recycle_view.findViewById(R.id.service_provider_recycle_view)
service_provider_recycle_view.layoutManager = LinearLayoutManager(this.requireContext())
service_provider_recycle_view.setHasFixedSize(true)
}
private fun getserviceproviderdata() {
db.collection("Barber").orderBy("dist")
.get()
.addOnSuccessListener { documents ->
servlist.clear()
for (document in documents) {
val imgurl = document.data["imageResource"].toString()
val prov_name = document.data["provider_name"].toString()
val prov_address = document.data["provider_address"].toString()
val prov_rate = document.data["provider_rating"].toString()
val prov_dist = document.data["provider_distance"].toString()
servlist.add(service_provider_list_data(imgurl, prov_name, prov_address, prov_rate, prov_dist))
service_provider_recycle_view.adapter = service_provider_list_adapter(servlist)
}
}
.addOnFailureListener { exception ->
Log.e("serf", "Error getting documents: ", exception)
}
}
}
MainActivity (It's a splash screen)
class MainActivity : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
#Suppress("DEPRECATION")
Handler().postDelayed(
{
supportFragmentManager.beginTransaction().replace(R.id.Activity_frag_container,Login_Screen()).commit()
},
1500
)
}
}
I solved this problem
just add new parameter(need to pass) inside replace in adapter
holder.itemView.setOnClickListener {
val datashares = sampledata[position].text1
val appCompatActivity = it.context as AppCompatActivity
appCompatActivity.supportFragmentManager.beginTransaction()
.replace(R.id.Activity_frag_container, service_providers_list(datashares))
.addToBackStack(null)
.commit()
}
and inside fragment just add
class service_providers_list(datashares: String) Fragment(){
//variable declaration
private var datasharae = datashares
(inside function where i wnt to add code i.e getserviceproviderdata() )
fun getserviceproviderdata() {
db.collection(datasharae)
.............
..............
......rest code.....
.........}
when i click recycler item it move to new fragment but when come back
to recycler items their number get doubled.how can i solve this issue
so it only pass item only one time and item not get doubled.using addOSnapshoListner also has no effect
thanks in advance
Code where adapter attached
private var db =FirebaseFirestore.getInstance()
private lateinit var userrecycler : RecyclerView
var list = ArrayList<daxhboard_gridlayout_data>()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.dashboard_screen, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (list.isEmpty()){
getUserdata()
userrecycler = dashboard_grid_recycleView.findViewById(R.id.dashboard_grid_recycleView)
dashboard_grid_recycleView.layoutManager = GridLayoutManager(this.requireContext(), 2)
dashboard_grid_recycleView.setHasFixedSize(true)}}`
private fun getUserdata(){
db.collection("services")
.get()
.addOnSuccessListener { documents ->
for (document in documents) {
val imgurl = document.data["imageResource"].toString()
val text = document.data["text1"].toString()
list.add(daxhboard_gridlayout_data(imgurl,text))
dashboard_grid_recycleView.adapter = dashboard_gridlayout_adapter(list)
}
}
.addOnFailureListener { exception ->
Log.e("serf", "Error getting documents: ", exception)
}
}`
Adapter code
class dashboard_gridlayout_adapter(private val sampledata: ArrayList<daxhboard_gridlayout_data>):
Adapter<dashboard_gridlayout_adapter.dashboard_viewholder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): dashboard_viewholder {
val itemView =
LayoutInflater.from(parent.context).inflate(R.layout.dashboard_gridlayout_single_item_design, parent,
false)
return dashboard_viewholder(itemView)
}
override fun onBindViewHolder(holder: dashboard_viewholder, position: Int) {
val currentitem = sampledata[position]
Glide.with(holder.itemView).load(currentitem.imageResource)
.into(holder.imageView)
holder.textView.text = currentitem.text1
holder.itemView.setOnClickListener {
val appCompatActivity = it.context as AppCompatActivity
appCompatActivity.supportFragmentManager.beginTransaction()
.replace(R.id.Activity_frag_container, service_providers_list())
.addToBackStack(null)
.commit()
}
}
override fun getItemCount()=sampledata.size
class dashboard_viewholder(itemView: View) : RecyclerView.ViewHolder(itemView){
val imageView: ImageView = itemView.dashboard_adapter_image
val textView: TextView = itemView.dashboard_adapter_text
}
You need to clear the list before adding items to it.
Just add the list.clear() line, and it should work.
private fun getUserdata(){
db.collection("services")
.get()
.addOnSuccessListener { documents ->
list.clear()
for (document in documents) {
val imgurl = document.data["imageResource"].toString()
val text = document.data["text1"].toString()
list.add(daxhboard_gridlayout_data(imgurl,text))
dashboard_grid_recycleView.adapter = dashboard_gridlayout_adapter(list)
}
}
.addOnFailureListener { exception ->
Log.e("serf", "Error getting documents: ", exception)
}
}
I also recomend you take a look at the lifecycle of fragments.
it worked if i remove list.empty() condition form where adapter code is attached and use list.clear() inside OnSuccessListner it works
I will try to be more specific about my issue. I start saying I've already seen this question that shows the same kind of problem, I guess, but I didn't really understand the right solution.
Note: I have created the drawer activity and all navigation dependencies from a template in creating new project step
Initially, I found that when, in ShowProfileFragment, I tried to update the header of the navigation drawer, the same issue happened, so when I put that if statement (see code below) to update it only if necessary, the problem seemed to be vanished (because opening this fragment from drawer doesn't perform this action anymore).
Now, when in ItemListFragment I add all my objects, taken from SharedPreferences to the ArrayList passed to an adapter (ItemCardsAdapter) everything works well until in onBindViewHolder of my adapter I perform setImageBitmap on the ImageView. It appears to be wasting time loading bitmaps...
Note: when I run the app on a real device (my phone) the issue is very highlighted, unlike what happens in the emulator on my pc (here, it was highlighted at the beginning, when issue regarded the profile picture's updating on the drawer's header)
Here is my code:
MainActivity.kt
import ...
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private var host: NavHostFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
host = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment?
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
var navController = host?.navController //findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
// if (savedInstanceState != null) {
// //Restore the fragment's instance
// navController = (supportFragmentManager.getFragment(savedInstanceState, "myFragmentEdit")!! as NavHostFragment?)!!.navController
// }
appBarConfiguration = AppBarConfiguration(setOf(R.id.nav_showprofile, R.id.nav_itemlist), drawerLayout)
setupActionBarWithNavController(navController!!, appBarConfiguration)
navView.setupWithNavController(navController)
/*short info in drawer's header taken from SharedPrefs*/
val sharedPref = getSharedPreferences(getString(R.string.shared_pref_key), Context.MODE_PRIVATE)
val parsedData = sharedPref.getString(getString(R.string.profile_json),"missing data")
if(parsedData != "missing data")
{
val json = Json(JsonConfiguration.Stable)
val obj = json.parse(User.serializer(),parsedData!!)
if(obj.photoPath != "")
navView.getHeaderView(0).header_userpic.setImageBitmap(getCircledBitmap(decodeSampledBitmapFromResource(obj.photoPath,256,256)))
navView.getHeaderView(0).header_username.text = obj.name
navView.getHeaderView(0).header_usermail.text = obj.email
}
else
{
//profile pic path as for as other info are taken from resources here
navView.getHeaderView(0).header_username.text = getString(R.string.user_name)
navView.getHeaderView(0).header_usermail.text = getString(R.string.user_mail)
}
}
// override fun onSaveInstanceState(outState: Bundle) {
// super.onSaveInstanceState(outState)
// supportFragmentManager.putFragment(outState, "myFragmentEdit", host!!)
// }
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
override fun onBackPressed() {
super.onBackPressed()
}
}
ShowProfileFragment.kt
import ...
class ShowProfileFragment : Fragment() {
companion object {
fun newInstance() = ShowProfileFragment()
}
private lateinit var viewModel: ShowProfileViewModel
#SuppressLint("RestrictedApi")
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.show_profile_fragment, container, false)
viewModel = ViewModelProviders.of(this).get(ShowProfileViewModel::class.java)
/*get User info from SharedPrefs*/
val sharedPref = this.activity!!.getSharedPreferences(getString(R.string.shared_pref_key), Context.MODE_PRIVATE)
val parsedData = sharedPref.getString(getString(R.string.profile_json),"missing data")
if(parsedData != "missing data")
{
val json = Json(JsonConfiguration.Stable)
val obj = json.parse(User.serializer(),parsedData!!)
/*update header info after user clicks save*/
val header = activity!!.findViewById(R.id.nav_view) as NavigationView
header.getHeaderView(0).header_username.text = obj.name
header.getHeaderView(0).header_usermail.text = obj.email
if(obj.photoPath != "")
{
if(arguments?.getString("headerPic") == "update") /*I mean this statement*/
header.getHeaderView(0).header_userpic.setImageBitmap(getCircledBitmap(decodeSampledBitmapFromResource(obj.photoPath,256,256)))
root.photo.setImageBitmap(getCircledBitmap(decodeSampledBitmapFromResource(obj.photoPath,256,256)))
}
viewModel.userKey = obj.userId
root.full_name.text = obj.name
root.nickname.text = obj.nickname
root.email.text = obj.email
root.geographic_area.text = obj.country
//Log.d("kkk","header info from showProfile: name = ${header.getHeaderView(0).header_username.text}")
}
val storageDir = activity!!.getExternalFilesDir(Environment.DIRECTORY_PICTURES)!!
removeIllegalProfilePic(storageDir,sharedPref)
setHasOptionsMenu(true)
return root
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.edit_profile, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when(item.itemId){
R.id.editProfileFragment -> {
val bundle = bundleOf("userKey" to viewModel.userKey)
findNavController().navigate(R.id.action_nav_showprofile_to_editProfileFragment, bundle)
true
}
else -> {
super.onOptionsItemSelected(item)
}
}
//return NavigationUI.onNavDestinationSelected(item, view!!.findNavController()) || super.onOptionsItemSelected(item)
}
#SuppressLint("SimpleDateFormat")
private fun removeIllegalProfilePic(root: File, sPrefs: SharedPreferences){
/*check for illegal 0B file, caused of app termination from the camera activity*/
/*and for illegal file generated by any Activity.RESULT_OK caused of app termination from EditProfileActivity*/
val illegalProfilePic = sPrefs.getString(getString(R.string.illegal_profile_pic_key),"saved")
for(f in root.listFiles()!!)
if (f.length() <= 0 || f.absolutePath == illegalProfilePic)
f.delete()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(ShowProfileViewModel::class.java)
// TODO: Use the ViewModel
}
}
ItemListFragment.kt
import ...
class ItemListFragment : Fragment() {
companion object {
fun newInstance() = ItemListFragment()
}
private lateinit var viewModel: ItemListViewModel
//var itemCardsArray= ArrayList<Item>()
lateinit var mAdapter : ItemCardsAdapter
#SuppressLint("RestrictedApi")
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewModel = ViewModelProviders.of(this).get(ItemListViewModel::class.java)
val root = inflater.inflate(R.layout.item_list_fragment, container, false)
val viewManagerPortrait = LinearLayoutManager(activity)
val viewManagerLandscape = GridLayoutManager(activity, 3)
/*adapter -> taken from SharedPrefs*/
var itemCardsArray= ArrayList<Item>()
//itemCardsArray.add( Item("path","Teddy Bear","Sweet Bear baby peluche","13.49","Toddler Toys","Turin","20/12/2020") )
val sharedPref = this.activity!!.getSharedPreferences(getString(R.string.shared_pref_key), Context.MODE_PRIVATE)
val itemCount = sharedPref.getInt(getString(R.string.item_count), 0)
if(itemCount == 0)
root.listItems.visibility = View.GONE
else
{
root.emptyAds.visibility = View.GONE
mAdapter = ItemCardsAdapter(itemCardsArray, this)
//viewAdapter.notifyDataSetChanged()
root.listItems.apply {
setHasFixedSize(true)
// use a linear layout manager if portrait, grid one else
layoutManager = if(activity!!.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE)
viewManagerLandscape
else
viewManagerPortrait
// specify an viewAdapter (see also next example)
adapter = mAdapter
//adapter!!.notifyDataSetChanged()
}
for(i in 1..itemCount)
{
val parsedData = sharedPref.getString(getString(R.string.item_json)+i.toString(),"missing data")
if(parsedData != "missing data")
{
val json = Json(JsonConfiguration.Stable)
val obj = json.parse(Item.serializer(),parsedData!!)
itemCardsArray.add(i-1, obj)
mAdapter.notifyItemInserted(i-1)
}
}
}
root.fab_addItem.setOnClickListener {
Snackbar.make(it, "Creating new advertisement...", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
findNavController().navigate(R.id.action_nav_itemlist_to_itemEditFragment)
}
return root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(ItemListViewModel::class.java)
// TODO: Use the ViewModel
}
}
ItemCardsAdapter.kt
import ...
class ItemCardsAdapter(private val myDataset: ArrayList<Item>, private val f: Fragment) : RecyclerView.Adapter<ItemCardsAdapter.MyViewHolder>() {
class MyViewHolder(viewItem: View) : RecyclerView.ViewHolder(viewItem){
val itemphoto = viewItem.itemphoto
val itemtitle = viewItem.title
val itemprice = viewItem.itemprice
val itemlocation = viewItem.itemlocation
val editpencil = viewItem.editCard
}
// Create new views (invoked by the layout manager)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
// create a new view
val viewItem = LayoutInflater.from(parent.context).inflate(R.layout.item_card, parent, false)
// set the view's size, margins, paddings and layout parameters
return MyViewHolder(viewItem)
}
// Replace the contents of a view (invoked by the layout manager)
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.itemtitle.text = myDataset[position].title
holder.itemprice.text = myDataset[position].price
holder.itemlocation.text = myDataset[position].location
if(myDataset[position].photoPath != "") /*Here it stucks on load !?*/
holder.itemphoto.setImageBitmap(decodeSampledBitmapFromResource(myDataset[position].photoPath,256,256))
//holder.View.startAnimation(AnimationUtils.loadLayoutAnimation(this,R.anim.layout_animation))
val bundle = bundleOf("itemAdKey" to myDataset[position].adId)
holder.editpencil.setOnClickListener {
bundle.putString("nav", "editCard")
f.findNavController().navigate(R.id.action_nav_itemlist_to_itemEditFragment, bundle)
}
holder.itemView.setOnClickListener {
f.findNavController().navigate(R.id.action_nav_itemlist_to_nav_itemdetails, bundle)
}
}
// Return the size of your dataset (invoked by the layout manager)
override fun getItemCount() = myDataset.size
}
I found the solution, following this official documentation:
https://developer.android.com/topic/performance/graphics
that recommends to use this external library to solve that kind of memory caching issues: Glide
So, I changed, for example, this
ItemCardsAdapter.kt
holder.itemphoto.setImageBitmap(decodeSampledBitmapFromResource(myDataset[position].photoPath,256,256))
with this
Glide.with(f.activity!!).load(myDataset[position].photoPath).into(holder.itemphoto)