Android优化之数据结构优化

Android内存优化指南:从数据结构到5R法则的全面策略 Android内存优化涉及多个方面,从选择合适的数据结构如ArrayMap和SparseArray以减少内存占用,到避免使用内存开销大的枚举类型。谨慎使用多进程和large heap选项,同时充分利用NDK进行内存管理。图片优化是关键,通过采样、缓存和格式转换等方式减少内存占用。此外,遵循5R法则——释放、回收、减少、重用和检查,确保资源得到有效管理。这些策略共同构成了一套全面的Android内存优化方案,有助于提升应用性能和用户体验。 阅读详情

HashMap

简介

java中的常用集合,底层使用数组+链表的数据格式存储键值对。数组为主干,元素为键值对组成的Entry
图片来源于网络

源码分析

关键元素

// 默认初始容量-必须为2的幂
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
// 最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;
// 阀值 当前容量的75%
static final float DEFAULT_LOAD_FACTOR = 0.75f;
// 当链表长度大于8时转换为红黑树 当红黑树长度小于6时转换为链表
static final int TREEIFY_THRESHOLD = 8;
static final int UNTREEIFY_THRESHOLD = 6;

put

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        //声明了一个局部变量 tab,局部变量 Node 类型的数据 p,int 类型 n,i
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        /*首先将当前 hashmap 中的 table(哈希表)赋值给当前的局部变量 tab,然后判断tab 
        是不是空或者长度是不是 0,实际上就是判断当前 hashmap 中的哈希表是不是空或者长度等于 0
        **/
        if ((tab = table) == null || (n = tab.length) == 0)
        //如果是空的或者长度等于0,代表现在还没哈希表,所以需要创建新的哈希表,
        //默认就是创建了一个长度为 16 的哈希表
            n = (tab = resize()).length;
        //将当前哈希表中与要插入的数据位置对应的数据取出来,(n - 1) & hash])就是
        //找当前要插入的数据应该在哈希表中的位置,如果没找到,代表哈希表中当前的位置是空的,否则就代表找到数据了, 并赋值给变量 p
        if ((p = tab[i = (n - 1) & hash]) == null){
        //创建一个新的数据,这个数据没有下一条,并将数据放到当前这个位置
            tab[i] = newNode(hash, key, value, null);}
        else {
        //代表要插入的数据所在的位置是有内容的
        //声明了一个节点 e, 一个 key k
            Node<K,V> e; K k;
            //如果当前位置上的那个数据的 hash 和我们要插入的 hash 是一样,代表没有放错位置
            //如果当前这个数据的 key 和我们要放的 key 是一样的,实际操作应该是就替换值
            if (p.hash == hash && 
                ((k = p.key) == key || (key != null && key.equals(k)))){
                //将当前的节点赋值给局部变量 e
                e = p;
                //如果当前节点的 key 和要插入的 key 不一样,
                //然后要判断当前节点是不是一个红黑色类型的节点
            }else if (p instanceof TreeNode){
            	//如果是就创建一个新的树节点,并把数据放进去
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            }else {
                //如果不是树节点,代表当前是一个链表,那么就遍历链表
                for (int binCount = 0; ; ++binCount) {
                	//如果当前节点的下一个是空的,就代表没有后面的数据了
                    if ((e = p.next) == null) {
                    	//创建一个新的节点数据并放到当前遍历的节点的后面
                        p.next = newNode(hash, key, value, null);
                        // 重新计算当前链表的长度是不是超出了限制
                        if (binCount >= TREEIFY_THRESHOLD - 1) {
                        /*超出了之后就将当前链表转换为树,注意转换树的时候,
                        如果当前数组的长度小于MIN_TREEIFY_CAPACITY(默认 64),会触发扩容,
                        我个人感觉可能是因为觉得一个节点下面的数据都超过8 了,
                        说明 hash寻址重复的厉害(比如数组长度为 16 ,
                        hash 值刚好是 0或者 16 的倍数,导致都去同一个位置),需要重新扩容重新 hash**/
                            treeifyBin(tab, hash);
                        }
                        break;
                    }
                    //如果当前遍历到的数据和要插入的数据的 key 是一样,和上面之前的一样,赋值给变量 e,下面替换内容
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { //如果当前的节点不等于空,
                V oldValue = e.value;//将当前节点的值赋值给 oldvalue
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value; //将当前要插入的 value 替换当前的节点里面值
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;//增加长度
        if (++size > threshold){
        	/*
        	如果当前的 hash表的长度已经超过了当前 hash 需要扩容的长度, 
        	重新扩容,条件是 haspmap 中存放的数据超过了临界值(经过测试),
        	而不是数组中被使用的下标
        	**/
            resize();
        }
        afterNodeInsertion(evict);
        return null;
    }


get

public V get(Object key) {
    Node<K, V> e;
    return (e = getNode(hash(key), key)) == null ? null : e.value;
}
final HashMap.Node<K,V> getNode(int hash, Object key) {
    //定义变量
    HashMap.Node<K,V>[] tab; HashMap.Node<K,V> first, e; int n; K k;
    //查看数据需要满足一下条件
    //1)数组不为空
    //2)数组长度>0
    //3)通过hash计算出该元素在数组中存放位置的索引,而且该索引处数据不为空null
    if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
        //判断该数组索引位置处第一个是否为我们要找的元素 判断条件需要满足hash 和 key 相同
        if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
            //如果第一个就是我们要找的,直接返回即可
            return first;
        //如果第一个不是,我们需要循环遍历,然后找数据
        if ((e = first.next) != null) {
            //如果第1个的元素是红黑树类型的节点
            if (first instanceof HashMap.TreeNode)
                //那我们需要调用红黑树的方法查找节点
                return ((HashMap.TreeNode<K,V>)first).getTreeNode(hash, key);
            //如果不是,则该为链表,需要遍历查找
            do {
                //循环判断下一个节点的hash和key是否相同
                if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
                //更新e为下一个
            } while ((e = e.next) != null);
        }
    }
    //没找到返回Null
    return null;
}

SparseArray

简介

integer到Object的映射。与其他Array不同的是,他的index可以是不连续的。比HashMap更节省内存,因为它避免了auto-boxing keys并且他的数据结构中的每个映射关系不依赖一个额外的入口对象。使用数组 数据结构来存储映射,使用二分查找法 查找key。不适用于存储大量的数据,通常他比传统的HashMap慢,因为查找需要通过二分搜索,而且增加和删除需要在Array中插入和删除条目。对于存储量几百的容器来说,性能的差异不是很大,少于50%.为了提高性能,这个容器对于移除key有一个优化:它保留那些被移除的条目并给它们一个deleted标志而不是直接删除并压缩数组。这个条目可以在以后被同样的键值重用或者在之后的垃圾回收时一起进行回收。垃圾回收会在任何一个数组需要增长或者映射的size或者条目的值被获取的时间被执行。
可以通过keyAt(int)方法和valueAt(int)方法遍历容器中的item。

优点:

避免了基本数据类型的装箱操作
不需要额外的结构体,单个元素的存储成本更低
数据量小的情况下,随机访问的效率更高

缺点:

插入操作需要复制数组,增删效率降低
数据量巨大时,复制数组成本巨大,gc()成本也巨大
数据量巨大时,查询效率也会明显下降

源码分析

关键元素

// 删除元素后的标志
private static final Object DELETED = new Object();
// 是否存在垃圾,当调用delete remove 等方法时标记为true
private boolean mGarbage = false;
// 存储key的数组
private int[] mKeys;
// 存储value的数组
private Object[] mValues;
// 当前集合的大小
private int mSize;

binarySearch

 class ContainerHelpers {

    /**
     * 通过二分查找获取value值在当前数组中的位置
     * @param array
     * @param size
     * @param value
     * @return 如果存在value则返回该元素的索引,如果不存在当前元素则返回~(比该元素小的前一个元素的索引)  ~ 非运算
     * ~1 = -2   ~-1 = 0
     * 即如果存在则返回正整数或0  不存在则返回负整数
     */
	static int binarySearch(int[] array, int size, int value) {
	    int lo = 0;
	    int hi = size - 1;
	
	    while (lo <= hi) {
	        final int mid = (lo + hi) >>> 1;
	        final int midVal = array[mid];
	
	        if (midVal < value) {
	            lo = mid + 1;
	        } else if (midVal > value) {
	            hi = mid - 1;
	        } else {
	            return mid;  // value found
	        }
	    }
	    return ~lo;  // value not present
	}
	
	 static int binarySearch(long[] array, int size, long value) {
	     int lo = 0;
	     int hi = size - 1;
	
	     while (lo <= hi) {
	         final int mid = (lo + hi) >>> 1;
	         final long midVal = array[mid];
	
	         if (midVal < value) {
	             lo = mid + 1;
	         } else if (midVal > value) {
	             hi = mid - 1;
	         } else {
	             return mid;  // value found
	         }
	     }
	     return ~lo;  // value not present
	 }
}

put

public void put(int key, E value) {
	// 使用二分查找查询当前key存在的索引
	int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
	//如果i >= 0 证明元素存在 直接覆盖 value数组中对应索引的值
	if (i >= 0) {
	    mValues[i] = value;
	} else {
	    // i<0 证明不存在  i是比当前元素小的最近的元素
	    //  如待插入元素为15,  存在数组[10,13,14,16,44] 则应该插入14与16之间 返回~(14的索引)即 ~2 等于 -3;
	    // i = ~i (~-3 等于 2)  //获取 14的正确索引值
	    i = ~i;
	    //如果索引小于当前长度,且value数组中当前索引的值被删除标记为deleted  那么就覆盖keys数组以及value数组中当前索引对应的值
	    if (i < mSize && mValues[i] == DELETED) {
	        mKeys[i] = key;
	        mValues[i] = value;
	        return;
	    }
	    //如果 当前 集合中存在垃圾(被删除过),并且当前集合长度>= key数组的长度 则进行垃圾回收
	    if (mGarbage && mSize >= mKeys.length) {
	        gc();
	
	        // Search again because indices may have changed.
	        i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
	    }
	    // 将 key 跟value插入数组中对应位置
	    mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
	    mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
	    mSize++;
	}
}

get

 /**
 * Gets the Object mapped from the specified key, or <code>null</code>
 * if no such mapping has been made.
 */
public E get(int key) {
    return get(key, null);
}

/**
 * 含默认值重写方法
 * @param key
 * @param valueIfKeyNotFound 默认值
 * @return value
 */
public E get(int key, E valueIfKeyNotFound) {
    // 二分查找 key对应的索引值
    int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
    // i < 0 或者 当前索引对应value 被删除时 返回默认值
    if (i < 0 || mValues[i] == DELETED) {
        return valueIfKeyNotFound;
    } else {
        return (E) mValues[i];
    }
}

ArrayMap

简介

ArrayMap是一个<key,value>映射的数据结构,它设计上更多的是考虑内存的优化,内部是使用两个数组进行数据存储,一个数组记录key的hash值,另外一个数组记录Value值,它和SparseArray一样,也会对key使用二分法进行从小到大排序,在添加、删除、查找数据的时候都是先使用二分查找法得到相应的index,然后通过index来进行添加、查找、删除等操作,所以,应用场景和SparseArray的一样,如果在数据量比较大的情况下,那么它的性能将退化至少50%。

源码分析

关键元素

put

public V put(K key, V value) {
	final int osize = mSize;
	// 1.计算 hash code 并获取 index
	final int hash;
	int index;
	if (key == null) {
	    // 为空直接取 0
	    hash = 0;
	    index = indexOfNull();
	} else {
	    // 否则取 Object.hashCode()
	    hash = mIdentityHashCode ? System.identityHashCode(key) : key.hashCode();
	    index = indexOf(key, hash);
	}
	// 2.如果 index 大于等于 0 ,说明之前存在相同的 hash code 且 key 也相同,则直接覆盖
	if (index >= 0) {
	    index = (index<<1) + 1;
	    final V old = (V)mArray[index];
	    mArray[index] = value;
	    return old;
	}
	// 3.如果没有找到则上面的 indexOf() 或者  indexOfNull() 就会返回一个负数,而这个负数就是由将要插入的位置 index 取反得到的,所以这里再次取反就变成了将进行插入的位置
	index = ~index;
	// 4.判断是否需要扩容
	if (osize >= mHashes.length) {
	    final int n = osize >= (BASE_SIZE*2) ? (osize+(osize>>1))
	            : (osize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE);
	
	    if (DEBUG) Log.d(TAG, "put: grow from " + mHashes.length + " to " + n);
	
	    final int[] ohashes = mHashes;
	    final Object[] oarray = mArray;
	    // 5.申请新的空间
	    allocArrays(n);
	
	    if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) {
	        throw new ConcurrentModificationException();
	    }
	
	    if (mHashes.length > 0) {
	        if (DEBUG) Log.d(TAG, "put: copy 0-" + osize + " to 0");
	        // 将数据复制到新的数组中
	        System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);
	        System.arraycopy(oarray, 0, mArray, 0, oarray.length);
	    }
	    // 6.释放旧的数组
	    freeArrays(ohashes, oarray, osize);
	}
	
	if (index < osize) {
	    // 7.如果 index 在当前 size 之内,则需要将 index 开始的数据移到 index + 1 处,以腾出 index 的位置
	    if (DEBUG) Log.d(TAG, "put: move " + index + "-" + (osize-index)
	            + " to " + (index+1));
	    System.arraycopy(mHashes, index, mHashes, index + 1, osize - index);
	    System.arraycopy(mArray, index << 1, mArray, (index + 1) << 1, (mSize - index) << 1);
	}
	
	if (CONCURRENT_MODIFICATION_EXCEPTIONS) {
	    if (osize != mSize || index >= mHashes.length) {
	        throw new ConcurrentModificationException();
	    }
	}
	// 8.然后根据计算得到的 index 分别插入 hash,key,以及 code
	mHashes[index] = hash;
	mArray[index<<1] = key;
	mArray[(index<<1)+1] = value;
	mSize++;
	return null;
}

