notifyDataSetChanged() doesn't call's onBindViewHolder() method - java

I have a RecyclerView's Adapter, where I am adding items dynamically, when I am calling the my adapter's updateMessages function old data list were changing correctly but, recycler items stays the same.
this is my updateMessages method in my adapter:
fun updateMessages(messages: List<MessageReceivedResponseModel>?){
messages?.let {
this.messages.clear()
this.messages.addAll(messages)
}
notifyDataSetChanged()
}
also here is complete adapter class, I don't understand what's the problem
class MessagesRecyclerAdapter(private val itemActionListener: IOnMessageItemActionListener) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val messages = ArrayList<MessageReceivedResponseModel>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.awesome_chat_item, parent, false)
return MyHolder(view)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
(holder as MyHolder).updateUI(messages[position])
}
override fun getItemCount(): Int {
return messages.size
}
fun updateMessages(messages: List<MessageReceivedResponseModel>?){
messages?.let {
this.messages.clear()
this.messages.addAll(messages)
}
notifyDataSetChanged()
}
private inner class MyHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val messageTextView: TextView = itemView.findViewById(R.id.chat_from_text_id) as TextView
private val msgQuantityTextView: TextView = itemView.findViewById(R.id.msg_quantity_txt_id) as TextView
internal fun updateUI(msg: MessageReceivedResponseModel) {
messageTextView.text = msg.from
msgQuantityTextView.text = msg.quantity.toString()
}
}
}
this is where my adapter and recycler initialization goes
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater?.inflate(R.layout.activity_awesome_chat, container, false)
recycler = view?.findViewById(R.id.awesome_chat_list_view_id) as RecyclerView
val layoutManager = LinearLayoutManager(activity)
recycler?.layoutManager = layoutManager
.....
}
override fun onMessageReceived(messages: List<MessageReceivedResponseModel>){
adapter?.updateMessages(messages)
Log.e(TAG, messages.size.toString())
}
// called in oncreateView of fragment
private fun initRecycler(items: List<MessageReceivedResponseModel>?) {
adapter = MessagesRecyclerAdapter(this)
adapter?.updateMessages(items)
recycler?.adapter = adapter
Log.e(TAG, items?.size.toString())
}

I realized my problem where out of all this classes, The problem was in my interactor class where the messages retrieving requests started
fun startMessageRetrieveRequest(callback: OnRequestFinishedListener<List<MessageReceivedResponseModel>>){
doAsync {
Thread.sleep(1000)
val idx = Random().nextInt(2)
val its: List<MessageReceivedResponseModel>
when(idx){
0 -> its = REs
1 -> its = RES_1
else -> its = RES_1
}
callback.onResponse(its)
}
}
I removed doAsync and works correctly, here callback.onResponse() is being called from Non-UI thread and it caused the problem Only the original thread that created a view hierarchy can touch its views., but not always. Also app weren't crashed and I missed the log

Try using notifyItemRangeChanged(0, messages.size - 1);.
fun updateMessages(messages: List<MessageReceivedResponseModel>?){
messages?.let {
this.messages.clear()
this.messages.addAll(messages)
this.notifyItemRangeChanged(0, messages.size - 1)
}
}
I think notifyDataSetChanged() isn't working because your dataset (messages field) is still the same object.
You can try to replace object of messages:
fun updateMessages(messages: List<MessageReceivedResponseModel>?){
messages?.let {
this.messages = messages
notifyDataSetChanged()
}
}

You should use notifyDataSetChanged(); on your adapter, like this:
adapter.notifyDataSetChanged(); .
If you wanna use a class you can, you just need to declare the adapter variable as a member variable of the class and call the method like I said above. Where adapter is the name of your adapter.

Related

Error Updating Recycler View Item Button Visibility outside Adapter

