String、StringBuffer、StringBuilder操作字符串耗时对比
private void todo() {//这是一个很长的字符串String str ="最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。接下来让我们回忆一下,ListView最基本的填充方式分为向下填充和向上填充两种,分别对应的方法是fillDown()和fillUp()方法,而这两个方法的触发点都是在fillGap()方法当中的,fillGap()方法又是由trackMotionScroll()方法根据子元素的位置来进行调用的,这个方法只要手指在屏幕上滑动时就会不停进行计算,当有屏幕外的元素需要进入屏幕时,就会调用fillGap()方法来进行填充。那么,trackMotionScroll()方法也许就应该是我们开始着手修改的地方了。其中mColumnCount表示瀑布流布局一共有几列,这里我们先让它分为两列显示,后面随时可以对它进行修改。当然,如果想扩展性做的好的话,也可以使用自定义属性的方式在XML里面指定显示的列数,不过这个功能就不在我们本篇文章的讨论范围之内了。mColumnViews创建了一个长度为mColumnCount的数组,数组中的每个元素都是一个泛型为View的ArrayList,用于缓存对应列的子View。mPosIndexMap则是用于记录每一个位置的子View应当放置在哪一列当中。OK,工作原理确认了之后,接下来的工作就是动手实现了。由于瀑布流这个扩展对ListView整体的改动非常大,我们没办法简单地使用继承来实现,所以只能先将ListView的源码抽取出来,然后对其内部的逻辑进行修改来实现功能,那么我们第一步的工作就是要将ListView的源码抽取出来。但是这个工作并不是那么简单的,因为仅仅ListView这一个单独的类是不能够独立工作的,我们如果要抽取代码的话还需要将AbsListView、AdapterView等也一起抽取出来,然后还会报各种错误都需要一一解决,我当时也是折腾了很久才搞定的。所以这里我就不带着大家一步步对ListView源码进行抽取了,而是直接将我抽取好的工程UIListViewTest上传到了CSDN,大家只需要点击 这里 进行下载就可以了,今天我们所有的代码改动都是在这个工程的基础上进行的。StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(\"le\") 会使字符串缓冲区包含“startle”,而 z.insert(4, \"le\") 将更改字符串缓冲区,使之包含“starlet”。"+"最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。接下来让我们回忆一下,ListView最基本的填充方式分为向下填充和向上填充两种,分别对应的方法是fillDown()和fillUp()方法,而这两个方法的触发点都是在fillGap()方法当中的,fillGap()方法又是由trackMotionScroll()方法根据子元素的位置来进行调用的,这个方法只要手指在屏幕上滑动时就会不停进行计算,当有屏幕外的元素需要进入屏幕时,就会调用fillGap()方法来进行填充。那么,trackMotionScroll()方法也许就应该是我们开始着手修改的地方了。其中mColumnCount表示瀑布流布局一共有几列,这里我们先让它分为两列显示,后面随时可以对它进行修改。当然,如果想扩展性做的好的话,也可以使用自定义属性的方式在XML里面指定显示的列数,不过这个功能就不在我们本篇文章的讨论范围之内了。mColumnViews创建了一个长度为mColumnCount的数组,数组中的每个元素都是一个泛型为View的ArrayList,用于缓存对应列的子View。mPosIndexMap则是用于记录每一个位置的子View应当放置在哪一列当中。OK,工作原理确认了之后,接下来的工作就是动手实现了。由于瀑布流这个扩展对ListView整体的改动非常大,我们没办法简单地使用继承来实现,所以只能先将ListView的源码抽取出来,然后对其内部的逻辑进行修改来实现功能,那么我们第一步的工作就是要将ListView的源码抽取出来。但是这个工作并不是那么简单的,因为仅仅ListView这一个单独的类是不能够独立工作的,我们如果要抽取代码的话还需要将AbsListView、AdapterView等也一起抽取出来,然后还会报各种错误都需要一一解决,我当时也是折腾了很久才搞定的。所以这里我就不带着大家一步步对ListView源码进行抽取了,而是直接将我抽取好的工程UIListViewTest上传到了CSDN,大家只需要点击 这里 进行下载就可以了,今天我们所有的代码改动都是在这个工程的基础上进行的。StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(\"le\") 会使字符串缓冲区包含“startle”,而 z.insert(4, \"le\") 将更改字符串缓冲区,使之包含“starlet”。"+"最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。接下来让我们回忆一下,ListView最基本的填充方式分为向下填充和向上填充两种,分别对应的方法是fillDown()和fillUp()方法,而这两个方法的触发点都是在fillGap()方法当中的,fillGap()方法又是由trackMotionScroll()方法根据子元素的位置来进行调用的,这个方法只要手指在屏幕上滑动时就会不停进行计算,当有屏幕外的元素需要进入屏幕时,就会调用fillGap()方法来进行填充。那么,trackMotionScroll()方法也许就应该是我们开始着手修改的地方了。其中mColumnCount表示瀑布流布局一共有几列,这里我们先让它分为两列显示,后面随时可以对它进行修改。当然,如果想扩展性做的好的话,也可以使用自定义属性的方式在XML里面指定显示的列数,不过这个功能就不在我们本篇文章的讨论范围之内了。mColumnViews创建了一个长度为mColumnCount的数组,数组中的每个元素都是一个泛型为View的ArrayList,用于缓存对应列的子View。mPosIndexMap则是用于记录每一个位置的子View应当放置在哪一列当中。OK,工作原理确认了之后,接下来的工作就是动手实现了。由于瀑布流这个扩展对ListView整体的改动非常大,我们没办法简单地使用继承来实现,所以只能先将ListView的源码抽取出来,然后对其内部的逻辑进行修改来实现功能,那么我们第一步的工作就是要将ListView的源码抽取出来。但是这个工作并不是那么简单的,因为仅仅ListView这一个单独的类是不能够独立工作的,我们如果要抽取代码的话还需要将AbsListView、AdapterView等也一起抽取出来,然后还会报各种错误都需要一一解决,我当时也是折腾了很久才搞定的。所以这里我就不带着大家一步步对ListView源码进行抽取了,而是直接将我抽取好的工程UIListViewTest上传到了CSDN,大家只需要点击 这里 进行下载就可以了,今天我们所有的代码改动都是在这个工程的基础上进行的。StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(\"le\") 会使字符串缓冲区包含“startle”,而 z.insert(4, \"le\") 将更改字符串缓冲区,使之包含“starlet”。"+"最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。接下来让我们回忆一下,ListView最基本的填充方式分为向下填充和向上填充两种,分别对应的方法是fillDown()和fillUp()方法,而这两个方法的触发点都是在fillGap()方法当中的,fillGap()方法又是由trackMotionScroll()方法根据子元素的位置来进行调用的,这个方法只要手指在屏幕上滑动时就会不停进行计算,当有屏幕外的元素需要进入屏幕时,就会调用fillGap()方法来进行填充。那么,trackMotionScroll()方法也许就应该是我们开始着手修改的地方了。其中mColumnCount表示瀑布流布局一共有几列,这里我们先让它分为两列显示,后面随时可以对它进行修改。当然,如果想扩展性做的好的话,也可以使用自定义属性的方式在XML里面指定显示的列数,不过这个功能就不在我们本篇文章的讨论范围之内了。mColumnViews创建了一个长度为mColumnCount的数组,数组中的每个元素都是一个泛型为View的ArrayList,用于缓存对应列的子View。mPosIndexMap则是用于记录每一个位置的子View应当放置在哪一列当中。OK,工作原理确认了之后,接下来的工作就是动手实现了。由于瀑布流这个扩展对ListView整体的改动非常大,我们没办法简单地使用继承来实现,所以只能先将ListView的源码抽取出来,然后对其内部的逻辑进行修改来实现功能,那么我们第一步的工作就是要将ListView的源码抽取出来。但是这个工作并不是那么简单的,因为仅仅ListView这一个单独的类是不能够独立工作的,我们如果要抽取代码的话还需要将AbsListView、AdapterView等也一起抽取出来,然后还会报各种错误都需要一一解决,我当时也是折腾了很久才搞定的。所以这里我就不带着大家一步步对ListView源码进行抽取了,而是直接将我抽取好的工程UIListViewTest上传到了CSDN,大家只需要点击 这里 进行下载就可以了,今天我们所有的代码改动都是在这个工程的基础上进行的。StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(\"le\") 会使字符串缓冲区包含“startle”,而 z.insert(4, \"le\") 将更改字符串缓冲区,使之包含“starlet”。"+ "最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。接下来让我们回忆一下,ListView最基本的填充方式分为向下填充和向上填充两种,分别对应的方法是fillDown()和fillUp()方法,而这两个方法的触发点都是在fillGap()方法当中的,fillGap()方法又是由trackMotionScroll()方法根据子元素的位置来进行调用的,这个方法只要手指在屏幕上滑动时就会不停进行计算,当有屏幕外的元素需要进入屏幕时,就会调用fillGap()方法来进行填充。那么,trackMotionScroll()方法也许就应该是我们开始着手修改的地方了。其中mColumnCount表示瀑布流布局一共有几列,这里我们先让它分为两列显示,后面随时可以对它进行修改。当然,如果想扩展性做的好的话,也可以使用自定义属性的方式在XML里面指定显示的列数,不过这个功能就不在我们本篇文章的讨论范围之内了。mColumnViews创建了一个长度为mColumnCount的数组,数组中的每个元素都是一个泛型为View的ArrayList,用于缓存对应列的子View。mPosIndexMap则是用于记录每一个位置的子View应当放置在哪一列当中。OK,工作原理确认了之后,接下来的工作就是动手实现了。由于瀑布流这个扩展对ListView整体的改动非常大,我们没办法简单地使用继承来实现,所以只能先将ListView的源码抽取出来,然后对其内部的逻辑进行修改来实现功能,那么我们第一步的工作就是要将ListView的源码抽取出来。但是这个工作并不是那么简单的,因为仅仅ListView这一个单独的类是不能够独立工作的,我们如果要抽取代码的话还需要将AbsListView、AdapterView等也一起抽取出来,然后还会报各种错误都需要一一解决,我当时也是折腾了很久才搞定的。所以这里我就不带着大家一步步对ListView源码进行抽取了,而是直接将我抽取好的工程UIListViewTest上传到了CSDN,大家只需要点击 这里 进行下载就可以了,今天我们所有的代码改动都是在这个工程的基础上进行的。StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(\"le\") 会使字符串缓冲区包含“startle”,而 z.insert(4, \"le\") 将更改字符串缓冲区,使之包含“starlet”。";//转成字符串数组String[] strA=str.split("");Log.i("aa","字符串长度是:"+strA.length);long t1=System.currentTimeMillis();String result = "";for (String s : strA) {result = result + s;}Log.i("aa","使用String拼接耗时 "+(System.currentTimeMillis()-t1)+" 毫秒。");long t2=System.currentTimeMillis();StringBuilder sb=new StringBuilder();for (String s:strA){sb=sb.append(s);}Log.i("aa","使用StringBuilder拼接耗时 "+(System.currentTimeMillis()-t2)+" 毫秒。");long t3=System.currentTimeMillis();StringBuffer sf=new StringBuffer();for (String s:strA){sf=sf.append(s);}Log.i("aa","使用StringBuffer拼接耗时 "+(System.currentTimeMillis()-t3)+" 毫秒。");}
看现象憋说话!还敢乱用字符串吗?
String、StringBuffer、StringBuilder操作字符串耗时对比相关推荐
- 浅谈 Java 字符串(String, StringBuffer, StringBuilder)
我们先要记住三者的特征: String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全) 一.定义 查看 API 会发现,String ...
- 重温java中的String,StringBuffer,StringBuilder类
不论什么一个系统在开发的过程中, 相信都不会缺少对字符串的处理. 在 java 语言中, 用来处理字符串的的类经常使用的有 3 个: String.StringBuffer.StringBuilder ...
- `java`学习笔记(十二)`Java`--`String``StringBuffer``StringBuilder`
Java–String&&StringBuffer&&StringBuilder 文章目录 `Java`--`String`&&`StringBuffe ...
- String StringBuffer StringBuilder区别与联系
String StringBuffer StringBuilder String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量 ...
- String StringBuffer StringBuilder的区别
简单的事情做到极致也是一种能力. 首先,说一下目前我还没进行整理的情况下,我的理解: String 不可修改 修改后相当于又新创建创建一个字符串 比如: String a = "abc&qu ...
- String, StringBuffer, StringBuilder之间的区别
String与StringBuffer/StringBuilder之间的主要区别 1.String对象不可变, 如果修改会重新创建一个对象, 然后把值保存进去. StringBuffer/String ...
- StringBuffer类,StringBuffer类和String的区别、String,StringBuffer,StringBuilder之间的区别
1.概述 StringBuffer是一个线程安全的可变序列. 2.StringBuffer与String区别 (1)StringBuffer的长度和内容都可以发生改变,String却不行 (2)Str ...
- 116day(String,StringBuffer,StringBuilder,模拟器和虚拟机的区别,复合命题的种类)
<2018年2月4日>[连续116天] 标题:String,StringBuffer,StringBuilder,模拟器和虚拟机的区别,复合命题的种类: 内容: A.详见http://bl ...
- Java中的String,StringBuffer,StringBuilder有什么区别?
相信有很多同学都是经常使用String的,或者也或多或少的听说过StringBuffer,StringBuilder,那么在经常遇见的面试题中(标题),到底这三个的区别是什么呢?让我们来一探究竟! S ...
最新文章
- MFC按钮添加提示文字
- 《Cisco/H3C交换机配置与管理完全手册(第2版)》终稿封面和目录
- 企业移动办公及手机办公方案
- linux shell编程语句if、case.
- 从零开始学Pytorch(七)之卷积神经网络
- input file multiple 配合springmvc实现多文件上传
- Docker cpu memory quota使用说明
- linux之创建大文件
- 深入理解并行编程pdf
- linq group by 多个字段取值以及取出重复的数据
- php如何替换ico图标,wordpress网站怎么设置更换站点favicon ico图标
- 颠覆性创始人Tony Delgado在波多黎各启动编码训练营
- java国际化之时区问题处理
- 快排算法的针对重复键值的优化
- 2017百度之星资格赛1003 度度熊与邪恶大魔王(完全背包)
- 如何减轻tomcat压力_6种简单的技巧可帮助您减轻工作压力
- 【C Primer Plus】温度转换器
- Linux系统中彻底隐藏你的进程(隐藏后如何恢复显示?)
- 工作是最好的投资——图书摘录
- Android启动摄像机拍照存储展示
热门文章
- 智能安防场景:19类物品x光机图像数据集
- C语言hist()函数第2篇
- java 答题卡_试题八(共15分)阅读以下说明和Java程序代码,将应填入(n) 处的字句写在答题纸的对应栏内。[说明]在 - 赏学吧...
- LeetCode——哈希表经典例题
- 浅谈Api 签名算法
- PCtoLCD取模软件的使用步骤
- 航空1553接口测试工装研究
- jsp同游网驴友网ssh旅游论坛
- 计算机正版化检查,软件正版化检查整改工作报告
- python石头剪刀布