Android RecyclerView的卡顿问题的解决方法
作者:彼岸sakura 发布时间:2023-07-01 20:01:14
RecyclerView为什么会卡
RecyclerView作为v7包的新控件,自从推出就广受Android Developer们欢迎,实际上它已经取代了ListView和GridView两位老前辈的地位。然而不少亲们想必也已经发现了:没有优化过的Recycler性能很poor。上一篇博主使用的item也仅仅是一个图两串字而已,结果一滑动就卡的要命,不能忍!
那么why?回想在用ListView和GridView的adapter时,我们是用一种叫ViewHolder的自定义类(容器)来实现优化的,而RecyclerView的特性之一就是强制你使用它的RecyclerView.ViewHolder。可是,RecyclerView.ViewHolder要比我们写的那个单纯的容器复杂多了(源码里算上注释有大约500行),与RecyclerView.Adapter的联系也是千丝万缕。
按stackoverflow上面比较通俗的解释:RecyclerView.Adapter里面的onCreateViewHolder()方法和onBindViewHolder()方法对时间都非常敏感。类似I/O读写,Bitmap解码一类的耗时操作,最好不要在它们里面进行。
如何解决这个问题
首先当然得优化你的item,合理运用<include>,<merge>,<ViewStub>等标签,使布局层次尽量少——其实ListView和GridView里你也应该这么做,应该当成是一种写UI的习惯。
其次就是灵活使用各种第三方库,去完成各种耗时操作,比如通过Glide或者是Picasso加载图片。优秀的开源库在性能上往往都考虑得很仔细。
最后的问题来了,如果只想写一个小demo,不愿大张旗鼓怎么办?如果即便一般的第三方库也不好解决问题,比如上一篇那个该死的loadIcon()方法返回的是一个Drawable对象,Glide和Picasso都没法直接处理,转码又等于添了个耗时任务,那怎么办?
真正的app管理应用,应该引入UIL或者Picasso一类的加载库进行图标加载
答案就是,想法在你setAdapter之前就把任务给完成。
Demo
哟西,上代码!本文代码完全基于上一篇文,无须删减重构。
主要就是增添了一个实体bean对象,setAdapter()时要传递的数据,全部通过它预先加载到内存里!这样那俩敏感方法里只需要简单的get出来即可。
实体类AppBean.java
package com.example.jin.localapp;
import android.graphics.drawable.Drawable;
/**
* Created by Jin on 2016/11/8.
*/
public class AppBean {
private CharSequence name;
private String packageName;
private Drawable icon;
//这类代码可别逞英雄手动写哦,IDE(Android Studio和Eclipse都有的)里可以直接生成
public CharSequence getName() {
return name;
}
public void setName(CharSequence name) {
this.name = name;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public Drawable getIcon() {
return icon;
}
public void setIcon(Drawable icon) {
this.icon = icon;
}
}
主界面MainActivity.java
private List<AppBean> mList;//mList的泛型换成AppBean
private void initData() {//然后只需要改这个方法
mList = new ArrayList<>();
manager = getPackageManager();
List<PackageInfo> list = manager.getInstalledPackages(0);//获取已安装的全部应用
for (PackageInfo info : list) {
if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
AppBean bean = new AppBean();
bean.setName(info.applicationInfo.loadLabel(manager));
bean.setPackageName(info.packageName);
bean.setIcon(info.applicationInfo.loadIcon(manager));
mList.add(bean);
}
}
//拿到数据再setAdapter
mainRcv.setLayoutManager(new LinearLayoutManager(this));
mainRcv.setHasFixedSize(true);
mainRcv.setAdapter(new AppAdapter(this, mList));
}
适配器AppAdapter.java
private List<AppBean> appList;
//同样这边的类型换过来
public AppAdapter(Context context, List<AppBean> appList) {
this.context = context;
this.appList = appList;
inflater = LayoutInflater.from(context);
manager = context.getPackageManager();
}
//然后也只需要改这个方法
@Override
public void onBindViewHolder(AppHolder holder, final int position) {
final AppBean bean = appList.get(position);
holder.itemIconIv.setImageDrawable(bean.getIcon());//图标
holder.itemNameTv.setText(bean.getName());//名称
holder.itemPackageTv.setText(bean.getPackageName());//包名
holder.view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(manager.getLaunchIntentForPackage(bean.getPackageName()));//根据包名启动此应用
context.startActivity(intent);
}
});
}
搞定!因为博主是用手机直接录像再转gif,为了使点击看上去有效果,于是给item增添了一个背景层,这需求实战中也是很常见的哦~~
色彩资源文件colors.xml
这个粉红色其实很难看,单纯当区别用。。。。。。
实战开发如果没有美工,一定要仔细斟酌选取,尽量让自己审美好点!
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="colorWhite">#ffffff</color>
<color name="colorPink">#f8bbd0</color>
</resources>
选择器item_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="@color/colorWhite" />
<item android:state_focused="true" android:drawable="@color/colorPink" />
<item android:state_pressed="true" android:drawable="@color/colorPink" />
<item android:drawable="@color/colorWhite"/>
</selector>
条目布局item_app.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@drawable/item_selector"
android:layout_width="match_parent"
android:layout_height="60dp">
<!-- 中间内容无须修改,略-->
</RelativeLayout>
最终运行效果
截图已经不太能感受到卡了,真机运行更加流畅!
来源:http://www.jianshu.com/p/58f530735022#
猜你喜欢
- 序初涉江湖,还望海涵!写点东西,纯粹是因为个人的记忆能力较弱,写些笔记罢了,若有错误还望雅正!对Android中的时间获取做个记录,以下为结
- 本文实例为大家分享了Android Studio实现简单计算器功能的具体代码,供大家参考,具体内容如下程序步骤:(1)在布局文件定义一些计算
- 最近项目中用到了Elasticsearch5.4(ES)是比较新的一个版本,使用的过程中出现了很多的问题,很是头疼,但是问题最终还是解决掉了
- 用servlet实现一个注册的小功能 ,后台获取数据。注册页面:注册页面代码 :<!DOCTYPE html><html&
- 本文实例讲述了java实现的RSA加密算法。分享给大家供大家参考,具体如下:一、什么是非对称加密1、加密的密钥与加密的密钥不相同,这样的加密
- maven thin jar 步骤spring-boot-maven-plugin configuration &
- 像javascript中有eval()来执行动态代码,c#中是没有的,于是自己动手丰衣足食,先来代码using System;using S
- 这篇文章主要介绍了Springboot2.0处理自定义异常并返回json,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考
- 面试题1:说一下抽象类和接口有哪些区别?正经回答:抽象类和接口的主要区别:从设计层面来说,抽象类是对类的抽象,是一种模板设计;接口是行为的抽
- //构造文件File类File f=new File(fileName);//判断是否为目录f.isDirectory();//获取目录下的
- 算法介绍概念 TF-IDF(term frequency–inverse document
- 即只能在组件布局代码后,或者在组件的前面添加注释。#注释格式:Android的XML文件注释一般采用 <!--注释内容 -->的
- 官网教程一、翻转(镜像)头文件 quick_opencv.h:声明类与公共函数#pragma once#include <opencv
- 本文实例为大家分享了java字符串和数字转换工具的具体代码,供大家参考,具体内容如下package com.test.util;/** *
- 本文实例为大家分享了如何利用AOP实现SqlSugar自动事务,供大家参考,具体内容如下先看一下效果,带接口层的三层架构:BL层: publ
- 如果想你写的程序随系统开机一起启动的话,那么你可以照下面这个方法来做。 RunWhenStart(false, Applicati
- 前排提示,我在这个工具类加了@Component注解,如果在springboot的项目使用,记得通过@Autowired注入使用。impor
- 一、Close与Dispose这两种方法的区别调用完了对象的Close方法后,此对象有可能被重新进行使用;而Dispose方法来说,此对象所
- 一、template下文件不允许直接访问1、查资料得知:springboot项目默认是不允许直接访问template下的文件的,是受保护的。
- java url中如何传递数组,springMVC框架controller类如何接收数组参数?下面介绍一下URL中传递数组参数方法:dd.d