My goal is to have button inside each RecyclerView item that will appear on click so Im changing the buttons visibility. On the first click it works fine but on clicking again or in any other item it crashes the app.
This is my Adapter.kt
class Adapter (private val orders:ArrayList<Order>, private val listener : OnItemClickListener) : RecyclerView.Adapter<Adapter.ViewHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_pedido,parent,false)
return ViewHolder(itemView)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val currentItem = orders[position]
holder.nrPedido.text = currentItem.id.toString()
holder.distancia.text = currentItem.distancia.toString()+"km"
holder.estado.text = currentItem.estado
}
override fun getItemCount(): Int {
return orders.size
}
inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView),
View.OnClickListener{
val nrPedido : TextView = itemView.findViewById(R.id.textViewIDPedido)
val distancia : TextView = itemView.findViewById(R.id.textViewDistancia)
val estado : TextView = itemView.findViewById(R.id.textViewEstado)
val buttonEstado : Button = itemView.findViewById(R.id.buttonEstado)
val buttonAceitarRecusar : Button = itemView.findViewById(R.id.buttonAceitarRecusar)
val buttonDados : Button = itemView.findViewById(R.id.buttonDados)
init {
itemView.setOnClickListener(this)
}
override fun onClick(p0: View?) {
val holder = ViewHolder(itemView)
val order = orders[adapterPosition]
val position = adapterPosition
if(position != RecyclerView.NO_POSITION && order != null) {
listener.onItemClick(order,position,holder)
}
}
}
interface OnItemClickListener{
fun onItemClick(order: Order,position: Int,holder: ViewHolder)
}
}
This Is my mainActivity where the onItemClick Method is being called
override fun onItemClick(order: Order,position:Int,holder: Adapter.ViewHolder) {
visible = visible?.not()
if(arrayListPedidos.contains(order)){
val clickedItem = arrayListPedidos[position]
if(visible==true){
holder.buttonDados.visibility = View.VISIBLE
}else{
holder.buttonDados.visibility = View.INVISIBLE
}
}else if(arrayListMeusPedidos.contains(order)){
val clickedItem = arrayListMeusPedidos[position]
if(visible==true){
holder.buttonDados.visibility = View.VISIBLE
}else{
holder.buttonDados.visibility = View.INVISIBLE
}
}
}
I think it could be something to do with not notifying that the item is being updated, but it could also be the way im sending the holder.
When I click one time on the item it changed the visibility to visible. If I click again (to make it invisible) or if I click in any other item it crashed the app.
Think about the ViewHolder as a highly volatile view, you don't want to keep any references about it that you use outside the Adapter – I see that you pass the ViewHolder back into the MainActivity if I understand correctly what you are trying to achieve could be done by doing something like this:
class Adapter(
private val orders: ArrayList<Order>,
// Note: Modern callbacks are declared like this, don't worry about passing the
// OnItemClickListener
private val listener: ((Order) -> Unit)
) : RecyclerView.Adapter<ViewHolder> { // Note: Try to use your own ViewHolders
// In situations like this you can use a map or some other data structure to keep track of what
// order button is supposed to be visible or not. You could also keep track of this in the Order
// class itself.
private val isVisibleMap = mutableMapOf<Int, Boolean>().apply {
orders.forEachIndexed { index, _ -> put(index, false) }
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_pedido,parent,false)
return ViewHolder(itemView)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val currentItem = orders[position]
// You must set the visibility during the binding
holder.buttonDados.visibility = if (isVisibleMap[position]) {
View.VISIBLE
} else {
View.GONE
}
holder.nrPedido.text = currentItem.id.toString()
holder.distancia.text = currentItem.distancia.toString()+"km"
holder.estado.text = currentItem.estado
holder.itemView.setOnClickListener {
// Here we update the visibility
isVisibleMap[position] = !isVisibleMap[position]
listener.invoke(currentItem)
}
}
override fun getItemCount(): Int {
return orders.size
}
inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
val nrPedido : TextView = itemView.findViewById(R.id.textViewIDPedido)
val distancia : TextView = itemView.findViewById(R.id.textViewDistancia)
val estado : TextView = itemView.findViewById(R.id.textViewEstado)
val buttonEstado : Button = itemView.findViewById(R.id.buttonEstado)
val buttonAceitarRecusar : Button = itemView.findViewById(R.id.buttonAceitarRecusar)
val buttonDados : Button = itemView.findViewById(R.id.buttonDados)
}
}
Keep in mind that things like this, changing the visibility of an item from the adapter, should be handled within the adapter itself. Hope it helps!
Edit: If you want to change the button visibility programmatically from outside the Adapter, you can always do something like:
class Adapter ... {
fun changeButtonVisibility(isVisible: Boolean, pos: Int) {
isVisibleMap[pos] = isVisible
notifyItemChanged(pos)
}
}

