Android Scroller完全解析_Android

在Android中,任何一个控件都是可以滚动的,因为在View类当中有scrollTo()和scrollBy()这两个方法,如下图所示:

这两个方法的主要作用是将View/ViewGroup移至指定的坐标中,并且将偏移量保存起来。另外:

mScrollX 代表X轴方向的偏移坐标
mScrollY 代表Y轴方向的偏移坐标

这两个方法都是用于对View进行滚动的,那么它们之间有什么区别呢?简单点讲,scrollBy()方法是让View相对于当前的位置滚动某段距离,而scrollTo()方法则是让View相对于初始的位置滚动某段距离。

关于偏移量的设置我们可以参看下源码:

public class View {
  ....
  protected int mScrollX; //该视图内容相当于视图起始坐标的偏移量,X轴方向
  protected int mScrollY; //该视图内容相当于视图起始坐标的偏移量,Y轴方向
  //返回值
  public final int getScrollX() {
    return mScrollX;
  }
  public final int getScrollY() {
    return mScrollY;
  }
  public void scrollTo(int x, int y) {
    //偏移位置发生了改变
    if (mScrollX != x || mScrollY != y) {
      int oldX = mScrollX;
      int oldY = mScrollY;
      mScrollX = x; //赋新值,保存当前便宜量
      mScrollY = y;
      //回调onScrollChanged方法
      onScrollChanged(mScrollX, mScrollY, oldX, oldY);
      if (!awakenScrollBars()) {
        invalidate(); //一般都引起重绘
      }
    }
  }
  // 看出区别了吧 。 mScrollX 与 mScrollY 代表我们当前偏移的位置 , 在当前位置继续偏移(x ,y)个单位
  public void scrollBy(int x, int y) {
    scrollTo(mScrollX + x, mScrollY + y);
  }
  //...
} 

于是,在任何时刻我们都可以获取该View/ViewGroup的偏移位置了,即调用getScrollX()方法和getScrollY()方法。

下面我们写个例子看下它们的区别吧:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/layout"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">

  <Button
    android:id="@+id/scroll_to_btn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="scrollTo"/>

  <Button
    android:id="@+id/scroll_by_btn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="10dp"
    android:text="scrollBy"/>
</LinearLayout>

外层使用了一个LinearLayout,在里面包含了两个按钮,一个用于触发scrollTo逻辑,一个用于触发scrollBy逻辑。

public class MainActivity extends AppCompatActivity {

  private LinearLayout layout;
  private Button scrollToBtn;
  private Button scrollByBtn;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    layout = (LinearLayout) findViewById(R.id.layout);
    scrollToBtn = (Button) findViewById(R.id.scroll_to_btn);
    scrollByBtn = (Button) findViewById(R.id.scroll_by_btn);
    scrollToBtn.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        layout.scrollTo(getResources().getDimensionPixelOffset(R.dimen.horizontal_scroll),
            getResources().getDimensionPixelOffset(R.dimen.horizontal_scroll));
      }
    });
    scrollByBtn.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        layout.scrollBy(getResources().getDimensionPixelOffset(R.dimen.horizontal_scroll),
            getResources().getDimensionPixelOffset(R.dimen.horizontal_scroll));
      }
    });
  }
}

<resources>
  <dimen name="horizontal_scroll">-20dp</dimen>
  <dimen name="vertical_scroll">-30dp</dimen>
</resources>

当点击了scrollTo按钮时,我们调用了LinearLayout的scrollTo()方法,当点击了scrollBy按钮时,调用了LinearLayout的scrollBy()方法。那有的朋友可能会问了,为什么都是调用的LinearLayout中的scroll方法?这里一定要注意,不管是scrollTo()还是scrollBy()方法,滚动的都是该View内部的内容,而LinearLayout中的内容就是我们的两个Button,如果你直接调用button的scroll方法的话,那结果一定不是你想看到的。

另外还有一点需要注意,就是两个scroll方法中传入的参数,第一个参数x表示相对于当前位置横向移动的距离,正值向左移动,负值向右移动。第二个参数y表示相对于当前位置纵向移动的距离,正值向上移动,负值向下移动。
运行一下程序:

