我正在努力地通过分组加载自定义项目布局。是特别的-当我使用滑行加载图像(图像约为12kb)时,在项目绑定上。遇到“冻结帧”。探查器显示,在滑行加载图像的那一刻,CPU使用率急剧上升。即使我一次添加3个项目,但它仍然滞后,但是我需要添加更多(3个和48个项目之间的cpu使用率没有太大差异,因此冻结大约相同的时间)。通过从资源/预缓存/直接下载加载该文件进行了测试,无论是否带有RequestOptions()-一切都相同
与该问题有关的一些代码:
HomeScreen.kt
var subscription = 0
//Transformation
var loading = false
var itemWidth = 120
class HomeScreen : AppCompatActivity() {
val categoriesReference = FirebaseDatabase.getInstance().getReference("/categories")
var photos = ArrayList<PhotoItem>()
val adapter = GroupAdapter<ViewHolder>()
var itemsAllowed = 48
lateinit var manager: GridLayoutManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home_screen)
itemWidth = getItemWidth(this@HomeScreen)
setSupportActionBar(toolbar)
window.exitTransition = null
//Action bar options
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.title = "Все обои"
//FIX BLINKING ON TRANSITIONS
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
/*var fade = Fade()
fade.excludeTarget(toolbar, true)
fade.excludeTarget(toolbar2, true)
fade.excludeTarget(android.R.id.statusBarBackground, true);
fade.excludeTarget(android.R.id.navigationBarBackground, true);
getWindow().setEnterTransition(fade)
getWindow().setExitTransition(fade)*/
}
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_FULLSCREEN)
//Working with layout
manager = GridLayoutManager(this, calculateNoOfColumns(this@HomeScreen))
adapter.setHasStableIds(true)
recycleView.isNestedScrollingEnabled = false
recycleView.adapter = adapter
recycleView.layoutManager = manager
loadPageFully()
addItemsToMenu()
//Listener for navigation view
navigView.setNavigationItemSelectedListener {
/*if (it.toString() == "Купить тариф") {
subscription = 1
alert("Тариф успешно установлен") {
navigView.menu.clear()
addItemsToMenu()
loadPageFully()
yesButton { }
supportActionBar?.title = "Все обои"
}.show()
true
} else {*/
when(it.title.toString()){
"Все обои" -> {
loadPageFully()
}
}
drawerLayoutMain.closeDrawer(GravityCompat.START, true)
for (i in 0 until navigView.menu.size()) {
navigView.menu.getItem(i).setChecked(false)
}
it.setChecked(true)
loadPageFully(it.toString())
loadingImageView.visibility = View.GONE
waveImageView.visibility = View.GONE
supportActionBar?.title = it.toString()
true
// }
}
//Shuffle images in layout manager
shuffleButton.onClick {
photos.shuffle()
adapter.clear()
photos.forEach {
if (manager.itemCount < itemsAllowed) {
adapter.add(it)
}
}
}
scrollView3.setOnScrollChangeListener(object : View.OnScrollChangeListener {
override fun onScrollChange(v: View?, scrollX: Int, scrollY: Int, oldScrollX: Int, oldScrollY: Int) {
println(loading.toString())
if (!loading && !scrollView3.canScrollVertically(1) && manager.itemCount > 0) {
loading = true
if (itemsAllowed == photos.size) {
} else if (itemsAllowed + 48 >= photos.size) {
for (i in 48.downTo(0)) {
if (itemsAllowed + i == photos.size) {
itemsAllowed += i
waveImageView.visibility = View.VISIBLE
doAsync {
Thread.sleep(300)
scrollView3.fullScroll(View.FOCUS_DOWN)
}
}
}
} else {
waveImageView.visibility = View.VISIBLE
doAsync {
Thread.sleep(300)
scrollView3.fullScroll(View.FOCUS_DOWN)
}
itemsAllowed += 48
}
checkOk()
}
}
})
recycleView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
when (newState) {
SCROLL_STATE_IDLE -> Glide.with(this@HomeScreen).resumeRequests()
SCROLL_STATE_TOUCH_SCROLL, SCROLL_STATE_FLING -> Glide.with(this@HomeScreen).pauseRequests()
}
}
})
}
//On home button clicked
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
drawerLayoutMain.openDrawer(GravityCompat.START)
true
}
else -> super.onOptionsItemSelected(item)
}
}
fun getEntries(categoryName: String = "All") {
//This fun with ChildEventListeners(Firebase SDK) gets urls and pushes them to photos no problem here because by the time lags occur they all are in photos.
}
var okToLoad = false
var loaded = 0
fun loadImages() {
if (okToLoad) {
okToLoad = false
if (photos.size < itemsAllowed) {
itemsAllowed = photos.size
}
loading = true
try {
for (i in manager.findLastVisibleItemPosition() + 1 until itemsAllowed) {
Glide.with(this@HomeScreen).load(photos[i].url).apply(
RequestOptions().diskCacheStrategy(
DiskCacheStrategy.ALL
)/*.skipMemoryCache(true)*/
).apply(RequestOptions().dontTransform()/*.override(220, 330)*/)
.listener(object : RequestListener<Drawable> {
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: com.bumptech.glide.request.target.Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
loaded += 1
println("1:$loaded")
println("2:$itemsAllowed")
if (loaded == itemsAllowed) {
Timer().schedule(object : TimerTask() {
override fun run() {
runOnUiThread {
waveImageView.visibility = View.GONE
shuffleButton.visibility = View.VISIBLE
okToLoad = true
loading = false
loadingImageView.visibility = View.GONE
for (i in manager.findLastVisibleItemPosition() + 1 until loaded) {
adapter.add(photos[i])
}
}
}
}, 1000)
}
return false
}
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: com.bumptech.glide.request.target.Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
return false
}
}).preload(220, 330)
}
} catch (e: IndexOutOfBoundsException) {
} catch (e: FileNotFoundException) {
Toast.makeText(this@HomeScreen, "Квота превышена", Toast.LENGTH_LONG).show()
}
}
}
fun checkOk() {
doAsync {
if (photos.size == 0) {
okToLoad = false
Thread.sleep(100)
checkOk()
} else {
okToLoad = true
uiThread {
loadImages()
}
}
}
}
fun addItemsToMenu() {
categoriesReference.addChildEventListener(object : ChildEventListener {
override fun onChildAdded(p0: DataSnapshot, p1: String?) {
navigView.menu.add(p0.key.toString()).setIcon(R.drawable.ic_bookmark_black_24dp)
}
override fun onCancelled(p0: DatabaseError) = Unit
override fun onChildChanged(p0: DataSnapshot, p1: String?) = Unit
override fun onChildMoved(p0: DataSnapshot, p1: String?) = Unit
override fun onChildRemoved(p0: DataSnapshot) = Unit
})
}
fun loadPageFully(key: String = "All") {
shuffleButton.visibility = View.GONE
loaded = 0
okToLoad = false
loadingImageView.visibility = View.VISIBLE
doAsync {
Glide.get(this@HomeScreen).clearDiskCache()
}
Glide.get(this@HomeScreen).clearMemory()
manager.removeAndRecycleAllViews(recycleView.Recycler())
adapter.clear()
photos.clear()
getEntries(key)
checkOk()
}
fun calculateNoOfColumns(context: Context): Int {
val displayMetrics = context.getResources().getDisplayMetrics();
val dpWidth = displayMetrics.widthPixels / displayMetrics.density;
val scalingFactor = 110 // You can vary the value held by the scalingFactor
// variable. The smaller it is the more no. of columns you can display, and the
// larger the value the less no. of columns will be calculated. It is the scaling
// factor to tweak to your needs.
var columnCount = (dpWidth / scalingFactor).toInt()
if (columnCount < 3) columnCount = 3
return columnCount // if column no. is less than 2, we still display 2 columns
}
fun getItemWidth(context: Context): Int {
val displayMetrics = context.resources.displayMetrics
val dpWidth = displayMetrics.widthPixels
return (dpWidth / calculateNoOfColumns(context)).toInt()
}
}
val factory = DrawableCrossFadeFactory.Builder().setCrossFadeEnabled(true).build()
//Layout item for adapter
class PhotoItem(
val cnt: Context,
var url: String,
var downloads: Int,
var ref: DatabaseReference,
var locked: Boolean
) : Item<ViewHolder>() {
override fun bind(viewHolder: ViewHolder, position: Int) {
viewHolder.itemView.itemImageView.layoutParams.width = itemWidth
viewHolder.itemView.itemImageView.layoutParams.height = itemWidth
Glide.with(cnt)
.load(url)
.apply(RequestOptions().placeholder(R.drawable.placeholder).format(DecodeFormat.PREFER_RGB_565))/*transition(DrawableTransitionOptions.withCrossFade(factory)).apply(RequestOptions().placeholder(R.drawable.background))*//**//*.skipMemoryCache(true)*//**//*priority(Priority.HIGH))*//**//*.listener(
object : RequestListener<Bitmap> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: com.bumptech.glide.request.target.Target<Bitmap>?,
isFirstResource: Boolean
): Boolean {
return false
}
override fun onResourceReady(
resource: Bitmap?,
model: Any?,
target: Target<Bitmap>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
return false
}
})*/.into(viewHolder.itemView.itemImageView)
viewHolder.itemView.itemImageView.transitionName = url
viewHolder.itemView.setOnClickListener {
var intent = Intent(cnt, PhotoScreen::class.java).apply {
putExtra("url", url)
putExtra("ref", ref.toString())
putExtra("downs", downloads.toString())
putExtra("locked", locked.toString())
}
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
cnt as AppCompatActivity,
viewHolder.itemView.itemImageView,
viewHolder.itemView.itemImageView.transitionName
)
cnt.startActivity(intent, options.toBundle())
}
}
override fun getLayout(): Int {
return R.layout.image_item
}
首页
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawerLayoutMain"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HomeScreen"
android:background="@drawable/background">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent" android:id="@+id/relativeLayout"
>
<androidx.core.widget.NestedScrollView
android:layout_width="0dp"
android:layout_height="0dp"
tools:layout_conversion_absoluteHeight="598dp"
tools:layout_conversion_absoluteWidth="384dp" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/toolbar"
android:id="@+id/scrollView3"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintBottom_toBottomOf="parent"
android:overScrollMode="ifContentScrolls"
android:fillViewport="false">
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:id="@+id/linearLayout"
android:descendantFocusability="blocksDescendants"
android:layout_marginLeft="0dp" android:layout_marginRight="0dp"
android:layout_gravity="fill">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="-100dp"
android:layout_marginTop="0dp" android:id="@+id/recycleView"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_marginRight="0dp"
android:focusableInTouchMode="true"
android:scrollbars="vertical"
android:layout_gravity="center_horizontal|fill"
>
</androidx.recyclerview.widget.RecyclerView>
<pl.droidsonroids.gif.GifImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/waveImageView" android:src="@drawable/intro_image"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:visibility="gone" android:background="@drawable/background"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="0dp"
android:layout_height="45dp"
android:background="@drawable/background"
app:titleTextColor="@android:color/white"
android:textAlignment="gravity"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:isScrollContainer="false"
android:fitsSystemWindows="false"
tools:layout_conversion_absoluteHeight="42dp"
tools:layout_conversion_absoluteWidth="384dp"
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="@drawable/ic_list_black_24dp">
</androidx.appcompat.widget.Toolbar>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content" app:srcCompat="@drawable/ic_shuffle_black_24dp"
android:id="@+id/shuffleButton"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="@+id/toolbar"
android:padding="10dp"
app:layout_constraintBottom_toTopOf="@+id/scrollView3"
android:focusedByDefault="true"
/>
<pl.droidsonroids.gif.GifImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/loadingImageView" android:visibility="visible"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp" app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp" android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent" android:layout_marginTop="8dp"
app:layout_constraintTop_toTopOf="parent" android:src="@drawable/placeholder_gif"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.navigation.NavigationView
android:layout_width="250dp"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/header_menu"
android:theme="@style/ThemeOverlay.AppCompat.ActionBar" android:id="@+id/navigView"
app:itemBackground="@drawable/menu_item_background"
android:background="@drawable/menu_bitmap"/>
</androidx.drawerlayout.widget.DrawerLayout>
ImageItem布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ImageView
android:layout_width="110dp"
android:layout_height="110dp"
android:id="@+id/itemImageView"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent"
android:scaleType="centerCrop"/>
</FrameLayout>
如我所见,OnMeasure()和nativePollOnce()方法需要很多时间。还是不知道该怎么办
答案 0 :(得分:0)
已解决
主要问题是 groupie适配器,目前在UI线程上产生差异。这造成了滞后。切换到另一个库可能会对您有所帮助。我已切换为 airbnb的环氧
P.S。我在滚动视图中嵌套了recyclerview。删除scrollview可以提高性能