How to show only 2 items in RecyclerView?

There is a list of operations that I display in the recyclerview through the ListAdapter. The size of the RecyclerView is 2 elements.enter image description here
ListAdapter:
class OperationAdapter(private val onItemClicked: (Operation) -> Unit) :
ListAdapter<Operation, OperationAdapter.OperationViewHolder>(DiffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OperationViewHolder {
val viewHolder = OperationViewHolder(
OperationItemBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
return viewHolder
}
#SuppressLint("ResourceAsColor", "SetTextI18n")
override fun onBindViewHolder(holder: OperationViewHolder, position: Int) {
holder.bind(getItem(position))
}
class OperationViewHolder(private var binding: OperationItemBinding): RecyclerView.ViewHolder(binding.root) {
/*val imageOperation:ImageView = view.findViewById(R.id.imageViewItem)
val nameOperation:TextView = view.findViewById(R.id.name_operation)
val balanceOperation:TextView = view.findViewById(R.id.textSum)*/
fun bind(operation: Operation){
if(operation.receive == ACCOUNT.number){
binding.imageViewItem.setImageResource(R.drawable.ic_type_recieve)
binding.nameOperation.text = operation.send
binding.nameOperation.setTextColor(Color.rgb(35, 135, 0))
val sum = NumberFormat.getCurrencyInstance(Locale("en", "US")).format(operation.sum)
binding.textSum.text = sum
binding.textSum.setTextColor(Color.rgb(35, 135, 0))
}else{
binding.imageViewItem.setImageResource(R.drawable.ic_type_sent)
binding.nameOperation.text = operation.receive
binding.nameOperation.setTextColor(Color.rgb(231, 223,255))
val sum = NumberFormat.getCurrencyInstance(Locale("en", "US")).format(operation.sum)
binding.textSum.text = "-$sum"
binding.textSum.setTextColor(Color.rgb(231, 223,255))
}
}
}
companion object{
private val DiffCallback = object: DiffUtil.ItemCallback<Operation>(){
override fun areItemsTheSame(oldItem: Operation, newItem: Operation): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Operation, newItem: Operation): Boolean {
return oldItem == newItem
}
}
}
}
I retrieve list from Room by courotine:
GlobalScope.launch(Dispatchers.IO){
sharedViewModel.getOperationsAll(ACCOUNT.number).collect(){ it ->
operationAdapter.submitList(it.sortedByDescending { it.time })
}
}
I cannot output recycler view with only two items, where user can scroll it.
You must not use GlobalScope for this, because it will leak your Activity and/or Fragment for the entire lifetime of your app. Every time the screen changes, it'll leak another copy of it until your app runs out of memory.
Dispatchers.IO is unnecessary. You are not calling any blocking functions in this coroutine.
To limit to two items, you can use take(2) on the list before you pass it to the adapter:
lifecycleScope.launch {
sharedViewModel.getOperationsAll(ACCOUNT.number).collect { opList ->
operationAdapter.submitList(opList.sortedByDescending { it.time }.take(2))
}
}
If this is a Fragment, you should use viewLifecycleOwner.lifecycleScope instead.

ProgressBar not updating in RecyclerView item row