当我们点击scrollTo按钮时,两个按钮会一起向右下方滚动,之后再点击scrollTo按钮就没有任何作用了,界面不会再继续滚动,只有点击scrollBy按钮界面才会继续滚动,并且不停点击scrollBy按钮界面会一起滚动下去。

Scroller类

从上面例子运行结果可以看出,利用scrollTo()/scrollBy()方法把一个View偏移至指定坐标(x,y)处,整个过程是直接跳跃的,没有对这个偏移过程有任何控制,对用户而言不太友好。于是,基于这种偏移控制,Scroller类被设计出来了,该类的主要作用是为偏移过程制定一定的控制流程,从而使偏移更流畅,更完美。
我们分析下源码里去看看Scroller类的相关方法,其源代码(部分)如下: 路径位于 \frameworks\base\core\Java\android\widget\Scroller.java

public class Scroller { 

  private int mStartX;  //起始坐标点 , X轴方向
  private int mStartY;  //起始坐标点 , Y轴方向
  private int mCurrX;   //当前坐标点 X轴, 即调用startScroll函数后,经过一定时间所达到的值
  private int mCurrY;   //当前坐标点 Y轴, 即调用startScroll函数后,经过一定时间所达到的值 

  private float mDeltaX; //应该继续滑动的距离, X轴方向
  private float mDeltaY; //应该继续滑动的距离, Y轴方向
  private boolean mFinished; //是否已经完成本次滑动操作, 如果完成则为 true 

  //构造函数
  public Scroller(Context context) {
    this(context, null);
  }
  public final boolean isFinished() {
    return mFinished;
  }
  //强制结束本次滑屏操作
  public final void forceFinished(boolean finished) {
    mFinished = finished;
  }
  public final int getCurrX() {
    return mCurrX;
  }
   /* Call this when you want to know the new location. If it returns true,
   * the animation is not yet finished. loc will be altered to provide the
   * new location. */
  //根据当前已经消逝的时间计算当前的坐标点,保存在mCurrX和mCurrY值中
  public boolean computeScrollOffset() {
    if (mFinished) { //已经完成了本次动画控制,直接返回为false
      return false;
    }
    int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
    if (timePassed < mDuration) {
      switch (mMode) {
      case SCROLL_MODE:
        float x = (float)timePassed * mDurationReciprocal;
        ...
        mCurrX = mStartX + Math.round(x * mDeltaX);
        mCurrY = mStartY + Math.round(x * mDeltaY);
        break;
      ...
    }
    else {
      mCurrX = mFinalX;
      mCurrY = mFinalY;
      mFinished = true;
    }
    return true;
  }
  //开始一个动画控制,由(startX , startY)在duration时间内前进(dx,dy)个单位,即到达坐标为(startX+dx , startY+dy)出
  public void startScroll(int startX, int startY, int dx, int dy, int duration) {
    mFinished = false;
    mDuration = duration;
    mStartTime = AnimationUtils.currentAnimationTimeMillis();
    mStartX = startX;    mStartY = startY;
    mFinalX = startX + dx; mFinalY = startY + dy;
    mDeltaX = dx;      mDeltaY = dy;
    ...
  }
} 

其中比较重要的两个方法为:

public boolean computeScrollOffset()
函数功能说明:根据当前已经消逝的时间计算当前的坐标点,保存在mCurrX和mCurrY值中。

public void startScroll(int startX, int startY, int dx, int dy, int duration)
函数功能说明:开始一个动画控制,由(startX , startY)在duration时间内前进(dx,dy)个单位,到达坐标为(startX+dx , startY+dy)处。

computeScroll()方法介绍:
为了易于控制滑屏控制,Android框架提供了 computeScroll()方法去控制这个流程。在绘制View时,会在draw()过程调用该方法。因此, 再配合使用Scroller实例,我们就可以获得当前应该的偏移坐标,手动使View/ViewGroup偏移至该处。
computeScroll()方法原型如下,该方法位于ViewGroup.java类中

/**
   * Called by a parent to request that a child update its values for mScrollX and mScrollY if necessary. This will typically be done if the child is animating a scroll using a {@link android.widget.Scroller Scroller}
   * object.
   * 由父视图调用用来请求子视图根据偏移值 mScrollX,mScrollY重新绘制 */
  public void computeScroll() { //空方法 ,自定义ViewGroup必须实现方法体
  } 

为了实现偏移控制,一般自定义View/ViewGroup都需要重载该方法 。其调用过程位于View绘制流程draw()过程中,如下:

@Override
protected void dispatchDraw(Canvas canvas){
  ... 

  for (int i = 0; i < count; i++) {
    final View child = children[getChildDrawingOrder(count, i)];
    if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
      more |= drawChild(canvas, child, drawingTime);
    }
  }
}
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
  ...
  child.computeScroll();
  ...
} 

