Android-常用数据结构和控件

HashMap 的原理

HashMap 的内部可以看做数组+链表的复合结构。数组被分为一个个的桶(bucket)。哈希值决定了键值对在数组中的寻址。具有相同哈希值的键值对会组成链表。需要注意的是当链表长度超过阈值(默认是8)的时候会触发树化,链表会变成树形结构。
把握HashMap的原理需要关注4个方法:hash、put、get、resize。
hash方法。 将 key 的 hashCode 值的高位数据移位到低位进行异或运算。这么做的原因是有些 key 的 hashCode 值的差异集中在高位,而哈希寻址是忽略容量以上高位的,这种做法可以有效避免哈希冲突。
put 方法。put 方法主要有以下几个步骤:
1、通过 hash 方法获取 hash 值,根据 hash 值寻址。
2、如果未发生碰撞,直接放到桶中。
3、如果发生碰撞,则以链表形式放在桶后。
4、当链表长度大于阈值后会触发树化,将链表转换为红黑树。
5、如果数组长度达到阈值,会调用 resize 方法扩展容量。
get方法。get 方法主要有以下几个步骤:
1、通过 hash 方法获取 hash 值,根据 hash 值寻址。
2、如果与寻址到桶的 key 相等,直接返回对应的 value。
3、如果发生冲突,分两种情况。如果是树,则调用 getTreeNode 获取 value;如果是链表则通过循环遍历查找对应的 value。
resize 方法。resize 做了两件事:
将原数组扩展为原来的 2 倍
重新计算 index 索引值,将原节点重新放到新的数组中。这一步可以将原先冲突的节点分散到新的桶中。

LruCache的原理

LruCache 的核心原理就是对 LinkedHashMap 的有效利用,它的内部存在一个 LinkedHashMap 成员变量。值得我们关注的有四个方法:构造方法、get、put、trimToSize。

构造方法: 在 LruCache 的构造方法中做了两件事,设置了 maxSize、创建了一个 LinkedHashMap。这里值得注意的是 LruCache 将 LinkedHashMap的accessOrder 设置为了 true,accessOrder 就是遍历这个LinkedHashMap 的输出顺序。true 代表按照访问顺序输出,false代表按添加顺序输出,因为通常都是按照添加顺序输出,所以 accessOrder 这个属性默认是 false,但我们的 LruCache 需要按访问顺序输出,所以显式的将 accessOrder 设置为 true。
get方法: 本质上是调用 LinkedHashMap 的 get 方法,由于我们将 accessOrder 设置为了 true,所以每调用一次get方法,就会将我们访问的当前元素放置到这个LinkedHashMap的尾部。
put方法: 本质上也是调用了 LinkedHashMap 的 put 方法,由于 LinkedHashMap 的特性,每调用一次 put 方法,也会将新加入的元素放置到 LinkedHashMap 的尾部。添加之后会调用 trimToSize 方法来保证添加后的内存不超过 maxSize。
trimToSize方法: trimToSize 方法的内部其实是开启了一个 while(true)的死循环,不断的从 LinkedHashMap 的首部删除元素,直到删除之后的内存小于 maxSize 之后使用 break 跳出循环。
其实到这里我们可以总结一下,为什么这个算法叫 最近最少使用 算法呢?原理很简单,我们的每次 put 或者get都可以看做一次访问,由于 LinkedHashMap 的特性,会将每次访问到的元素放置到尾部。当我们的内存达到阈值后,会触发 trimToSize 方法来删除 LinkedHashMap 首部的元素,直到当前内存小于 maxSize。为什么删除首部的元素,原因很明显:我们最近经常访问的元素都会放置到尾部,那首部的元素肯定就是 最近最少使用 的元素了,因此当内存不足时应当优先删除这些元素。

DiskLruCache原理

设计一个图片的异步加载框架
设计一个图片加载框架,肯定要用到图片加载的三级缓存的思想。三级缓存分为内存缓存、本地缓存和网络缓存。

内存缓存:将Bitmap缓存到内存中,运行速度快,但是内存容量小。
本地缓存:将图片缓存到文件中,速度较慢,但容量较大。
网络缓存:从网络获取图片,速度受网络影响。

