zoukankan      html  css  js  c++  java
  • 如何解决快应用页面滑动卡顿问题

    问题现象

    页面一次加载了100条数据,页面滑动出现卡顿。

    问题代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    <template>
      <div class="container">
        <div class="nav">
          <text class="nav-item">list</text>
        </div>
      
        <!-- List -->
        <list class="list" onclick="listClick" onlongpress="listLongPress"
          onscrollbottom="scrollbottom"  id="list" scrollpage="{{scrollPage}}">
      
          <list-item type="listItem" class="item"  onclick="listItemClick"
            if="{{listData.length>0}}">
               <div for="{{listData}}" style="flex-direction:column;">
                    <text  class="txt">{{$item}}--{{$idx}}</text>
               </div>
          </list-item>
      
          <!-- Loading More  -->
          <list-item type="loadMore" class="load-more" if="{{loadMore}}">
            <progress type="circular"></progress>
            <text>More</text>
          </list-item>
        </list>
      
      </div>
    </template>
    <style>
      
      .container{
         flex-direction: column;
      }
      
      .list {
        padding-left: 10px;
        padding-right: 10px;
        columns: 1;
        flex-direction: column;
        border-color: #FF0000;
        border- 5px;
      }
      
      .item {
        flex-direction: column;
        align-items: flex-start;
        margin-bottom: 15px;
        border-color: #9400D3;
        border- 5px;
        margin-right: 20px;
        #f76160;
      }
      
      .load-more {
        justify-content: center;
        align-items: center;
        height: 100px;
        border-color: #bbbbbb;
        border-bottom- 1px;
      }
      
      .btn-little {
        flex: 1;
        height: 80px;
        margin-left: 15px;
        border-radius: 5px;
        color: #ffffff;
        font-size: 30px;
        text-align: center;
        #0faeff;
      }
      
      .nav {
        padding-left: 60px;
        padding-right: 60px;
        padding-bottom: 30px;
      }
      
      .nav-item {
        flex: 1;
        padding-bottom: 30px;
        border-bottom- 5px;
        border-color: #fbf9fe;
        font-size: 35px;
        color: #666666;
        text-align: center;
      }
      
    </style>
    <script>
      import prompt from '@system.prompt'
      
      export default {
        data: {
          componentName: 'list',
          loadMore: true,
          listAdd: ['A''B''C''D''E''F''G''H''I''J''K''L''M''N''O''P''Q''R''S''T''U''V''W''X''Y''Z'],
          listData: [],
          scrollPage: false,
        },
        onInit: function () {
          this.$page.setTitleBar({ text: 'list' })
          for(var index = 0;index < 100;index++){
              this.listData[index] = 'A';
         }
           
        },
       
        scrollbottom: function () {
          prompt.showToast({
            message: 'The list slides to the bottom and starts loading other data.'
          })
          // Load next page
          var that = this
          var renderData = [].concat(that.listData, that.listAdd)
          setTimeout(function () {
            that.listData = renderData
          }, 1000)
        },
      
        // monitoring during sliding
        scroll: function (e) {
          let msg = 'scroll' '.scrollX:' + e.scrollX
            ' .scrollY:' + e.scrollY
            ' .scrollState:' + e.scrollState
          console.info(msg)
        },
       
       
        listItemClick: function (e) {
          e.stopPropagation()
          console.info('List Item is clicked.')
          prompt.showToast({
            message: 'List Item is clicked.'
          })
        },
        listClick: function (e) {
          e.stopPropagation()
          console.info('List is clicked.')
          prompt.showToast({
            message: 'List is clicked.'
          })
        },
      
        listLongPress: function (e) {
          e.stopPropagation()
          console.info('List is long pressed.')
          prompt.showToast({
            message: 'List is long pressed.'
          })
        },
      }
    </script>

    问题分析

         以上代码使用list、list-item来加载大规模数据,但是使用方法不当,导致list-item的视图view没有被复用。

    我们知道快应用的引擎是一个android apk,list、list-item的实现最终都是通过android的ListView、BaseAdapter等这些实现的,了解这些其实知道列表界面上超过屏幕显示的区域是不会重新创建视图的,而是复用第一次在界面上可见区域的那些view的,只需要把数据刷新一下即可。每一行的视图view其实就是list-item。

    以上代码虽然看起来是列表,但是只有1个list-item,开发者在list-item内部使用了for循环,每循环一次,都会创建一个新的view,当数据量很大时,内存占用越多,手机内存吃紧,不断地做申请、释放内存的操作,应用性能受到严重影响,导致滑动卡顿。

    解决方法

       基于list组件的特点,在list-item内部内部需谨慎使用if指令或for指令,根据列表每行数据特点,在list-item上设置不同的type,尽可能复用list-item,在list-item上使用for语句。修改后代码如下(注意list-item部分):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    <template>
      <div class="container">
        <div class="nav">
          <text class="nav-item">list</text>
        </div>
      
        <!-- List -->
        <list class="list" onclick="listClick" onlongpress="listLongPress"
          onscrollbottom="scrollbottom"  id="list" scrollpage="{{scrollPage}}">
          
          <list-item type="listItem" class="item item-color"  onclick="listItemClick"
            for="{{listData}}">
            <text  class="txt">{{$item}}--{{$idx}}</text>
          </list-item>
      
          <!-- <list-item type="listItem" class="item"  onclick="listItemClick"
            if="{{listData.length>0}}">
               <div for="{{listData}}" style="flex-direction:column;">
                    <text  class="txt">{{$item}}--{{$idx}}</text>
               </div>
          </list-item> -->
      
          <!-- Loading More  -->
          <list-item type="loadMore" class="load-more" if="{{loadMore}}">
            <progress type="circular"></progress>
            <text>More</text>
          </list-item>
        </list>
      
      </div>
    </template>

    代码运行效果图对比:              

     

     
     

     
     

               图1 修改后效果

     
     

             图2  修改前效果

     



    从上面效果图中我们看到,虽然都是列表数据,但是图1每一行都是一个list-item(list-item的css中背景色设置的是红色),而且type值都一样,能很好地复用list-item,但是图2中只有1个list-item,里面列表数据都是作为list-item的子节点。图2的效果和使用普通的div加载大量列表数据是一样的,根源在于开发者没有很好地理解list、list-item的原理。

    欲了解更多详情,请参见:

    快应用list开发指导:

    https://developer.huawei.com/consumer/cn/doc/development/quickApp-References/quickapp-component-list#h1-1592485335262

    原文链接:https://developer.huawei.com/...
    原作者:Mayism

  • 相关阅读:
    NumberFormat 类
    ExtJs自学教程(1):一切从API開始
    机器学习笔记——贝叶斯学习
    装饰模式
    Cocos2d-x 动手实现游戏主循环
    Solr使用入门指南
    3D数学读书笔记——矩阵进阶
    学习笔记一:关于directx sdk的安装于一些概念
    oracle-db安装
    java实现第六届蓝桥杯切开字符串
  • 原文地址:https://www.cnblogs.com/developer-huawei/p/15147725.html
Copyright © 2011-2022 走看看