indexOf

/*
(1) 如果当前为空表,则直接返回 ~0,注意不是 0 ,而是最大的负数。
(2) 在 mHashs 数组中进行二分查找,找到 hash 的 index。
(3) 如果 index < 0,说明没有找到。
(4) 如果 index >= 0,且在 mArray 中对应的 index<<1 处的 key 与要找的 key 又相同,则认为是同一个 key,说明找到了。
(5) 如果 key 不相同,说明只是 hash code 相同,那么分别向后和向前进行搜索,如果找到了就返回。如果没找到,那么对 end 取反就是当前需要插入的 index 位置。
**/
int indexOf(Object key, int hash) {
	final int N = mSize;
	// Important fast case: if nothing is in here, nothing to look for.
	if (N == 0) {
	    return ~0;
	}
	int index = binarySearchHashes(mHashes, N, hash);
	// If the hash code wasn't found, then we have no entry for this key.
	if (index < 0) {
	    return index;
	}
	// If the key at the returned index matches, that's what we want.
	if (key.equals(mArray[index<<1])) {
	    return index;
	}
	// Search for a matching key after the index.
	int end;
	for (end = index + 1; end < N && mHashes[end] == hash; end++) {
	    if (key.equals(mArray[end << 1])) return end;
	}
	// Search for a matching key before the index.
	for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) {
	    if (key.equals(mArray[i << 1])) return i;
	}
	// Key not found -- return negative value indicating where a
	// new entry for this key should go.  We use the end of the
	// hash chain to reduce the number of array entries that will
	// need to be copied when inserting.
	return ~end;
}

