Android关于列表卡顿的问题(或者说两个列表数据关联的问题)

最近在做一个TV项目时遇到了一个小问题:
主要是这样一种业务,一个主列表,主要是显示video文件的名称,右边一个列表显示详细的信息,包括文件名称、存储路径、视频时长、文件大小等等信息。左边的主列表切换不同的Item时,右边的信息对应变化。
在我使用常规的方式编写列表的时候出现了卡顿的问题,最终发现原因并解决了问题。

  • 卡顿的原因
  • 优化方法
  • 最终效果

卡顿的原因

网上关于卡顿原因的资料很多。总结一下主要是:
1.未使用复用机制;
2.Item的布局过于复杂,或者嵌套层数太深;
3.不合适的调用notifyDataSetChanged()方法;
4.列表数据中包含耗时操作,并且未使用工作线程;
5.其他原因。

我的业务中出现卡顿的原因就是第四点。
因为列表中的视频文件的时长、文件的大小等属于耗时操作。其他几种原因也一并总结一下。

优化方法

  1. 第一、二种原因造成的问题,改进方法很直接,在Adapter中使用复用机制、将Item的嵌套层数减少,不能减少的尽可能使用<include/>标签
    复用机制一般是使用ViewHolder(不论是普通的AdapterView还是现在流行的RecyclerView)

  2. 第三种原因造成的现象主要是要注意更新列表的时候需要注意:
    1) 创建Adapter的时候,传入的数据可能是List<T> == null 或者 List<T>.size()==0;
    2) 数据可能需要读取本地、网络文件(比较耗费时间),读取的过程需要再工作线程中进行,可以自己管理Thread,也可以使用线程池、或者网络框架比如Retrofit等(内部包含了线程管理)
    3) 在完成读取数据之后,通知主线程更新UI,此时应该在收到更新UI的消息后,进行notifyDataSetChanged()的调用。
    4) 在列表数据发生变化,一般包括用户新增一条数据、用户删除一条数据(一般对于一个用户可编辑的列表),操作完成也需要进行进行notifyDataSetChanged()的调用。
    5) 其他非必要情况,尽可能不要调用notifyDataSetChanged()。

  3. 耗时操作 :文件信息的获取:

/*简单的写一个线程池执行*/
mInfoExecutors.execute(new Runnable() {

        @Override
        public void run() {
            try {
                // 1.File的length方法得到文件大小(耗时)    
                long fileBytes = itemFile.length();
                // 2.将文件大小转化为用户可读的内容(..KB、..MB、..GB)
                String mSize = calculateFileSize(fileBytes);
                // 3.文件最后一次修改的时间
                long lastTime = itemFile.lastModified();
                // 4.在未播放的情况下,获取视频文件的时长
                long duration = getMediaFileDuration(itemFile.getPath());
                Message.obtain(mInfoHandler, MSG_REFRESH_INFO, mInfoText).sendToTarget();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
});
/**
 * @param bytes 文件的长度
 * @return 用户可读的文件大小
 */
private String calculateFileSize(long bytes) {
    String result = "0 KB";
    if(bytes > 0 && bytes < 1024*1024) {
        result = String.format("%.1f", ((double)bytes/1024.0)) + "KB";
    } else if (bytes > 1024*1024 && bytes < 1024*1024*1024) {
        result = String.format("%.1f", ((double)bytes/1024/1024)) + "MB";
    } else if (bytes > 1024*1024*1024) {
        result = String.format("%.1f", ((double)bytes/1024/1024/1024)) + "GB";
    }
    return result;
}
/**
 * @param filePath 视频文件的路径
 * @return 视频文件的时长
 */
public static long getMediaFileDuration(String filePath){
    long duration = 0L;
    MediaMetadataRetriever mmr = new MediaMetadataRetriever();
    try {
        if (filePath != null) {
            mmr.setDataSource(filePath);
        }
        duration = Long.valueOf(mmr.extractMetadata(
        MediaMetadataRetriever.METADATA_KEY_DURATION));
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        mmr.release();
    }
    return duration;
}
5.  其他原因,需要根据业务逻辑和具体情况分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值