I'm uploading some photos to my server, and want to view the progress of individual uploads. However, my RecyclerView isn't updating.
I know the progress is being updated, as I can see the progress in the my upload task, and the photo is uploaded to the server. I thought the viewholder would be what I would use to update the view, but my progress listener isn't' called.
Does anyone see what I have done wrong? Or could do better?
The PhotoUploadItem is the object that gets updated with the progress.
class PhotoUploadItem(var photoStore: PhotoStore) {
interface PhotoUploadProgressListener {
fun onProgressChanged(progress: Int)
}
private var uploadProgress = 0
private var listener: PhotoUploadProgressListener? = null
fun setUploadProgress(uploadProgress: Int) {
this.uploadProgress = uploadProgress
listener?.onProgressChanged(uploadProgress)
}
fun subscribe(listener: PhotoUploadProgressListener) {
this.listener = listener
}
fun unsubscribe() {
this.listener = null
}
fun progress() = uploadProgress
fun identifier(): Int = photoStore.key
}
The PhotoUploadsAdapter takes a list of them.
class PhotoUploadsAdapter : RecyclerView.Adapter<PhotoUploadsAdapter.CustomViewHolder>() {
inner class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
private val differCallback = object : DiffUtil.ItemCallback<PhotoUploadItem>() {
override fun areItemsTheSame(oldItem: PhotoUploadItem, newItem: PhotoUploadItem) = oldItem.identifier() == newItem.identifier()
override fun areContentsTheSame(oldItem: PhotoUploadItem, newItem: PhotoUploadItem) = oldItem.hashCode() == newItem.hashCode()
}
val differ = AsyncListDiffer(this, differCallback)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
return CustomViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.row_photo_upload, parent, false))
}
override fun getItemCount() = differ.currentList.size
#SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
val item = differ.currentList[position]
holder.itemView.apply {
///..... set other fields
tvDisplayName?.text = item.photoStore.displayName
// THIS DOESN'T WORK
item.subscribe(object : PhotoUploadItem.PhotoUploadProgressListener{
override fun onProgressChanged(progress: Int) {
Log.i("UploadViewHolder", "${item.identifier()} has progress: $progress")
progressBar?.progress = progress
tvProgressAmount?.text = String.format(Locale.ROOT, "%d%%", progress)
}
})
}
}
}

How to notify and update list when item has been deleted using Groupie RecyclerView library and Kotlin