get

public V get(Object key) {
    final int index = indexOfKey(key);
    return index >= 0 ? (V)mArray[(index<<1)+1] : null;
}
Versal - 从零构建Petalinux 2024.2 AI边缘计算平台(VD100+SDT+JupyterLab实战) 本文详细介绍了如何从零开始,基于AMD Versal VD100开发板和Petalinux 2024.2构建AI边缘计算平台。内容涵盖开发环境搭建、Petalinux工程创建与配置、SDT新流程实战、启动SD卡制作,并最终集成JupyterLab与Conda,打造出开箱即用的交互式AI开发环境,帮助开发者快速进行算法验证与部署。 阅读详情

相关推荐

从零搭建自动驾驶仿真环境:我的Nuplan-devkit实战笔记(含PyCharm配置技巧)

本文详细记录了从零搭建Nuplan-devkit自动驾驶仿真环境的完整流程,包括conda环境配置、pip版本控制、PyCharm专业版集成等关键步骤。特别针对Ubuntu系统下的依赖管理、数据目录优化和性能调优提供了实用技巧,帮助开发者高效构建稳定的自动驾驶仿真开发环境。

weixin_30505225的博客 479

Java---Arrays类的常用方法

对于Java中数组的一些操作快捷方法,比如查元素,转换字符串,拷贝数组之类的,简单详细。