实例演示

ViewPager相信每个人都再熟悉不过了,因此它实在是太常用了,我们可以借助ViewPager来轻松完成页面之间的滑动切换效果,但是如果问到它是如何实现的话,我感觉大部分人还是比较陌生的。其实说到ViewPager最基本的实现原理主要就是两部分内容,一个是事件分发,一个是Scroller。对于事件分发,不了解的同学可以参考我这篇博客Android事件的分发、拦截和执行。
接下来我将结合事件分发和Scroller来实现一个简易版的ViewPager。首先自定义一个ViewGroup,不了解的可以参考Android自定义ViewGroup(一)之CustomGridLayout这篇文章。平滑偏移的主要做法如下:

第一、调用Scroller实例去产生一个偏移控制(对应于startScroll()方法)
第二、手动调用invalid()方法去重新绘制,剩下的就是在computeScroll()里根据当前已经逝去的时间,获取当前应该偏移的坐标(由Scroller实例对应的computeScrollOffset()计算而得)
第三、当前应该偏移的坐标,调用scrollBy()方法去缓慢移动至该坐标处。

新建一个ScrollerLayout并让它继承自ViewGroup来作为我们的简易ViewPager布局,代码如下所示:

public class ScrollerLayout extends ViewGroup {

  private Scroller mScroller; //用于完成滚动操作的实例
  private VelocityTracker mVelocityTracker = null ; //处理触摸的速率
  public static int SNAP_VELOCITY = 600 ; //最小的滑动速率
  private int mTouchSlop = 0 ;      //最小滑动距离,超过了,才认为开始滑动
  private float mLastionMotionX = 0 ;  //上次触发ACTION_MOVE事件时的屏幕坐标
  private int curScreen = 0 ; //当前屏幕
  private int leftBorder;  //界面可滚动的左边界
  private int rightBorder; //界面可滚动的右边界

  //两种状态: 是否处于滑屏状态
  private static final int TOUCH_STATE_REST = 0; //什么都没做的状态
  private static final int TOUCH_STATE_SCROLLING = 1; //开始滑屏的状态
  private int mTouchState = TOUCH_STATE_REST; //默认是什么都没做的状态