I have a RecyclerView implemented with the Groupie library and I can delete an item from the list fine, however need to update the view to see the change. I'd like to have something like notifyDataSetChanged() instead, so the list updates immediately. I'm a bit confused at this stage though, tried a few different ways to get an interface from the class that hosts my view holder to be triggered from the fragment that holds the adapter but I think I'm stuck now if I could get some help please.
class RecyclerProductItem(
private val activity: MainActivity,
private val product: Product, private val adapterListener: AdapterListener
) : Item<GroupieViewHolder>() {
companion object {
var clickListener: AdapterListener? = null
}
override fun bind(viewHolder: GroupieViewHolder, position: Int) {
viewHolder.apply {
with(viewHolder.itemView) {
clickListener = adapterListener
ivTrash.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
if (clickListener != null) {
Toast.makeText(context, "delete method to be added here", Toast.LENGTH_SHORT).show()
clickListener?.onClickItem(position)
}
}
})
}
}
}
override fun getLayout() = R.layout.recyclerview_item_row
interface AdapterListener {
fun onClickItem(position: Int)
}
}
Here it's my fragment. I tried to add a section to the adapter to see if it would allow me to retrieve a listener for it, but as my listener should be triggered under a specific item within the layout, this may not be the best solution, although couldn't make this work either.
class ProductsListFragment : Fragment(), RecyclerProductItem.AdapterListener {
private lateinit var adapter: GroupAdapter<GroupieViewHolder>
private val section = Section()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_products_list, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val linearLayoutManager = LinearLayoutManager(activity)
recyclerView.layoutManager = linearLayoutManager
adapter = GroupAdapter()
adapter.add(section)
recyclerView.adapter = adapter
loadProducts()
}
private fun loadProducts() {
GetProductsAPI.postData(object : GetProductsAPI.ThisCallback {
override fun onSuccess(productList: List<JsonObject>) {
for (jo in productList) {
val gson = GsonBuilder().setPrettyPrinting().create()
val product: Product =
gson.fromJson(jo, Product::class.java)
adapter.add(
RecyclerProductItem(
activity as MainActivity,
Product(
product.id,
product.title,
product.description,
product.price
),adapterListenerToBePassedHere
)
) // This part is where I should be giving the listener, but get a red line since not sure how to get it to include it here.
}
}
})
}
companion object {
fun newInstance(): ProductsListFragment {
return ProductsListFragment()
}
}
override fun onClickItem(position: Int) {
adapter.notifyItemRemoved(position)
}
}
Many thanks.
I think you are missing this concept from the groupie Readme:
Modifying the contents of the GroupAdapter in any way automatically sends change notifications. Adding an item calls notifyItemAdded(); adding a group calls notifyItemRangeAdded(), etc.
So to remove an item, call section.remove(item). However, in your onClickItem function you currently only pass the position. Pass the item like clickListener?.onClickItem(this#RecyclerProductItem) instead.
Even more ideally and safely you should remove by product.id, e.g. clickListener?.onClickItem(this#RecyclerProductItem.product.id) then in onClickItem() you just search for the item with that product id and remove it. Let me know if I'm not clear.
Based on #carson's reply, this is what worked for me. Had to add the items to the section, the section to the adapter and then remove the item from the section based on the adapter position once that listener is clicked, passing the method that implements the listener as one of the arguments to complete the GroupAdapter.
class RecyclerProductItem(
private val activity: MainActivity,
private val product: Product, private val adapterListener: AdapterListener
) : Item<GroupieViewHolder>() {
companion object {
var clickListener: AdapterListener? = null
}
override fun bind(viewHolder: GroupieViewHolder, position: Int) {
viewHolder.apply {
with(viewHolder.itemView) {
tvTitle.text = product.title
clickListener = adapterListener
ivTrash.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
if (clickListener != null) {
Toast.makeText(context, "delete method to be added here", Toast.LENGTH_SHORT).show()
clickListener?.onClickItem(this#RecyclerProductItem.product.id, adapterPosition)
}
}
})
}
}
}
override fun getLayout() = R.layout.recyclerview_item_row
interface AdapterListener {
fun onClickItem(id: Int, position: Int)
}
}
And
private fun loadProducts() {
GetProductsAPI.postData(object : GetProductsAPI.ThisCallback,
RecyclerProductItem.AdapterListener {
override fun onSuccess(productList: List<JsonObject>) {
Log.i(LOG_TAG, "onSuccess $LOG_TAG")
for (jo in productList) {
val gson = GsonBuilder().setPrettyPrinting().create()
val product: Product =
gson.fromJson(jo, Product::class.java)
val linearLayoutManager = LinearLayoutManager(activity)
recyclerView.layoutManager = linearLayoutManager
adapter = GroupAdapter()
section.add(
RecyclerProductItem(
activity as MainActivity,
Product(
product.id,
product.title,
product.description,
product.price
), this
)
)
adapter.add(section)
recyclerView.adapter = adapter
}
}
override fun onFailure() {
Log.e(LOG_TAG, "onFailure $LOG_TAG")
}
override fun onError() {
Log.e(LOG_TAG, "onError $LOG_TAG")
}
override fun onClickItem(id: Int, position: Int) {
section.remove(adapter.getItem(position))
}
})
}

View pager holds old fragment after rotate screen

