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>

最终运行效果

截图已经不太能感受到卡了,真机运行更加流畅!

Android RecyclerView的卡顿问题的解决方法 

来源:http://www.jianshu.com/p/58f530735022#

标签:recyclerview,卡顿
0
投稿

猜你喜欢

  • Windows系统中Java调用cmd命令及执行exe程序的方法

    2021-11-27 23:00:02
  • Android 利用 APT 技术在编译期生成代码

    2023-12-20 14:46:23
  • java遍历Map的几种方法分析

    2023-12-04 22:34:27
  • 在winform下实现左右布局多窗口界面的方法

    2023-02-23 11:31:51
  • Android 图片添加水印的实现方法

    2023-11-20 01:13:29
  • 实现一个基于Servlet的hello world程序详解步骤

    2022-06-21 00:22:13
  • Java IO之序列化与反序列化详解

    2023-05-21 14:59:14
  • java反射之方法反射的基本操作方法

    2021-11-26 00:45:36
  • Android用户注册界面简单设计

    2023-07-13 02:59:50
  • Java语言实现Blowfish加密算法完整代码分享

    2023-11-02 21:30:07
  • Android绘制动态折线图

    2021-12-28 12:59:50
  • maven profile动态选择配置文件详解

    2023-11-05 22:05:20
  • Java基于JDK 1.8的LinkedList源码详析

    2021-07-15 03:29:26
  • spring使用OXM进行对象XML映射解析

    2022-11-11 16:05:19
  • SpringBoot下如何实现支付宝接口的使用

    2023-11-06 14:26:15
  • C#十五子游戏编写代码

    2023-06-13 07:33:22
  • C#提取网页中超链接link和text部分的方法

    2023-02-24 02:04:14
  • Android设置透明状态栏和透明导航栏

    2021-09-22 07:19:41
  • Java中Runnable与Callable接口的区别详解

    2021-12-22 11:33:28
  • Unity实现游戏存档框架

    2023-02-10 13:05:15
  • asp之家 软件编程 m.aspxhome.com