gaoqiandr的博客 2092

基于51单片机+SYN6288语音播报

51单片机控制SYN6288语音播报资料SYN6288模块原理图语音合成命令接线如何接线实现原理程序代码main.csyn6288.cuart.cdelay.c基于 51单片机的其他项目基于51单片机+遥控灯基于51单片机+LCD1602显示基于51单片机+红外遥控解码+LCD1602显示基于51单片机+DHT11温湿度+LCD1602显示基于51单片机+DS18B20温度测温器+LCD1602显示尾声 资料 我用的是绿深电子技术的模块,资料也挺齐全的。也有相关例程。 SYN6288模块原理图 语音合成

weixin_47457689的博客 3万+

java中的六种常用的Array方法

Array方法

张超的博客 3479

系统设计---算法与架构

这片文章对系统设计的具体步骤及相关知识进行介绍,主要分为四部分:算法设计、IC系统架构设计、基于systemC的IC系统设计、系统设计工具SPW简介。 (一)算法设计 系统设计的第一步是给出清晰的系统规范,该规范写明了系统的功能、性能、费用、开发时间等。接下来创建一个系统行为模型,并且可以用来初步验证设计的性能。再下来,对行为模型进行细化,即进行算法设计。算法设计大致分为三步: 1)给出浮点

正在努力的ICer的博客 4372

