【轻松一刻】实战项目开发(二) list数据去重 数据追加与缓存

引入开源控件 PullToRefresh 下拉刷新列表

每次下拉刷新都会发送请求,从接口返回json信息。

如果前后两次请求返回的数据中有重复的数据 该怎么给list去重

在上一篇中我们重写了实体Data的hashcode和equals方法

/**
     * 因为更新时间和unixtime都不是唯一的
     * 这里使用唯一标识hashId来得到哈希码
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((hashId == null) ? 0 : hashId.hashCode());
        return result;
    }

    /**
     * 因为更新时间和unixtime都不是唯一的
     * 这里使用唯一标识hashId来比较
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Data other = (Data) obj;
        if (hashId == null) {
            if (other.hashId != null)
                return false;
        } else if (!hashId.equals(other.hashId))
            return false;
        return true;
    }

因为data数据中只有hashId 是唯一标识,所以我们使用它做比较

使用set中不能添加重新元素的特性作为判断条件去重

/**
     * 重写Data中的hashCode和equals方法
     * 使用set中不能添加重新元素的特性作为判断条件
     * 将不重复的data元素依次放入临时的newlist
     * 循环完毕后,将原始list清空,addAll(newlist)
     * @param list
     * @return
     */
    public static List<Data> removeDuplicateDataInOrder(List<Data> list)
    {
        HashSet<Data> hashSet = new HashSet<Data>();
        List<Data> newlist = new ArrayList<Data>();
        for (Iterator iterator = list.iterator(); iterator.hasNext();)
        {
            Data element = (Data) iterator.next();
            if (hashSet.add(element))
            {
                newlist.add(element);
            }
        }
        list.clear();
        list.addAll(newlist);
        return list;
    }

而为了保证数据排列的先后顺序 我们应该在去重复之前做如下操作

1.如果是下拉刷新 在把数据添加到list的头部 list.addAll(0,list<T>)
 2.如果是上拉加载更多则把数据加载到尾部 list.addAll(list<T>)

聚合数据接口 还可以按时间戳返回该时间点前或后的笑话列表

请求示例:http://japi.juhe.cn/joke/content/list.from?key=您申请的KEY&page=2&pagesize=10&sort=asc&time=1418745237

其中参数中的sort param sort desc:指定时间之前发布的,asc:指定时间之后发布的 ,time 表示时间戳

所以我们在上拉加载更多时 使用这种请求方式,以当前list中最后一条数据的时间戳为节点 返回该时间点前笑话列表。

故上拉加载更多时,list没有必要再去重复了、

if(flag == PULL_DOWN_REFRESH_FLAG){
                    // 将新刷新的数据 添加到数据集头部
                    mCurrentListItems.addAll(0,result.getResult());
                    // 去除list中重复的数据
                    mCurrentListItems = UtilsHelper.removeDuplicateDataInOrder(mCurrentListItems);
                }else if(flag == PULL_UP_REFRESH_FLAG){
                    // 将新加载的数据 添加到数据集尾部
                    // 因为是以最后一条数据的时间戳向前查询,故不存在重复,无需list去重
                    mCurrentListItems.addAll(result.getResult());
                    pullUpPageNumber++;
                }

如何得到本次请求之后更新了多少条数据呢,很简单只要保存上次的list,并与最新的list的size做对比即可。

使用handler处理,并在主线程更新UI

if(mLastListItems != null){
    int count = mCurrentListItems.size() - mLastListItems.size();

    android.os.Message msg = new android.os.Message();
    msg.what = UPDATE_DATA_COUNT_MESSAGE;
    msg.arg1 = count;
    mHandler.sendMessage(msg);
}

然后通知adapter数据集发生改变,并调用listview (listview是PullToRefreshListView的实例) 的onRefreshComplete()方法

// 通知程序数据集已经改变,如果不做通知,那么将不会刷新mListItems的集合
mAdapter.notifyDataSetChanged();
mListView.onRefreshComplete();

假设我们处于没有网络的环境,那就有必要搞一个缓存了,以便离线查看,最好是缓存上次我们退出应用时显示的list数据。

没有使用sqlite,暂时使用文件,缓存到sdcard的一个目录中(/storage/emulated/0/qingsongyike/cache)