如果我们设计一个图片加载框架,流程一定是这样的:
1、拿到图片url后首先从内存中查找Bitmap,如果找到直接加载。
2、内存中没有找到,会从本地缓存中查找,如果本地缓存可以找到,则直接加载。
3、内存和本地都没有找到,这时会从网络下载图片,下载到后会加载图片,并且将下载到的图片放到内存缓存和本地缓存中。

上面是一些基本的概念,如果是具体的代码实现的话,大概需要这么几个方面的文件:
1、首先需要确定我们的内存缓存,这里一般用的都是 LruCache。
2、确定本地缓存,通常用的是 DiskLruCache,这里需要注意的是图片缓存的文件名一般是 url 被 MD5 加密后的字符串,为了避免文件名直接暴露图片的 url。
3、内存缓存和本地缓存确定之后,需要我们创建一个新的类 MemeryAndDiskCache,当然,名字随便起,这个类包含了之前提到的 LruCache 和 DiskLruCache。在 MemeryAndDiskCache 这个类中我们定义两个方法,一个是 getBitmap,另一个是 putBitmap,对应着图片的获取和缓存,内部的逻辑也很简单。getBitmap中按内存、本地的优先级去取 BItmap,putBitmap 中先缓存内存,之后缓存到本地。
4、在缓存策略类确定好之后,我们创建一个 ImageLoader 类,这个类必须包含两个方法,一个是展示图片 displayImage(url,imageView),另一个是从网络获取图片downloadImage(url,imageView)。在展示图片方法中首先要通过 ImageView.setTag(url),将 url 和 imageView 进行绑定,这是为了避免在列表中加载网络图片时会由于ImageView的复用导致的图片错位的 bug。之后会从 MemeryAndDiskCache 中获取缓存,如果存在,直接加载;如果不存在,则调用从网络获取图片这个方法。从网络获取图片方法很多,这里我一般都会使用 OkHttp+Retrofit。当从网络中获取到图片之后,首先判断一下imageView.getTag()与图片的 url 是否一致,如果一致则加载图片,如果不一致则不加载图片,通过这样的方式避免了列表中异步加载图片的错位。同时在获取到图片之后会通过 MemeryAndDiskCache 来缓存图片。

SparseArray 原理

