技术咨询、项目合作、广告投放、简历咨询、技术文档下载 点击这里 联系博主

# 合理的刷新机制

在应用的开发中,因为数据的变化,需要刷新页面来展示数据,但是频繁的刷新会增加资源的开销,并且可能导致卡顿。 合理的刷新机制需要注意以下几点:

  • 尽量减少刷新的次数
  • 尽量避免后台有高 CPU 线程运行
  • 缩小刷新区域

# 一、减少刷新次数

  • 控制刷新的频率 比如在显示进度条的时候,不需要每一个进度的时候都需要显示,可以做到每隔多少刷新显示一次,这样就减少了刷新的频率。
  • 避免没有必要的刷新 首先需要判断是否需要刷新,比如数据没有变化的时候,需要刷新的控件不在可见区域内,就没必要刷新,但是需要注意的是:如果一个 View 从不可见到可见,一定要刷新一次。

# 二、避免后台线程影响

后台线程过大会导致 CPU 占比过高,导致频繁的 GC 和 CPU 时间片资源紧张,还是优肯会导致页面的卡顿。比如在 RecyclerView 或者 ListView 在滑动的时候就可以暂停其他的 UI 操作: 通过监听 ListView 的 onScrollStateChanged 事件,在滚动的时候暂停下载图片和下载进程工作,结束后再刷新可以提高 ListView 的滑动平滑度。(具体详见:Android 缓存策略和 Bitmap 高效加载)。

# 三、缩小刷新的区域

# 在自定义 View

在自定义 View 中一般采用 invalidata 方法刷新,如果需要更新数据,只是在某个区域的话,在调用了 invalidata 就会更新整个视图,这就浪费了不需要更新区域的资源。我们采用两种更新局部数据的方法。

invalidata(Rect dirty)
invalidata(int left,int top,int right,int bottom)

# 容器中的某个 Item 发生了变化

只需要更新这个 Item 就行了。比如在 ListView 中或者 RecyclerView 中,如果是单条操作,就必须调用 AdapternotifyDataChanged()刷新。

# invalidate()函数的区域更新例子

public class FingerView extends View {

private static final float STROKE_WIDTH = 5f;

/** Need to track this so the dirty region can accommodate the stroke. **/
private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;

private Paint paint = new Paint();
private Path path = new Path();

 /**
  * Optimizes painting by invalidating the smallest possible area.
  */
 private float lastTouchX;
 private float lastTouchY;
 private final RectF dirtyRect = new RectF();

  public <span style="font-family: Arial, Helvetica, sans-serif; font-size: ;">FingerView </span>(Context context, AttributeSet attrs) {
   super(context, attrs);

   paint.setAntiAlias(true);
   paint.setColor(Color.BLACK);
   paint.setStyle(Paint.Style.STROKE);
   paint.setStrokeJoin(Paint.Join.ROUND);
   paint.setStrokeWidth(STROKE_WIDTH);
 }

 /**
  * Erases the signature.
  */
 public void clear() {
   path.reset();

   // Repaints the entire view.
   invalidate();
 }

 @Override
 protected void onDraw(Canvas canvas) {
   canvas.drawPath(path, paint);
 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
   float eventX = event.getX();
   float eventY = event.getY();

   switch (event.getAction()) {
     case MotionEvent.ACTION_DOWN:
       path.moveTo(eventX, eventY);
       lastTouchX = eventX;
       lastTouchY = eventY;
       // There is no end point yet, so don't waste cycles invalidating.
       return true;

     case MotionEvent.ACTION_MOVE:
     case MotionEvent.ACTION_UP:
       // Start tracking the dirty region.
       resetDirtyRect(eventX, eventY);

       // When the hardware tracks events faster than they are delivered,
       // event will contain a history of those skipped points.
       int historySize = event.getHistorySize();
       for (int i = 0; i < historySize; i++) {
         float historicalX = event.getHistoricalX(i);
         float historicalY = event.getHistoricalY(i);
         expandDirtyRect(historicalX, historicalY);
         path.lineTo(historicalX, historicalY);
       }

       // After replaying history, connect the line to the touch point.
       path.lineTo(eventX, eventY);
       break;

     default:
       debug("Ignored touch event: " + event.toString());
       return false;
   }

   // Include half the stroke width to avoid clipping.
   invalidate(
       (int) (dirtyRect.left - HALF_STROKE_WIDTH),
       (int) (dirtyRect.top - HALF_STROKE_WIDTH),
       (int) (dirtyRect.right + HALF_STROKE_WIDTH),
       (int) (dirtyRect.bottom + HALF_STROKE_WIDTH));

   lastTouchX = eventX;
   lastTouchY = eventY;

   return true;
 }

 /**
  * Called when replaying history to ensure the dirty region includes all
  * points.
  */
 private void expandDirtyRect(float historicalX, float historicalY) {
   if (historicalX < dirtyRect.left) {
     dirtyRect.left = historicalX;
    } else if (historicalX > dirtyRect.right) {
      dirtyRect.right = historicalX;
    }
    if (historicalY < dirtyRect.top) {
      dirtyRect.top = historicalY;
    } else if (historicalY > dirtyRect.bottom) {
      dirtyRect.bottom = historicalY;
    }
  }

  /**
   * Resets the dirty region when the motion event occurs.
   */
  private void resetDirtyRect(float eventX, float eventY) {

    // The lastTouchX and lastTouchY were set when the ACTION_DOWN
    // motion event occurred.
    dirtyRect.left = Math.min(lastTouchX, eventX);
    dirtyRect.right = Math.max(lastTouchX, eventX);
    dirtyRect.top = Math.min(lastTouchY, eventY);
    dirtyRect.bottom = Math.max(lastTouchY, eventY);
  }
}

【未经作者允许禁止转载】 Last Updated: 2/4/2024, 6:06:40 AM