Android 带有2个recyclerview内存泄漏的Viewpager2
我有一个带有2个recyclerview的viewpager (尝试在Instagram用户配置文件中实现post节) 问题是我的内存一直在泄漏。当我阅读leakCanary日志时,它说内存泄漏的原因是viewpager。这是泄漏的金丝雀片段Android 带有2个recyclerview内存泄漏的Viewpager2,android,android-recyclerview,memory-leaks,android-viewpager2,leakcanary,Android,Android Recyclerview,Memory Leaks,Android Viewpager2,Leakcanary,我有一个带有2个recyclerview的viewpager (尝试在Instagram用户配置文件中实现post节) 问题是我的内存一直在泄漏。当我阅读leakCanary日志时,它说内存泄漏的原因是viewpager。这是泄漏的金丝雀片段 2020-05-13 17:57:32.914 D/LeakCanary: ┬─── 2020-05-13 17:57:32.914 D/LeakCanary: │ GC Root: Local variable in native code 2020-0
2020-05-13 17:57:32.914 D/LeakCanary: ┬───
2020-05-13 17:57:32.914 D/LeakCanary: │ GC Root: Local variable in native code
2020-05-13 17:57:32.914 D/LeakCanary: │
2020-05-13 17:57:32.914 D/LeakCanary: ├─ android.net.ConnectivityThread instance
2020-05-13 17:57:32.914 D/LeakCanary: │ Leaking: NO (PathClassLoader↓ is not leaking)
2020-05-13 17:57:32.914 D/LeakCanary: │ Thread name: 'ConnectivityThread'
2020-05-13 17:57:32.914 D/LeakCanary: │ ↓ ConnectivityThread.contextClassLoader
2020-05-13 17:57:32.914 D/LeakCanary: ├─ dalvik.system.PathClassLoader instance
2020-05-13 17:57:32.914 D/LeakCanary: │ Leaking: NO (ViewDataBinding↓ is not leaking and A ClassLoader is never leaking)
2020-05-13 17:57:32.914 D/LeakCanary: │ ↓ PathClassLoader.runtimeInternalObjects
2020-05-13 17:57:32.914 D/LeakCanary: ├─ java.lang.Object[] array
2020-05-13 17:57:32.914 D/LeakCanary: │ Leaking: NO (ViewDataBinding↓ is not leaking)
2020-05-13 17:57:32.914 D/LeakCanary: │ ↓ Object[].[349]
2020-05-13 17:57:32.914 D/LeakCanary: ├─ androidx.databinding.ViewDataBinding class
2020-05-13 17:57:32.914 D/LeakCanary: │ Leaking: NO (RouteInfoFragment↓ is not leaking and a class is never leaking)
2020-05-13 17:57:32.914 D/LeakCanary: │ ↓ static ViewDataBinding.sReferenceQueue
2020-05-13 17:57:32.914 D/LeakCanary: ├─ java.lang.ref.ReferenceQueue instance
2020-05-13 17:57:32.914 D/LeakCanary: │ Leaking: NO (RouteInfoFragment↓ is not leaking)
2020-05-13 17:57:32.914 D/LeakCanary: │ ↓ ReferenceQueue.head
2020-05-13 17:57:32.914 D/LeakCanary: ├─ androidx.databinding.ViewDataBinding$WeakListener instance
2020-05-13 17:57:32.914 D/LeakCanary: │ Leaking: NO (RouteInfoFragment↓ is not leaking)
2020-05-13 17:57:32.914 D/LeakCanary: │ ↓ ViewDataBinding$WeakListener.mObservable
2020-05-13 17:57:32.914 D/LeakCanary: ├─ androidx.databinding.ViewDataBinding$LiveDataListener instance
2020-05-13 17:57:32.914 D/LeakCanary: │ Leaking: NO (RouteInfoFragment↓ is not leaking)
2020-05-13 17:57:32.914 D/LeakCanary: │ ↓ ViewDataBinding$LiveDataListener.mLifecycleOwner
2020-05-13 17:57:32.914 D/LeakCanary: ├─ iclaude.berlinwanderer.features.route.ui.route_dashboard.route_info.RouteInfoFragment instance
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: NO (RouteDashboardFragment↓ is not leaking and Fragment#mFragmentManager is not null)
2020-05-13 17:57:32.915 D/LeakCanary: │ Fragment.mTag=f0
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ RouteInfoFragment.mParentFragment
2020-05-13 17:57:32.915 D/LeakCanary: ├─ iclaude.berlinwanderer.features.route.ui.route_dashboard.RouteDashboardFragment instance
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: NO (Fragment#mFragmentManager is not null)
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ RouteDashboardFragment.mLifecycleRegistry
2020-05-13 17:57:32.915 D/LeakCanary: │ ~~~~~~~~~~~~~~~~~~
2020-05-13 17:57:32.915 D/LeakCanary: ├─ androidx.lifecycle.LifecycleRegistry instance
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ LifecycleRegistry.mObserverMap
2020-05-13 17:57:32.915 D/LeakCanary: │ ~~~~~~~~~~~~
2020-05-13 17:57:32.915 D/LeakCanary: ├─ androidx.arch.core.internal.FastSafeIterableMap instance
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ FastSafeIterableMap.mHashMap
2020-05-13 17:57:32.915 D/LeakCanary: │ ~~~~~~~~
2020-05-13 17:57:32.915 D/LeakCanary: ├─ java.util.HashMap instance
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ HashMap.table
2020-05-13 17:57:32.915 D/LeakCanary: │ ~~~~~
2020-05-13 17:57:32.915 D/LeakCanary: ├─ java.util.HashMap$Node[] array
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ HashMap$Node[].[1]
2020-05-13 17:57:32.915 D/LeakCanary: │ ~~~
2020-05-13 17:57:32.915 D/LeakCanary: ├─ java.util.HashMap$Node instance
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ HashMap$Node.key
2020-05-13 17:57:32.915 D/LeakCanary: │ ~~~
2020-05-13 17:57:32.915 D/LeakCanary: ├─ androidx.viewpager2.adapter.FragmentStateAdapter$5 instance
2020-05-13 17:57:32.915 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.915 D/LeakCanary: │ Anonymous class implementing androidx.lifecycle.LifecycleEventObserver
2020-05-13 17:57:32.915 D/LeakCanary: │ ↓ FragmentStateAdapter$5.this$0
2020-05-13 17:57:32.916 D/LeakCanary: │ ~~~~~~
2020-05-13 17:57:32.916 D/LeakCanary: ├─ iclaude.berlinwanderer.features.route.ui.route_dashboard.RouteDashboardViewPagerAdapter instance
2020-05-13 17:57:32.916 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.916 D/LeakCanary: │ ↓ RouteDashboardViewPagerAdapter.mObservable
2020-05-13 17:57:32.916 D/LeakCanary: │ ~~~~~~~~~~~
2020-05-13 17:57:32.916 D/LeakCanary: ├─ androidx.recyclerview.widget.RecyclerView$AdapterDataObservable instance
2020-05-13 17:57:32.916 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.916 D/LeakCanary: │ ↓ RecyclerView$AdapterDataObservable.mObservers
2020-05-13 17:57:32.916 D/LeakCanary: │ ~~~~~~~~~~
2020-05-13 17:57:32.916 D/LeakCanary: ├─ java.util.ArrayList instance
2020-05-13 17:57:32.916 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.916 D/LeakCanary: │ ↓ ArrayList.elementData
2020-05-13 17:57:32.916 D/LeakCanary: │ ~~~~~~~~~~~
2020-05-13 17:57:32.916 D/LeakCanary: ├─ java.lang.Object[] array
2020-05-13 17:57:32.916 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.916 D/LeakCanary: │ ↓ Object[].[0]
2020-05-13 17:57:32.916 D/LeakCanary: │ ~~~
2020-05-13 17:57:32.916 D/LeakCanary: ├─ com.google.android.material.tabs.TabLayoutMediator$PagerAdapterObserver instance
2020-05-13 17:57:32.916 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.916 D/LeakCanary: │ ↓ TabLayoutMediator$PagerAdapterObserver.this$0
2020-05-13 17:57:32.916 D/LeakCanary: │ ~~~~~~
2020-05-13 17:57:32.916 D/LeakCanary: ├─ com.google.android.material.tabs.TabLayoutMediator instance
2020-05-13 17:57:32.916 D/LeakCanary: │ Leaking: UNKNOWN
2020-05-13 17:57:32.916 D/LeakCanary: │ ↓ TabLayoutMediator.tabLayout
2020-05-13 17:57:32.916 D/LeakCanary: │ ~~~~~~~~~
2020-05-13 17:57:32.916 D/LeakCanary: ├─ com.google.android.material.tabs.TabLayout instance
2020-05-13 17:57:32.916 D/LeakCanary: │ Leaking: YES (View detached and has parent)
2020-05-13 17:57:32.916 D/LeakCanary: │ mContext instance of iclaude.berlinwanderer.features.route.ui.RouteActivity with mDestroyed = false
2020-05-13 17:57:32.916 D/LeakCanary: │ View#mParent is set
2020-05-13 17:57:32.916 D/LeakCanary: │ View#mAttachInfo is null (view detached)
2020-05-13 17:57:32.916 D/LeakCanary: │ View.mID = R.id.tab_layout
2020-05-13 17:57:32.916 D/LeakCanary: │ View.mWindowAttachCount = 1
2020-05-13 17:57:32.916 D/LeakCanary: │ ↓ TabLayout.mParent
2020-05-13 17:57:32.916 D/LeakCanary: ╰→ androidx.constraintlayout.motion.widget.MotionLayout instance
2020-05-13 17:57:32.916 D/LeakCanary: Leaking: YES (ObjectWatcher was watching this because iclaude.berlinwanderer.features.route.ui.route_dashboard.RouteDashboardFragment received Fragment#onDestroyView() callback (references to its views should be cleared to prevent leaks))
2020-05-13 17:57:32.916 D/LeakCanary: key = 9c28ffc6-b1ce-4316-b015-c4df278892a1
2020-05-13 17:57:32.916 D/LeakCanary: watchDurationMillis = 36154
2020-05-13 17:57:32.916 D/LeakCanary: retainedDurationMillis = 31130
2020-05-13 17:57:32.916 D/LeakCanary: mContext instance of iclaude.berlinwanderer.features.route.ui.RouteActivity with mDestroyed = false
2020-05-13 17:57:32.917 D/LeakCanary: View#mParent is null
2020-05-13 17:57:32.917 D/LeakCanary: View#mAttachInfo is null (view detached)
2020-05-13 17:57:32.917 D/LeakCanary: View.mID = R.id.ml_main
2020-05-13 17:57:32.917 D/LeakCanary: View.mWindowAttachCount = 1
这是我的密码
轮廓片段
这是使用viewpager的片段
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestManager
import com.bumptech.glide.request.RequestOptions
import com.fdev.instagramclone.R
import com.fdev.instagramclone.business.domain.model.User
import com.fdev.instagramclone.databinding.FragmentProfileBinding
import com.fdev.instagramclone.framework.datasource.network.implementation.UserFirestoreServiceImpl
import com.fdev.instagramclone.framework.presentation.main.BaseMainFragment
import com.fdev.instagramclone.util.printLogD
import com.google.android.material.tabs.TabLayoutMediator
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
@FlowPreview
@ExperimentalCoroutinesApi
@AndroidEntryPoint
class ProfileFragment : BaseMainFragment(R.layout.fragment_profile), PhotoGridAdapter.Interaction, PostViewPagerAdapter.Interaction {
companion object {
const val PAGE_NUMBER = 2
}
private var _binding: FragmentProfileBinding? = null
private val binding
get() = _binding!!
private val viewModel: ProfileViewModel by viewModels()
private var _postViewPagerAdapter: PostViewPagerAdapter? = null
private val postViewPagerAdapter
get() = _postViewPagerAdapter!!
private val tabDrawable = listOf(R.drawable.ic_baseline_grid_on_24, R.drawable.ic_baseline_account_box_24)
private var requestManager: RequestManager? = null
lateinit var tabLayoutMediator: TabLayoutMediator
private var images1 = listOf(
"https://www.worldwomanfoundation.com/wp-content/uploads/2018/09/Jeannette_Ceja-_Head_Shot_2018_0-770x330.jpg",
"https://womensagenda.com.au/wp-content/uploads/2020/05/Sarah-Hill-002-1024x683.jpeg",
"https://news.harvard.edu/wp-content/uploads/2020/06/Durba_Mitra-copy_2500-1200x800.jpg",
"https://images.idgesg.net/images/article/2020/01/women-in-it_daphne-jones-100828118-large.jpg",
"https://vtnews.vt.edu/content/vtnews_vt_edu/en/articles/2020/04/science-women-in-data-science-online/_jcr_content/article-image.transform/m-medium/image.jpg",
)
private var images2 = listOf(
"https://koreanindo.net/wp-content/uploads/2019/02/everglow-wang-yiren.jpg",
"https://kepoper.com/wp-content/uploads/2019/10/Mina-Twice-Wiki-1-758x620.jpg",
"https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQT1uidd0fswlshWotS43XDLyscw6ZtFw-E3Q&usqp=CAU",
"https://cdn.idntimes.com/content-images/community/2020/04/20200417-142524-373be8fe5157e9ca9a24a8951ab21dda.jpg",
"https://i.redd.it/21csbponb0551.jpg",
"https://i.pinimg.com/originals/24/5d/87/245d87d800391ff353c04aed8eb52a50.jpg",
"https://womensagenda.com.au/wp-content/uploads/2020/05/Sarah-Hill-002-1024x683.jpeg",
"https://news.harvard.edu/wp-content/uploads/2020/06/Durba_Mitra-copy_2500-1200x800.jpg",
"https://images.idgesg.net/images/article/2020/01/women-in-it_daphne-jones-100828118-large.jpg"
)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = FragmentProfileBinding.inflate(inflater, container, false)
val view = binding.root
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initObserver()
initUI(view)
postViewPagerAdapter.addItemToPost(images2)
postViewPagerAdapter.addItemToTagged(images1)
}
private fun initUI(view: View) {
initViewPager(view)
}
private fun initViewPager(view: View) {
setupGlide()
_postViewPagerAdapter = PostViewPagerAdapter(requestManager as RequestManager, this, this)
binding.contentViewpager.adapter = postViewPagerAdapter
tabLayoutMediator = TabLayoutMediator(binding.contentTabLayout, binding.contentViewpager) { tab, position ->
tab.setIcon(tabDrawable[position])
}
tabLayoutMediator.attach()
}
private fun initObserver() {
viewModel.sessionManager.currentUser.observe(viewLifecycleOwner, { user ->
user?.let {
setUI(it)
}
})
}
private fun setUI(user: User) {
binding.apply {
usernameTv.text = user.username
followersTv.text = user.followers.size.toString()
followingTv.text = user.following.size.toString()
bioTv.text = user.bio
fullnameTv.text = user.name
if (!user.profileImage.equals(UserFirestoreServiceImpl.USER_DEFAULT_PICTURE_URL)) {
(requestManager as RequestManager)
.load(user.profileImage)
.into(profileCircleimageview)
}
}
}
private fun setupGlide() {
val requestOptions = RequestOptions
.placeholderOf(R.drawable.default_image)
.error(R.drawable.ic_baseline_error_outline_24)
activity?.let {
requestManager = Glide.with(it)
.applyDefaultRequestOptions(requestOptions)
}
}
override fun onItemSelected(position: Int, item: String, type: AdapterType) {
when (type) {
AdapterType.Post -> {
Toast.makeText(context, "Post $position", Toast.LENGTH_SHORT).show()
}
AdapterType.Tagged -> {
Toast.makeText(context, "Tagged $position", Toast.LENGTH_SHORT).show()
}
}
}
override fun onNextPage(type: Int) {
}
override fun onPause() {
super.onPause()
binding.swipeRefreshLayout.isEnabled = false
}
override fun afterScrolled(isFirstItem: Boolean) {
binding.swipeRefreshLayout.isEnabled = isFirstItem
}
override fun onDestroyView() {
super.onDestroyView()
tabLayoutMediator.detach()
// binding.contentViewpager.adapter = null
requestManager = null
_binding = null
}
}
视页雷达
导入android.content.Context
导入android.view.LayoutInflater
导入android.view.view
导入android.view.ViewGroup
导入androidx.recyclerview.widget*
导入com.bumptech.glide.RequestManager
import com.fdev.instagramclone.R
导入com.fdev.instagramclone.databinding.ViewpagerPostItemBinding
导入com.fdev.instagramclone.util.printLogD
导入kotlinx.android.synthetic.main.viewpager\u post\u item.view*
类PostViewPagerAdapter(
var requestManager:requestManager,
交互:PhotoGridAdapter。交互,
var onNextPageInteraction:交互
) :
RecyclerView.Adapter(){
伴星{
const val POST=1
常量值=2
}
私有变量adapterList=ArrayList()
专用var后适配器:PhotoGridAdapter
私有变量taggedAdapter:PhotoGridAdapter
初始化{
postAdapter=PhotoGridAdapter(
请求管理器,
相互作用
AdapterType.Post
)
taggedAdapter=PhotoGridAdapter(
请求管理器,
相互作用
AdapterType.taged
)
adapterList.add(后适配器)
adapterList.add(taggedAdapter)
}
override fun onCreateViewHolder(父级:ViewGroup,viewType:Int):RecyclerView.ViewHolder{
//val binding=VIEWPAGERPOTITEMBINDING.FLATE(
//LayoutFlater.from(父上下文),
//家长,假
// )
val view=LayoutInflater.from(parent.context).充气(
R.layout.viewpager\u post\u项,
父母亲
假的
)
返回ViewPagerAdapterViewHolder(视图,onNextPageInteraction)
}
覆盖onBindViewHolder(holder:RecyclerView.ViewHolder,位置:Int){
何时(持有人){
是ViewPagerAdapterViewHolder->{
固定器绑定(适配器列表[位置])
}
}
}
重写getItemCount():Int{
返回适配器列表.size
}
趣味addItemToTagged(列表:列表){
taggedAdapter.com(
请求管理器,
列表
)
taggedAdapter.submitList(列表)
}
趣味addItemToPost(列表:列表){
后适应。预适应图像(
请求管理器,
列表
)
postAdapter.submitList(列表)
}
类ViewPagerAdapterViewHolder
建造师(
var itemView:View,
互动:互动,
):RecyclerView.ViewHolder(项目视图){
趣味绑定(项目:PhotoGridAdapter)=与(项目视图){
initRecylerView(itemView.post_recylerview,item)
}
private fun initRecylerView(recyclerView:recyclerView,recyclerViewAdapter:PhotoGridAdapter){
回收视图{
val gridLayout=GridLayoutManager(上下文,3)
layoutManager=gridLayout
setHasFixedSize(真)
addOnScrollListener(对象:RecyclerView.OnScrollListener(){
覆盖CrollStateChanged(recyclerView:recyclerView,newState:Int){
super.onScrollStateChanged(recyclerView、newState)
val layoutManager=recyclerView.layoutManager作为LinearLayoutManager
val lastPosition=layoutManager.findLastVisibleItemPosition()
如果(lastPosition==RecycleServiceAdapter.itemCount.减去(1)){
interaction.onNextPage(适配器位置)
}
}
})
addOnScrollListener(对象:RecyclerView.OnScrollListener(){
覆盖已克隆的乐趣(recyclerView:recyclerView,dx:Int,dy:Int){
super.onScrolled(回收视图、dx、dy)
interaction.afterScrolled(gridLayout.findFirstCompletelyVisibleItemPosition()==0)
}
})
适配器=回收服务适配器
}
}
}
界面相互作用{
下一页(类型:Int)
有趣的余弦(isFirstItem:Boolean)
}
}
Recylerview适配器(viewpager的内容)
导入android.content.Context
导入androidx.recyclerview.widget.recyclerview
导入android.view.LayoutInflater
导入android.view.ViewGroup
导入androidx.recyclerview.widget.AsyncListDifferent
导入androidx.recyclerview.widget.DiffUtil
导入com.bumptech.glide.RequestManager
导入com.fdev.instagramclone.databinding.PhotoGridItemContainerBinding
导入com.bumptech.glide.load.resource.drawable.drawable TransitionOptions.withCrossFade
导入com.fdev.instagramclone.util.printLogD
类PhotoGridAdapter(
私有val请求管理器:请求管理器,
私有val交互:交互?=null,
私有值类型:AdapterType
) :
RecyclerView.Adapter(){
val DIFF_CALLBACK=对象:DiffUtil.ItemCallback(){
覆盖乐趣项相同(旧项:字符串,新项:字符串):布尔值{
返回oldItem==newItem
}
覆盖内容相同(旧项:字符串,新项:字符串):布尔值{
返回oldItem==newItem
}
}
private val difference=AsyncListDifference(这是DIFF_回调)
override fun onCreateViewHolder(父级:ViewGroup,viewType:Int):RecyclerView.ViewHolder{
val itemBinding=PhotoGridItemContainerBinding.inflate(
从
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.*
import com.bumptech.glide.RequestManager
import com.fdev.instagramclone.R
import com.fdev.instagramclone.databinding.ViewpagerPostItemBinding
import com.fdev.instagramclone.util.printLogD
import kotlinx.android.synthetic.main.viewpager_post_item.view.*
class PostViewPagerAdapter(
var requestManager: RequestManager,
interaction: PhotoGridAdapter.Interaction,
var onNextPageInteraction: Interaction
) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object{
const val POST = 1
const val TAGGED = 2
}
private var adapterList = ArrayList<PhotoGridAdapter>()
private var postAdapter: PhotoGridAdapter
private var taggedAdapter: PhotoGridAdapter
init {
postAdapter = PhotoGridAdapter(
requestManager,
interaction,
AdapterType.Post
)
taggedAdapter = PhotoGridAdapter(
requestManager,
interaction,
AdapterType.Tagged
)
adapterList.add(postAdapter)
adapterList.add(taggedAdapter)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
// val binding = ViewpagerPostItemBinding.inflate(
// LayoutInflater.from(parent.context),
// parent,false
// )
val view = LayoutInflater.from(parent.context).inflate(
R.layout.viewpager_post_item,
parent,
false
)
return ViewPagerAdapterViewHolder(view , onNextPageInteraction)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is ViewPagerAdapterViewHolder -> {
holder.bind(adapterList[position])
}
}
}
override fun getItemCount(): Int {
return adapterList.size
}
fun addItemToTagged(list : List<String>) {
taggedAdapter.preloadGlideImages(
requestManager,
list
)
taggedAdapter.submitList(list)
}
fun addItemToPost(list : List<String>) {
postAdapter.preloadGlideImages(
requestManager,
list
)
postAdapter.submitList(list)
}
class ViewPagerAdapterViewHolder
constructor(
var itemView : View,
var interaction: Interaction,
) : RecyclerView.ViewHolder(itemView) {
fun bind(item : PhotoGridAdapter) = with(itemView) {
initRecylerView(itemView.post_recylerview , item)
}
private fun initRecylerView(recyclerView: RecyclerView, recyclerViewAdapter : PhotoGridAdapter){
recyclerView.apply{
val gridLayout = GridLayoutManager( context, 3)
layoutManager = gridLayout
setHasFixedSize(true)
addOnScrollListener(object : RecyclerView.OnScrollListener(){
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val lastPosition = layoutManager.findLastVisibleItemPosition()
if(lastPosition == recyclerViewAdapter.itemCount.minus(1)){
interaction.onNextPage(adapterPosition)
}
}
})
addOnScrollListener(object : RecyclerView.OnScrollListener(){
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
interaction.afterScrolled(gridLayout.findFirstCompletelyVisibleItemPosition() == 0)
}
})
adapter = recyclerViewAdapter
}
}
}
interface Interaction {
fun onNextPage(type : Int)
fun afterScrolled(isFirstItem : Boolean)
}
}
import android.content.Context
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
import com.bumptech.glide.RequestManager
import com.fdev.instagramclone.databinding.PhotoGridItemContainerBinding
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade
import com.fdev.instagramclone.util.printLogD
class PhotoGridAdapter(
private val requestManager: RequestManager,
private val interaction: Interaction? = null,
private val type : AdapterType
) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
val DIFF_CALLBACK = object : DiffUtil.ItemCallback<String>() {
override fun areItemsTheSame(oldItem: String, newItem: String): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: String, newItem: String): Boolean {
return oldItem == newItem
}
}
private val differ = AsyncListDiffer(this, DIFF_CALLBACK)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val itemBinding = PhotoGridItemContainerBinding.inflate(
LayoutInflater.from(
parent.context
),parent , false
)
return PhotoGridViewHolder(itemBinding , interaction , requestManager , type)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is PhotoGridViewHolder-> {
holder.bind(differ.currentList.get(position))
}
}
}
override fun getItemCount(): Int {
return differ.currentList.size
}
fun submitList(list: List<String>) {
differ.submitList(list)
}
//To preload the image and cache it
fun preloadGlideImages(
requestManager: RequestManager ,
imagesURL : List<String>
){
for(url in imagesURL){
requestManager
.load(url)
.preload()
}
}
class PhotoGridViewHolder
constructor(
private val photoGridBinding: PhotoGridItemContainerBinding,
private val interaction: Interaction?,
private val requestManager: RequestManager,
private val type : AdapterType
) : RecyclerView.ViewHolder(photoGridBinding.root) {
fun bind(item: String) = with(photoGridBinding) {
postImage.setOnClickListener {
interaction?.onItemSelected(adapterPosition, item , type)
}
requestManager
.load(item)
.transition(withCrossFade())
.into(postImage)
}
}
interface Interaction {
fun onItemSelected(position: Int, item: String, type : AdapterType)
}
}
enum class AdapterType {
Tagged, Post
}