public static void saveJsonTextInLocalFile(String jsonData){
        boolean sdCardExist = Environment.getExternalStorageState()
                .equals(android.os.Environment.MEDIA_MOUNTED); //判断sd卡是否存在
        if(sdCardExist){
            Log.d("UtilsHelper", "sdcard exist.");
            File root = Environment.getExternalStorageDirectory();
            String path = root.getPath()+File.separator+"qingsongyike"+File.separator+"cache";
            Log.d("UtilsHelper", "dir path = "+ path);
            File file = new File(path);
            if(!file.exists()){
                file.mkdirs();
                Log.d("UtilsHelper", "cache dir had create finished.");
            }

            File cacheFile = new File(path+File.separator+"cache.txt");
            if(!cacheFile.exists()){
                try {
                    cacheFile.createNewFile();
                    Log.d("UtilsHelper", "file path = "+ path);
                    Log.d("UtilsHelper", "cache file is created.");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            try {
                synchronized (obj) {
                    FileOutputStream fos = new FileOutputStream(cacheFile,false);
                    OutputStreamWriter writer = new OutputStreamWriter(fos);
                    writer.write(jsonData);
                    writer.flush();
                    writer.close();
                    fos.close();
                }
                Log.d("UtilsHelper", "cache data write finished.");
                //fos.write(JsonData.getBytes());
                //fos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else {
            Log.d("UtilsHelper", "sdcard is not exist. Create cache file failed");
        }
    }

那我们需要将list数据重新组装成对象,并使用GSON的API函数将bean转换成json字符串

开一个子线程去做IO操作

class CacheThread implements Runnable{

        @Override
        public void run() {
            // 执行缓存操作  将刷新后最新的数据重组成对象 并转换成Json字符
            // 不够50条 则都缓存
            // 超过50条 则只缓存前50条
            // 避免缓存文件较大 读取速度缓慢
            String jsonData = null;
            List<Data> list = new ArrayList<Data>();
            list.addAll(mCurrentListItems);
            if(list.size() > 0 && list.size() < 50){
                jsonData = UtilsHelper.beanConvertToJson(new Message(0, "Success", list));
            }else if(list.size() >= 50){
                // 将list中50条之后的都移除
                Log.d("CacheThread", "list size is  more than 50 !!");
                for (int i = list.size()-1; i >= 50; i--) {
                    list.remove(i);
                }
                Log.d("CacheThread", "list remove finish.  size now is 50 !!");
                jsonData = UtilsHelper.beanConvertToJson(new Message(0, "Success", list));
            }else {
                Log.d("CacheThread", "list size is 0 !!");
            }

            // 将Json字符保存到本地 以便没有网络时离线浏览
            if(jsonData != null){
                UtilsHelper.saveJsonTextInLocalFile(jsonData);
            }else {
                Log.d("CacheThread", "jsonData is null !!");
            }
        }

    }

这里将只截取最多50条笑话信息,以避免数据量大造成的读写缓慢的问题。

其中将bean转换成json字符串的函数如下

// bean转换json
    public static String beanConvertToJson(Object obj){
        Gson gson = new Gson();
        String json = gson.toJson(obj);
        Log.d("UtilsHelper", "json = " + json);
        return json;
    }

不要忘了在AndroidiManfest.xml中添加关于sdcard操作和文件读写的权限

<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 从SDCard读取数据权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

只要有更新数据 我们就执行一次本地缓存的操作

打开文件 内容已经写进去了

未完待续。。。

时间: 2024-12-27 20:02:53

【轻松一刻】实战项目开发(二) list数据去重 数据追加与缓存的相关文章

Hadoop mapreduce 数据去重 数据排序小例子

数据去重: 数据去重,只是让出现的数据仅一次,所以在reduce阶段key作为输入,而对于values-in没有要求,即输入的key直接作为输出的key,并将value置空.具体步骤类似于wordcount: Tip:输入输出路径配置. import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop

【轻松一刻】实战项目开发(三) 分享文本内容至微信

首先需要在微信开放平台创建应用 并等待审核通过. 需要注意包名,签名不要写错了.创建的应用可以是暂时没有上线了, 应用名称中不能含有微信二字,否则会被驳回,一般一至两天就能通过. 注意 严格按照 开发指南或者参考SDK Sample Demo步骤来,不能少. 使用android tools 导出带签名的apk,不要使用run as. 如果配置信息中打开了代码混淆,为了保证sdk的正常使用, 需要在proguard.cfg加上下面两行配置: -keep class com.tencent.mm.s

【轻松一刻】实战项目开发(零)

新建项目 使用Fragment实现tab页面的效果 自定义对话框控件 IOSAlertDialog 使用聚合数据sdk 请求数据. 获得返回的json字符串. 使用Gson解析Json数据 得到list<Data>数据,设置adapter数据集 引入下拉刷新控件. 自定义listview中item的布局 解决list列表中数据重复的问题 申请微信分享权限 添加分享文本 没有网络时 给与提示 离线状态下加载本地缓存数据

Android快乐贪吃蛇游戏实战项目开发教程-03虚拟方向键(二)绘制一个三角形

该系列教程概述与目录:http://www.cnblogs.com/chengyujia/p/5787111.html 一.绘制三角形 在上一篇文章中,我们已经新建了虚拟方向键的自定义控件DirectionKeys类,下面我们继续. 本项目中的虚拟方向键的背景是4个三角形组成的矩形,其实是4个三角形的按钮. 系统自带的按钮是矩形的,怎么做一个三角形按钮呢? 首先我需要了解,所有控件的外观都是画出来的,当然不是我们手工去画而是用程序去画. 用程序怎么画呢? 很多技术平台上都有绘图功能,用起来也很相

Android快乐贪吃蛇游戏实战项目开发教程-01项目概述

一.项目简介贪吃蛇是一个很经典的游戏,也很适合用来学习.本教程将和大家一起做一个Android版的贪吃蛇游戏.我已经将做好的案例上传到了应用宝,大家可以下载下来把玩一下.为了和其它的贪吃蛇区别开来,我取名叫“快乐贪吃蛇”.应用宝链接:http://sj.qq.com/myapp/detail.htm?apkName=net.chengyujia.happysnake这里上两张截图先睹为快,哈哈.怎么玩大家应该都知道,不过我还是要多提一下.通过屏幕上的方向键控制蛇的前进方向.蛇每吃到一个食物身体会

Android项目开发二

新浪微博客户端开发 本周学习计划 学习布局控件和UI设计相关知识. 微博验证,学习OAuth相关知识. 看懂微博客户端开发部分代码. 把借鉴代码导入到Android Studio中并运行成功. 实际完成情况 我学习到布局控件XML在res/layout中,是以.xml的形式保存.下图是登录界面,这个layout采用LinearLayout控件作为顶层控件,然后用ImageView控件分别实现版本号图片顶部靠左对齐显示.软件名称和图标图片居中对齐.作者名称和blog图片底部靠右对齐. 2.微博验证

Android快乐贪吃蛇游戏实战项目开发教程-06虚拟方向键(五)绘制方向键箭头

本系列教程概述与目录:http://www.cnblogs.com/chengyujia/p/5787111.html本系列教程项目源码GitHub地址:https://github.com/jackchengyujia/HappySnake 一.本文概述 在上篇教程中,我们画了4个背景三角形,并且实现了点击变色的按钮效果.在本篇教程中,我们将在这4个三角形上分别绘制表示方向的箭头,并且让箭头也有点击变色的效果.我们先看一下运行效果,有一个直观的了解,然后再从代码的角度分析和讲解. 二.运行效果

react实战项目开发(2) react几个重要概念以及JSX语法

前言 前面我们已经学习了利用官方脚手架搭建一套可以应用在生产环境下的React开发环境.那么今天这篇文章主要先了解几个react重要的概念,以及讲解本文的重要知识JSX语法 React重要概念 [思想] React 的核心思想是:封装组件,各个组件维护自己的状态和 UI,当状态变更,自动重新渲染整个组件. 如果我们使用react编写的话,会把他拆分成一个一个的小组件进行编写方便管理复用性高,例如我们把登录拆分成一个组件编写,如果以后公司其它地方需要用到,那么就可以直接使用. 看一段代码感受下:

【轻松一刻】项目代码已上传至开源中国[email&#160;protected]

项目代码已上传至开源中国[email protected],实际上16号左右就改的差不多了,一直耽搁没上传.其中程序中关于趣图的部分我并没有写.其他部分基本完整.主要原因是聚合数据返回的趣图大小不一,且图片尺寸偏小,在1080p和720p的手机上效果都很不好.暂时就不加了.您可以自行找合适的图片接口或者网上爬取合适尺寸的图片,其中图片list的展示与笑话的list展示类似. 后续这个小项目可能也不再更新了. 需要说明的是聚合数据接口的使用是有时间限制的,要想一直使用接口,需要应用上线,并且官网实