  public ScrollerLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    // 创建Scroller的实例
    mScroller = new Scroller(context);
    //初始化一个最小滑动距离
    mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
      View childView = getChildAt(i);
      // 为ScrollerLayout中的每一个子控件测量大小
      measureChild(childView, widthMeasureSpec, heightMeasureSpec);
    }
  }

  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    if (changed) {
      int childCount = getChildCount();
      for (int i = 0; i < childCount; i++) {
        View childView = getChildAt(i);
        // 为ScrollerLayout中的每一个子控件在水平方向上进行布局
        childView.layout(i * childView.getMeasuredWidth(), 0, (i + 1) * childView.getMeasuredWidth(), childView.getMeasuredHeight());
      }
    }
    // 初始化左右边界值
    leftBorder = getChildAt(0).getLeft();
    rightBorder = getChildAt(getChildCount() - 1).getRight();
  }

  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    final int action = ev.getAction();
    //表示已经开始滑动了,不需要走该Action_MOVE方法了(第一次时可能调用)。
    //该方法主要用于用户快速松开手指,又快速按下的行为。此时认为是处于滑屏状态的。
    if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) {
      return true;
    }
    final float x = ev.getX();
    switch (action) {
      case MotionEvent.ACTION_MOVE:
        final int xDiff = (int) Math.abs(mLastionMotionX - x);
        //超过了最小滑动距离,就可以认为开始滑动了
        if (xDiff > mTouchSlop) {
          mTouchState = TOUCH_STATE_SCROLLING;
        }
        break;
      case MotionEvent.ACTION_DOWN:
        mLastionMotionX = x;
        mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;
        break;
      case MotionEvent.ACTION_CANCEL:
      case MotionEvent.ACTION_UP:
        mTouchState = TOUCH_STATE_REST;
        break;
    }
    return mTouchState != TOUCH_STATE_REST;
  }

  public boolean onTouchEvent(MotionEvent event){
    super.onTouchEvent(event);
    //获得VelocityTracker对象,并且添加滑动对象
    if (mVelocityTracker == null) {
      mVelocityTracker = VelocityTracker.obtain();
    }
    mVelocityTracker.addMovement(event);
    //触摸点
    float x = event.getX();
    switch(event.getAction()){
      case MotionEvent.ACTION_DOWN:
        //如果屏幕的动画还没结束,你就按下了,我们就结束上一次动画,即开始这次新ACTION_DOWN的动画
        if(mScroller != null){
          if(!mScroller.isFinished()){
            mScroller.abortAnimation();
          }
        }
        mLastionMotionX = x ; //记住开始落下的屏幕点
        break ;
      case MotionEvent.ACTION_MOVE:
        int detaX = (int)(mLastionMotionX - x ); //每次滑动屏幕,屏幕应该移动的距离
        if (getScrollX() + detaX < leftBorder) {  //防止用户拖出边界这里还专门做了边界保护,当拖出边界时就调用scrollTo()方法来回到边界位置
          scrollTo(leftBorder, 0);
          return true;
        } else if (getScrollX() + getWidth() + detaX > rightBorder) {
          scrollTo(rightBorder - getWidth(), 0);
          return true;
        }
        scrollBy(detaX, 0);//开始缓慢滑屏咯。 detaX > 0 向右滑动 , detaX < 0 向左滑动
        mLastionMotionX = x ;
        break ;
      case MotionEvent.ACTION_UP:
        final VelocityTracker velocityTracker = mVelocityTracker ;
        velocityTracker.computeCurrentVelocity(1000);
        //计算速率
        int velocityX = (int) velocityTracker.getXVelocity() ;
        //滑动速率达到了一个标准(快速向右滑屏,返回上一个屏幕) 马上进行切屏处理
        if (velocityX > SNAP_VELOCITY && curScreen > 0) {
          // Fling enough to move left
          snapToScreen(curScreen - 1);
        }
        //快速向左滑屏,返回下一个屏幕
        else if(velocityX < -SNAP_VELOCITY && curScreen < (getChildCount()-1)){
          snapToScreen(curScreen + 1);
        }
        //以上为快速移动的 ,强制切换屏幕
        else{
          //我们是缓慢移动的,因此先判断是保留在本屏幕还是到下一屏幕
          snapToDestination();
        }
        //回收VelocityTracker对象
        if (mVelocityTracker != null) {
          mVelocityTracker.recycle();
          mVelocityTracker = null;
        }
        //修正mTouchState值
        mTouchState = TOUCH_STATE_REST ;
        break;
      case MotionEvent.ACTION_CANCEL:
        mTouchState = TOUCH_STATE_REST ;
        break;
    }
    return true ;
  }

  //我们是缓慢移动的,因此需要根据偏移值判断目标屏是哪个
  private void snapToDestination(){
    //判断是否超过下一屏的中间位置,如果达到就抵达下一屏,否则保持在原屏幕
    //公式意思是:假设当前滑屏偏移值即 scrollCurX 加上每个屏幕一半的宽度,除以每个屏幕的宽度就是我们目标屏所在位置了。
    int destScreen = (getScrollX() + getWidth() / 2 ) / getWidth() ;
    snapToScreen(destScreen);
  }

  //真正的实现跳转屏幕的方法
  private void snapToScreen(int whichScreen){
    //简单的移到目标屏幕,可能是当前屏或者下一屏幕,直接跳转过去,不太友好,为了友好性,我们在增加一个动画效果
    curScreen = whichScreen ;
    //防止屏幕越界,即超过屏幕数
    if(curScreen > getChildCount() - 1)
      curScreen = getChildCount() - 1 ;
    //为了达到下一屏幕或者当前屏幕,我们需要继续滑动的距离.根据dx值,可能向左滑动,也可能向右滑动
    int dx = curScreen * getWidth() - getScrollX() ;
    mScroller.startScroll(getScrollX(), 0, dx, 0, Math.abs(dx) * 2);
    //由于触摸事件不会重新绘制View,所以此时需要手动刷新View 否则没效果
    invalidate();
  }

  @Override
  public void computeScroll() {
    //重写computeScroll()方法,并在其内部完成平滑滚动的逻辑
    if (mScroller.computeScrollOffset()) {
      scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
      invalidate();
    }
  }
}