RML2016.10a (CNN、LSTM、CNN-LSTM、CNN-LSTM-Multi-head-attention, TensorFlow)

RML2016.10a (CNN、LSTM、CNN-LSTM、CNN-LSTM-Multi-head-attention, TensorFlow) 包含所有数据和代码,支持一键运行(jupyter)

qq_40999533的博客 1481

Arrays类中的常用方法

Arrays类中的常用方法 Arrays类的定义 Arrays类位于java.util 包中,主要包含了操纵数组的各种方法 Arrays类常用的方法 1.toString() 返回指定数组内容的字符串表示形式 2.sort() 对指定的类型数组按数字升序进行排序 3.binarysearch() 使用二分搜索法来搜索指定类型数组,以获取指定值(要求数组中元素已经按照升序排序) 4.fill() 将指定值分配给指定数组的每个元素 import java.util.Arrays; public cla

qq_43110032的博客 1580

告别糊涂账!用CKM3底表逻辑自建物料成本监控报表(含ABAP代码片段)

本文详细介绍了如何利用CKM3底表逻辑自建物料成本监控报表,解决标准报表无法穿透成本差异根源的问题。通过ABAP代码片段和四步架构法,帮助财务团队精准分析成本构成,优化成本核算批量处理,实现多维透视差异分析,提升成本监控效率。

weixin_30740295的博客 266

Java—Arrays常用方法

Arrays常用方法

喻师傅的学习笔记 2387

把 ABAP Unit 测试放进本地类:让重构更安全、让测试更好找的组织方式

ABAP测试代码组织策略:单元测试与集成测试的合理存放位置 本文针对ABAP开发中测试代码组织混乱的问题,提出了一套系统化的解决方案: 单元测试应存放在被测类的本地测试include中(...CCAU或...T99),确保测试与代码同步演进且易于发现 跨对象测试(组件/集成/系统测试)应创建单独的全局测试类,并通过FOR TESTING和ABSTRACT进行防护 使用! @testing注释建立测试关系,使测试与被测对象明确关联,提高可发现性 针对不同技术栈(RAP/CAP/OData)提供了具体落地建议,

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1729

【赛题解析&命令脚本配置】2023年全国职业院校技能大赛GZ073网络系统管理赛项赛题第9套模块A:网络构建 & (三)无线网络配置+(四)出口网络配置-命令配置

【赛题解析&命令脚本配置】2023年全国职业院校技能大赛GZ073网络系统管理赛项赛题第9套模块A:网络构建 & (三)无线网络配置+(四)出口网络配置-命令配置

君逍遥o 1017

Java数组:针对数组(Array)的各种操作

文章目录本章学习要点Java数组简介:数组是什么?Java一维数组的定义、赋值和初始化创建一维数组分配空间例 1初始化一维数组1)使用 new 指定数组大小后进行初始化例 22)使用 new 指定数组元素的值例 33)直接指定数组元素的值例 4获取单个元素例 5例 6获取全部元素Java二维数组详解创建二维数组初始化二维数组例 1获取单个元素例 2获取全部元素例 3例 4获取整行元素例 5获取整列元素例 6Java不规则数组Java数组也是一种数据类型Java中到底有没有多维数组(长篇神文)?对Java数组

qq_41854911的博客 3852

完整复盘【避雷jd文职某岗位】潍坊青州hhj(据说未来搬到天津),助理实验师岗位,三人进面,面试全部不及格,空头岗位!像这种情况,该单位很多 | 附个人完整备考背诵题目 | 世间一场梦,不会再考这个了