i have a view pager, with 4 fragments. (im using FragmentStatePagerAdapter)
Each fragment have a "FrameLayout/ container", where i add and replace many fragments.
Everything works fine, but when i change screen orientation, the first fragment of the line is restored Over actual fragment. Then both appears at same time.
Im putting a picture with a example of what happens:
First Fragment
Second Fragment
[when i rotate screen]
http://i.stack.imgur.com/kxaVn.png
My MainActivity Code
class MainActivity : AppCompatActivity() {
val numPages = 4
var pager: ViewPager? = null
private val TITLES = arrayOf("Feed", "Catalogo","Guia","Rendimento")
var menuImages:Array<ImageView>?=null
var menuTexts:Array<TextView>?=null
var fragments = arrayListOf<Fragment>()
private var fragmentCreated1: FeedContainerFragment? = null
private var fragmentCreated2: CatalogContainerFragment? = null
private var fragmentCreated3: GuideContainerFragment? = null
private var fragmentCreated4: TestContainerFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_default)
fragments.add(FeedContainerFragment())
fragments.add(CatalogContainerFragment())
fragments.add(GuideContainerFragment())
fragments.add(TestContainerFragment())
menuImages= arrayOf(findViewById(R.id.icon_feed) as ImageView,
findViewById(R.id.icon_catalogue) as ImageView,
findViewById(R.id.icon_guide) as ImageView,
findViewById(R.id.icon_form) as ImageView)
menuTexts= arrayOf(findViewById(R.id.text_feed) as TextView,
findViewById(R.id.text_catalogue) as TextView,
findViewById(R.id.text_guide) as TextView,
findViewById(R.id.text_form) as TextView)
menuImages?.get(0)?.setColorFilter(ContextCompat.getColor(baseContext,R.color.colorAccent))
menuTexts?.get(0)?.setTextColor(ContextCompat.getColor(baseContext,R.color.colorAccent))
//view pager
pager = findViewById(R.id.pager) as ViewPager
val pagerAdapter = ScreenSlidePagerAdapter(supportFragmentManager)
pager?.adapter = pagerAdapter
pager?.offscreenPageLimit = 4
pager?.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
pager?.adapter?.notifyDataSetChanged()
repaintMenuDefaultColor()
menuImages?.get(position)?.setColorFilter(ContextCompat.getColor(baseContext,R.color.colorAccent))
menuTexts?.get(position)?.setTextColor(ContextCompat.getColor(baseContext,R.color.colorAccent))
}
override fun onPageScrollStateChanged(state: Int) {
}
})
//Navigation Menus
MenuUtils.generateMaterialMenu(this)
MenuUtils.generateBottomMenu(this, this.pager!!)
}
private inner class ScreenSlidePagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) {
override fun getCount(): Int {
return numPages
}
override fun getItem(position: Int): Fragment {
when(position) {
0->return FeedContainerFragment()
1->return CatalogContainerFragment()
2->return GuideContainerFragment()
3->return TestContainerFragment()
else->return FeedContainerFragment()
}
}
override fun getPageTitle(position: Int): CharSequence {
return TITLES[position]
}
override fun getItemPosition(obj: Any?): Int {
if (obj is Refreshable) {
return POSITION_NONE
}
return super.getItemPosition(obj)
}
override fun instantiateItem(container:ViewGroup, position:Int):Any {
val createdFragment = super.instantiateItem(container, position) as Fragment
when (position) {
0 -> fragmentCreated1 = createdFragment as FeedContainerFragment
1 -> fragmentCreated2 = createdFragment as CatalogContainerFragment
2 -> fragmentCreated3 = createdFragment as GuideContainerFragment
3 -> fragmentCreated4 = createdFragment as TestContainerFragment
}
return createdFragment
}
}
override fun onBackPressed() {
if (fragmentManager.backStackEntryCount > 0) {
fragmentManager.popBackStack()
} else {
super.onBackPressed()
}
}
fun repaintMenuDefaultColor(){
this.menuImages?.map {
it.setColorFilter(ContextCompat.getColor(baseContext,R.color.menu_icon))
}
this.menuTexts?.map {
it.setTextColor(ContextCompat.getColor(baseContext,R.color.menu_text))
}
}
}
Any Help is Welcome !
EDIT: Actually, what is happening is that ViewPager keep the Actual Fragment as a "Ghost" and then restore the First Fragment of the line.
Is there a way to clean the screen and remove that "Ghost" ?
EDIT 2: Found the solution. I needed to verify if a instance of fragment already exists before add the fragment on each "container"
The problem wasn't on ViewPager, or Adapter. Every time i change the orientation a new fragment was included.
So, just put the verification below :
if(savedInstanceState == null) {
activity
.supportFragmentManager
.beginTransaction()
.add(R.id.containerGuide, YourFragment())
.commit()
}
When Rotating Screen the Activity and the Fragments are recreated so its start from position 0..
Save Fragment position when viewpager is rebuild just choose the Fragment you need.
Check out this link https://developer.android.com/guide/topics/resources/runtime-changes.html
Disable screen Rotations.

Categories