代码比较长,但思路比较清晰。
(1)首先在ScrollerLayout的构造函数里面我们创建Scroller的实例,由于Scroller的实例只需创建一次,因此我们把它放到构造函数里面执行。另外在构建函数中我们还初始化的TouchSlop的值,这个值在后面将用于判断当前用户的操作是否是拖动。
(2)接着重写onMeasure()方法和onLayout()方法,在onMeasure()方法中测量ScrollerLayout里的每一个子控件的大小,在onLayout()方法中为ScrollerLayout里的每一个子控件在水平方向上进行布局,布局类似于方向为horizontal的LinearLayout。
(3) 接着重写onInterceptTouchEvent()方法, 在这个方法中我们记录了用户手指按下时的X坐标位置,以及用户手指在屏幕上拖动时的X坐标位置,当两者之间的距离大于TouchSlop值时,就认为用户正在拖动布局,置状态为TOUCH_STATE_SCROLLING,当用户手指抬起,重置状态为TOUCH_STATE_REST。这里当状态值为TOUCH_STATE_SCROLLING时返回true,将事件在这里拦截掉,阻止事件传递到子控件当中。
(4)那么当我们把事件拦截掉之后,就会将事件交给ScrollerLayout的onTouchEvent()方法来处理。
如果当前事件是ACTION_MOVE,说明用户正在拖动布局,那么我们就应该对布局内容进行滚动从而影响拖动事件,实现的方式就是使用我们刚刚所学的scrollBy()方法,用户拖动了多少这里就scrollBy多少。另外为了防止用户拖出边界这里还专门做了边界保护,当拖出边界时就调用scrollTo()方法来回到边界位置。
如果当前事件是ACTION_UP时,说明用户手指抬起来了,但是目前很有可能用户只是将布局拖动到了中间,我们不可能让布局就这么停留在中间的位置,因此接下来就需要借助Scroller来完成后续的滚动操作。首先计算滚动速率,判断当前动作是scroll还是fling。如果是fling,再根据fling的方向跳转到上一页或者下一页,调用函数snapToScreen。如果是scroll,就调用函数snapToDestination,函数中首先根据当前的滚动位置来计算布局应该继续滚动到哪一页,滚动到哪一页同样调用snapToScreen。再来看看snapToScreen写法吧,其实是调用startScroll()方法来滚动数据,紧接着调用invalidate()方法来刷新界面。
(5)重写computeScroll()方法,并在其内部完成平滑滚动的逻辑 。在整个后续的平滑滚动过程中,computeScroll()方法是会一直被调用的,因此我们需要不断调用Scroller的computeScrollOffset()方法来进行判断滚动操作是否已经完成了,如果还没完成的话,那就继续调用scrollTo()方法,并把Scroller的curX和curY坐标传入,然后刷新界面从而完成平滑滚动的操作。

现在ScrollerLayout已经准备好了,接下来我们修改activity_main.xml布局中的内容,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<com.hx.scroller.ScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <ImageView
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="@drawable/crazy_1" />

  <ImageView
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="@drawable/crazy_2" />

  <ImageView
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="@drawable/crazy_3" />

</com.hx.scroller.ScrollerLayout>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索android
Scroller
android scroller、android scroller详解、android overscroller、android scroller使用、android scrollerview,以便于您获取更多的相关知识。