SparseArray,通常来讲是 Android 中用来替代 HashMap 的一个数据结构。 准确来讲,是用来替换key为 Integer 类型,value为Object 类型的HashMap。需要注意的是 SparseArray 仅仅实现了 Cloneable 接口,所以不能用Map来声明。 从内部结构来讲,SparseArray 内部由两个数组组成,一个是 int[]类型的 mKeys,用来存放所有的键;另一个是 Object[]类型的 mValues,用来存放所有的值。 最常见的是拿 SparseArray 跟HashMap 来做对比,由于 SparseArray 内部组成是两个数组,所以占用内存比 HashMap 要小。我们都知道,增删改查等操作都首先需要找到相应的键值对,而 SparseArray 内部是通过二分查找来寻址的,效率很明显要低于 HashMap 的常数级别的时间复杂度。提到二分查找,这里还需要提一下的是二分查找的前提是数组已经是排好序的,没错,SparseArray 中就是按照key进行升序排列的。 综合起来来说,SparseArray 所占空间优于 HashMap,而效率低于 HashMap,是典型的时间换空间,适合较小容量的存储。 从源码角度来说,我认为需要注意的是 SparseArray的remove()、put()和 gc()方法。
1、remove()。 SparseArray 的 remove() 方法并不是直接删除之后再压缩数组,而是将要删除的 value 设置为 DELETE 这个 SparseArray 的静态属性,这个 DELETE 其实就是一个 Object 对象,同时会将 SparseArray 中的 mGarbage 这个属性设置为 true,这个属性是便于在合适的时候调用自身的 gc()方法压缩数组来避免浪费空间。这样可以提高效率,如果将来要添加的key等于删除的key,那么会将要添加的 value 覆盖 DELETE。
2、gc()。 SparseArray 中的 gc() 方法跟 JVM 的 GC 其实完全没有任何关系。``gc()` 方法的内部实际上就是一个for循环,将 value 不为 DELETE 的键值对往前移动覆盖value 为DELETE的键值对来实现数组的压缩,同时将 mGarbage 置为 false,避免内存的浪费。
3、put()。 put 方法是这么一个逻辑,如果通过二分查找 在 mKeys 数组中找到了 key,那么直接覆盖 value 即可。如果没有找到,会拿到与数组中与要添加的 key 最接近的 key 索引,如果这个索引对应的 value 为 DELETE,则直接把新的 value 覆盖 DELET 即可,在这里可以避免数组元素的移动,从而提高了效率。如果 value 不为 DELETE,会判断 mGarbage,如果为 true,则会调用 gc()方法压缩数组,之后会找到合适的索引,将索引之后的键值对后移,插入新的键值对,这个过程中可能会触发数组的扩容。

RecyclerView与ListView 对比:缓存机制

  1. 层级不同:RecyclerView比ListView多两级缓存,支持多个离屏ItemView缓存,支持开发者自定义缓存处理逻辑,支持所有RecyclerView共用同一个RecyclerViewPool(缓存池)。
    具体来说:
    ListView(两级缓存):在这里插入图片描述
    RecyclerView(四级缓存):
    在这里插入图片描述
    ListView和RecyclerView缓存机制基本一致:
    1). mActiveViews和mAttachedScrap功能相似,意义在于快速重用屏幕上可见的列表项ItemView,而不需要重新createView和bindView;2). mScrapView和mCachedViews + mReyclerViewPool功能相似,意义在于缓存离开屏幕的ItemView,目的是让即将进入屏幕的ItemView重用.
    3). RecyclerView的优势在于a.mCacheViews的使用,可以做到屏幕外的列表项ItemView进入屏幕内时也无须bindView快速重用;b.mRecyclerPool可以供多个RecyclerView共同使用,在特定场景下,如viewpaper+多个列表页下有优势.客观来说,RecyclerView在特定场景下对ListView的缓存机制做了补强和完善。

  2. 缓存不同:
    1). RecyclerView缓存RecyclerView.ViewHolder,抽象可理解为:View + ViewHolder(避免每次createView时调用findViewById) + flag(标识状态);2). ListView缓存View。

数据库的事务:事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/625659.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

5 - 声明式事务

传统事务流程: Connection connection JdbcUtils.getConnection(); try {//1. 先设置事务不要自动提交connection.setAutoCommit(false);//2. 进行各种 crud//多个表的修改,添加 ,删除select from 商品表 > 获取价格//修改用户余额updat…

“确定要在不复制其属性的情况下复制此文件?”解决方案(将U盘格式由FAT格式转换为NTFS格式)

文章目录 1.问题描述2.问题分析3.问题解决3.1 方法一3.2 方法二3.3 方法三 1.问题描述 从电脑上复制文件到U盘里会出现“确定要在不复制其属性的情况下复制此文件?”提示。 2.问题分析 如果这个文件在NTFS分区上,且存在特殊的安全属性。那么把它从NT…

请查收“链上天眼”2023年成绩单

1月10日是中国人民警察节,是一份责任,更一份安心,随着科技的发展,链上安全领域的技术与工具不断更新迭代,更加安全的Web3世界正在构建。 根据欧科云链安全团队统计,2023 年全球范围内利用虚拟货币进行诈骗…

采购申请检查并警告提示

设置:采购申请检查并警告提示 增强:MEREQ001 EXIT_SAPLMEREQ_005 &--------------------------------------------------------------------- *& 包含 ZXM02U05 &--------------------------------------------------------------------- …

Radzen Blazor Studio 脚手架框架解读

背景 组织管理管理准备使用Blazor这个工具实现,因为其有对应的 scaffold 脚手架,先构建数据库,然后通过向导,生成CRUD以及对应的接口,那么有必要看一下,其内部的代码结构是什么样的。 结构 接口层 有两类…

L1-024 后天(Java)

如果今天是星期三,后天就是星期五;如果今天是星期六,后天就是星期一。我们用数字1到7对应星期一到星期日。给定某一天,请你输出那天的“后天”是星期几。 输入格式: 输入第一行给出一个正整数D(1 ≤ D ≤…

布隆过滤器原理(易理解版)

当我们说布隆过滤器时,可以将其想象成一个特殊的盒子,这个盒子可以判断某个东西是否在里面。但是,这个盒子并不存储实际的东西,而是用一些特殊的方法来判断。 盒子(位数组): 有一个盒子&#xf…

Oracle sql sum函数返回null,默认值0

在Oracle SQL中,当你使用SUM函数对一组值进行求和时,如果这组值中包含NULL,那么SUM函数将忽略这些NULL值,并返回非NULL值的总和。 如果你希望在SUM函数返回NULL时有一个默认值,你可以使用COALESCE或NVL函数。 使用CO…

深度学习烦人的基础知识(1)---@在bash中的作用---positional parameter详解

文章目录 序Positional parameter练习题 Special parameter练习题 序 深度学习,反展到现在,真的是要融会贯通很多东西。遇到便补吧! 想直接知晓答案的,请到最后一个练习题,想补基础知识的,请按照顺序阅读…

Python——for循环的嵌套

用Python坚持表白一百天,每天都送10朵花,一百天表白成功! i1 for i in range(1,101):print(f"今天是表白的第{i}天,坚持ing")for j in range(1,11):print(f"送给你第{j}朵玫瑰花")print("小美我喜欢你&…

Hive 的 安装与使用

目录 1 安装 MySql2 安装 Hive3 Hive 元数据配置到 MySql4 启动 Hive5 Hive 常用交互命令6 Hive 常见属性配置 Hive 官网 1 安装 MySql 为什么需要安装 MySql? 原因在于Hive 默认使用的元数据库为 derby,开启 Hive 之后就会占用元数据库,且不与其他客户…

Mindspore 公开课 - prompt

prompt 介绍 Fine-Tuning to Prompt Learning Pre-train, Fine-tune BERT bidirectional transformer,词语和句子级别的特征抽取,注重文本理解Pre-train: Maked Language Model Next Sentence PredictionFine-tune: 根据任务选取对应的representatio…

算法通关村第十六关—滑动窗口经典问题(白银)

滑动窗口经典问题 一、最长子串专题 1.1 无重复字符的最长子串 LeetCode3给定一个字符串s,请你找出其中不含有重复字符的最长子串的长度。例如: 输入:s"abcabcbb" 输出:3 解释:因为无重复字符的最长子串是…

【Java万花筒】数据之舞:Java数据库连接与操作库全景视角

数据库连接与操作:Java 应用开发者的综合指南 前言 随着Java应用的不断发展,数据库连接与操作成为关键技能之一。本文将深入探讨主流Java库,涵盖了JDBC、Hibernate、MyBatis、Spring Data JPA、Apache Commons DBUtils、JOOQ以及Querydsl。…

牛客周赛 Round 28 F

以后需要使用map,set进行二分,并且需要知道二分位置的信息时,不妨考虑使用树状数组进行维护 因为简单版本保证了每个数都为正整数,所以前缀和保证了一定的递增的,即有序的,那么考虑固定左端点,去…

多线程并发与并行

📑前言 本文主要是【并发与并行】——并发与并行的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他 🌄每日一句&…

自动化测试理论(1)—概述需要掌握的内容

要在自动化测试领域取得成功,需要掌握一系列技能和概念。以下是一些关键的内容: 编程语言: 了解并精通至少一种编程语言,如Python,Java,JavaScript等。编写自动化测试脚本通常需要编程技能。 自动化测试框…

SpringBoot3

有用的新特性 JDK8-19 新增了不少新特性,这里我们把实际常用的新特性,给大家介绍一下。包括以下几个方面: Java RecordSwich 开关表达式Text Block 文本块var 声明局部变量sealed 密封类 Java14 中预览的新特性叫做 Record ,在…

explorer.exe 作用

Explorer.exe是什么 在Windows操作系统中,Explorer.exe是桌面进程的意思,它负责显示用户桌面信息,如果用户将它结束掉就看不到桌面上的任何图标了,相当于Windows操作系统中的人机交互界面,其重要性不言而喻。如果用户发…

【算法笔记】分支限界专题

分支限界 整体结构 本质上感觉还是遍历解树剪枝,但是配合优先队列使用以后可以更好的找到最优解。 例题 P8011 ⾛迷宫 对于迷宫问题,某一节点的关联节点指的是它四个方向上相邻的节点。 要利用flag数组确保不会重复访问。 void bfs(){//1、初始化队…