本文以博主本人报考jun dui文职,从报考、备考、考试、查成绩到资格审查、面试,全程亲身经历,给想要报考该内容的朋友们一些小的参考。祝你顺利上岸!完整复盘【避雷jd文职某岗位】潍坊青州hhj(据说未来搬到天津),助理实验师岗位,三人进面,面试全部不及格,空头岗位!像这种情况,该单位很多 | 附个人完整备考背诵题目 | 世间一场梦,不会再考这个了

追光者♂:记录、分享、总结、提升,现象级专栏《Python从入门到人工智能》作者,无惧黑暗,坚信曙光 245

Android 性能优化入门(一)—— 数据结构优化

一款 app 除了要有令人惊叹的功能和令人发指交互之外,在性能上也应该追求丝滑的要求,这样才能更好地提高用户体验,响应速度一项就主要取决于数据结构和算法。

tmacfrank 1568

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Android性能优化——数据结构的优化

Android性能优化包含很多方面,今天我们来看看对于数据结构如何做优化。 1.集合的遍历操作:private void for1(ArrayList<Model> list){ long start = System.currentTimeMillis(); int len = list.size(); for(int i= 0;i < len;i

lxfeng1098751554的专栏 554

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Android性能优化(一)——数据结构优化

数据结构优化,使用Sparsearray 替换HashMap 资料: Android应用性能优化之使用SparseArray替代HashMap Android中的稀疏数组:SparseArray问题:Sparsearray之所以比HashMap高效的原因是什么?结合两篇博客以及HashMap和Sparsearray的源码得出以下结论: 1、在数据存储方面,Sparsearray进行了优化

ZhangGeng's Blog 2636

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Android性能优化—数据结构优化

优化数据结构是提高Android应用性能的重要一环。在Android开发中,ArrayList、LinkedList和HashMap等常用的数据结构的正确使用对APP性能的提升有着重大的影响。

sziitjin的博客 986

Android 性能优化 (十三) 数据结构算法优化 秒变大神 Protocol Buffer

4大优化 1.图片数据优化 2.集合的优化 3.排序算法优化 4.传输数据优化 今天运行了一下:Android Lint工具,看到了程序中关于这块的问题 1.图片优化 用ARGB_4444替代ARGB_8888 ALPHA_8——代表8位Alpha位图 ARGB_4444——代表16位ARGB位图 ARGB_8888——代表32位ARGB位图 RGB_565——代表...

深南大盗的博客 504

安卓性能优化一数据结构

k为object类型,根据k找到int类型的hashcode,装箱过程,table []大小未知,根据hashcode % table的length求模运算,得到范围0-length-1,求模运算等价于位运算,源码中使用的是位运算,更快,往JVM转为字节码时速度更快,这时得到下标index即源码中的i,通过下标i找到要操作的位置,完成k的任务。扩容耗性能,避免扩容,创建时应该评估hash表的大小,(大小/0.75+1),如何保证大小为2的次幂,这就和put时有关。避免冲突,长度更大,冲突的可能性更低。

liuwushuang233的博客 678

Android性能优化-数据结构

云笔记链接:https://note.youdao.com/s/84OhDByE。

feather(猎羽) 169

Android高性能编码三:数据结构和算法优化

TPS(Transaction Per Second) TPS为每秒处理的事务数,是系统吞吐量的指标,在搜索系统中也用QPS(Query Per Second)衡量。TPS一般与响应时间反相关。 通常所说的性能问题就是指响应时间过长、系统吞吐量过低。 Android高性能编码一:多线程并发或分布式提高TPS Android高性能编码二:利用缓存提高TPS Android高性能编码

疾风的博客 3035

android list 排序_Android:内存优化你必须知道的三大数据结构

作者:众小成多积小致巨1、前言这几个数据结构呢,都是Android这家伙搞出来;为啥呢,打的旗号是节约内存,系统的很多地方都有他们的身影;为了追随google的脚步,也为了扩展自己对于数据结构的理解,我们有必要学习它;这里先大致说下,ArrayMap是一个map,是为了解决HashMap存储数据浪费空间情况;SparseArray是数组,为稀疏数据准备的;SparseXXXArray,也是数组,也...

weixin_35651855的博客 277

Android8.1_SystemUI_Notification:数据结构优化

18/1/13 $

QrowWong的博客 584

5个Android 数据结构和优化方面的深度面试题

本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点。

AntDream的程序世界 1253
上一篇: 常用密码技术-对称加密
下一篇: Java基础-泛形
hjdudu
博客等级 码龄10年 4粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值