时间: 2024-10-01 04:30:46

Android Scroller完全解析_Android的相关文章

详解Android OkHttp完全解析_Android

一.概述 最近在群里听到各种讨论okhttp的话题,可见okhttp的口碑相当好了.再加上Google貌似在6.0版本里面删除了HttpClient相关API,对于这个行为不做评价.为了更好的在应对网络访问,学习下okhttp还是蛮必要的,本篇博客首先介绍okhttp的简单使用,主要包含: 一般的get请求 一般的post请求 基于Http的文件上传 文件下载 加载图片 支持请求回调,直接返回对象.对象集合 支持session的保持 最后会对上述几个功能进行封装,完整的封装类的地址见:http:

Android Notification通知解析_Android

Notification是显示在手机状态栏的通知,Notification通知是具有全局性的通知,一般通过NotificationManager来进行管理. 一般运用Notification的步骤如下: 1.调用getSysytemService(NOTIFICATION_SERVICE)来获取系统的NotificationManager,进行Notification的发送和回收 2.通过构造器建立一个Notification 3.为Notification set各种属性,然后builder(

Android Scroller完全解析

在Android中,任何一个控件都是可以滚动的,因为在View类当中有scrollTo()和scrollBy()这两个方法,如下图所示: 这两个方法的主要作用是将View/ViewGroup移至指定的坐标中,并且将偏移量保存起来.另外: mScrollX 代表X轴方向的偏移坐标 mScrollY 代表Y轴方向的偏移坐标 这两个方法都是用于对View进行滚动的,那么它们之间有什么区别呢?简单点讲,scrollBy()方法是让View相对于当前的位置滚动某段距离,而scrollTo()方法则是让Vi

Android PopupWindow用法解析_Android

PopupWindow使用PopupWindow这个类用来实现一个弹出框,可以使用任意布局的View作为其内容,这个弹出框是悬浮在当前activity之上的.  PopupWindow使用Demo这个类的使用,不再过多解释,直接上代码吧. 比如弹出框的布局:  <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android

详解android使用SAX解析XML文件_Android

解析XML的方式有很多种,大家比较熟悉的可能就是DOM解析. DOM(文件对象模型)解析:解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以根据DOM接口来操作这个树结构了. 优点:整个文档读入内存,方便操作:支持修改.删除和重现排列等多种功能. 缺点:将整个文档读入内存中,保留了过多的不需要的节点,浪费内存和空间. 使用场合:一旦读入文档,还需要多次对文档进行操作,并且在硬件资源充足的情况下(内存,CPU). 为了解决DOM解析存在的问题,就出现了SAX解析.其特点为: 优点:不

Android利用Gson解析嵌套多层的Json的简单方法_Android

首先先讲一个比较简单点的例子(最简单的我就不讲啦,网上很多),帮助新手理解Gson的使用方法: 比如我们要解析一个下面这种的Json: String json = {"a":"100", "b":[{"b1":"b_value1","b2":"b_value2"}, {"b1":"b_value1","b2"

Android使用Jsoup解析Html表格的方法_Android

本文实例讲述了Android使用Jsoup解析Html表格的方法.分享给大家供大家参考,具体如下: 看代码吧,可解析表中的label text button 自己根据需要再添加,呵呵 import java.util.ArrayList; import java.util.List; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import org.jsoup.J

Android 创建与解析XML(四)——详解Pull方式_Android

 1.Pull概述 Android系统中和创建XML相关的包为org.xmlpull.v1,在这个包中不仅提供了用于创建XML的 XmlSerializer,还提供了用来解析XML的Pull方式解析器 XmlPullParser XmlSerializer没有像XmlPullParser那样提取XML事件,而是把它们推出到数据流OutputStream或Writer中. XmlSerializer提供了很直观的API,即使用startDocument开始文档,endDocument结束文档,st

Android 创建与解析XML(五)——详解Dom4j方式_Android

1.Dom4j概述 dom4j is an easy to use, open source library for working with XML, XPath and XSLT on the Java platform using the Java Collections Framework and with full support for DOM, SAX and JAXP. dom4j官方网址:dom4j  dom4j源码下载:dom4j download 本示例中,需要导入dom4