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)+"  毫秒。");
    }

看现象憋说话!还敢乱用字符串吗?

猜你喜欢

转载自blog.csdn.net/u013359807/article/details/80451752