欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2022-06-06 17:14:57
recyclerview为什么会卡 recyclerview作为v7包的新控件,自从推出就广受android developer们欢迎,实际上它已经取代了listview...

recyclerview为什么会卡

recyclerview作为v7包的新控件,自从推出就广受android developer们欢迎,实际上它已经取代了listview和gridview两位老前辈的地位。然而不少亲们想必也已经发现了:没有优化过的recycler性能很poor。上一篇博主使用的item也仅仅是一个图两串字而已,结果一滑动就卡的要命,不能忍!

那么why?回想在用listview和gridview的adapter时,我们是用一种叫viewholder的自定义类(容器)来实现优化的,而recyclerview的特性之一就是强制你使用它的recyclerview.viewholder。可是,recyclerview.viewholder要比我们写的那个单纯的容器复杂多了(源码里算上注释有大约500行),与recyclerview.adapter的联系也是千丝万缕。

按*上面比较通俗的解释: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的卡顿问题的解决方法 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。