Friday, June 22, 2012

Sax Parser example in Android

There are 2 ways to parse an xml in android. SAX an DOM. The DOM parser loads the whole document into memory before it can work with it, which can be slow and uses up a lot more memory - the benefit is that you're not writing as much code. So in mobile environment we are not using commonly this method for parsing xml.But in  SAX , it goes through each element and attribute one at a time, and you can pick and choose which one you want added into memory, but you do need to write a lot more code.  So this one is used in android for parsing. Here find an simple example for implementing this.
 
public static Login parse(String xml) throws Exception {
 LoginHandler handler = new LoginHandler();
 Xml.parse(xml ,handler);
 return handler.tempItem;
}

public static class LoginHandler extends DefaultHandler {

  private static final String RESPONSE = "response";
  private static final String STATUS = "result";
  private static final String CSRF = "_csrf";
  private static final String USER_TOKEN = "user_token"; 

  Login tempItem;
  private StringBuilder builder;

  @Override
  public void characters(char[] ch, int start, int length)
    throws SAXException {
   super.characters(ch, start, length);
   builder.append(ch, start, length);
  }

                // taking upto </tag> position.
  @Override
  public void endElement(String uri, String localName, String qName)
    throws SAXException {
   super.endElement(uri, localName, qName);
   if (this.tempItem != null) {
    if (localName.equalsIgnoreCase(STATUS)) {
      tempItem.setStatus(builder.toString().trim());
    }
   }
    builder.setLength(0);
  }

  @Override
  public void error(SAXParseException e) throws SAXException {
   super.error(e);
  }

  @Override
  public void fatalError(SAXParseException e) throws SAXException {
   super.fatalError(e);
  }

  @Override
  public void startDocument() throws SAXException {
   super.startDocument();
   builder = new StringBuilder();
  }
                // taking start position <response _csrf="456465" user_token="4557897">
  @Override
  public void startElement(String uri, String localName, String qName,
    Attributes attributes) throws SAXException {
   builder.setLength(0);
   super.startElement(uri, localName, qName, attributes);
   if (localName.equalsIgnoreCase(RESPONSE)) {
       tempItem = new Login();
                            // taking attributes value    
                            tempItem.setCsrf(attributes.getValue(CSRF));
                            tempItem.setUser_token(attributes.getValue(USER_TOKEN));
   }
  }

 }

public class Login {

 private String csrf = "";
 public String getUser_token() {
  return user_token;
 }

 public void setUser_token(String user_token) {
  this.user_token = user_token;
 }

 private String status = "";
 private String user_token = "";

 public String getCsrf() {
  return csrf;
 }

 public void setCsrf(String csrf) {
  this.csrf = csrf;
 }

 public String getStatus() {
  return status;
 }

 public void setStatus(String status) {
  this.status = status;
 }

}

Monday, June 18, 2012

Implementing multiple links in same textview android

Sometimes we need to create a textview with 2 separate links or we need to show different colors in different parts of the same textview. In a normal textview we cant implement it directly.  In order to attain this we using spannable textviews.  In this we splitting text in to different parts and implement the different changes. Take an example below.


 
 Textview mCommentTxt = (TextView) findViewById(R.id.contentTxt);
 MovementMethod m = holder.mCommentTxt.getMovementMethod();
 if ((m == null) || !(m instanceof LinkMovementMethod)) {
     holder.mCommentTxt.setMovementMethod(LinkMovementMethod.getInstance());
 }

 String content = String .format("##%s## checked-in $$%s$$", "username" ,"values");
 mCommentTxt.setText(content);
 CharSequence txt = holder.mCommentTxt.getText();
  String bgColor = "#E6E6E6"; 
txt = setSpanBetweenTokens(txt, "##", new   ForegroundColorSpan(Color.parseColor(bgColor)),
    new BackgroundColorSpan(Color.parseColor(bgColor)), new ClickableSpan() {
 @Override
 public void onClick(View v) {
  // Onclick listner
 }
 @Override
 public void updateDrawState(TextPaint ds) {
     ds.setColor(Color.parseColor("#4866a3"));
     ds.setUnderlineText(false);// set to false to remove underline 
     ds.setTypeface(Typeface.DEFAULT_BOLD);
 }
 });
 txt = setSpanBetweenTokens(txt, "$$", new ForegroundColorSpan(Color.WHITE ),      new BackgroundColorSpan(Color.parseColor(bgColor)),new ClickableSpan() {
 @Override
 public void onClick(View v) {
         // Onclick listener  
 }
 @Override
        public void updateDrawState(TextPaint ds) {
           ds.setColor(Color.parseColor("#4866a3"));
           ds.setUnderlineText(false); // set to false to remove underline
           ds.setTypeface(Typeface.DEFAULT_BOLD);
        }
 });
    
 mCommentTxt.setText( txt );
 
public static CharSequence setSpanBetweenTokens(CharSequence text, String token, CharacterStyle... cs) {
 int tokenLen = token.length();
 int start = text.toString().indexOf(token) + tokenLen;
 int end = text.toString().indexOf(token, start);
 if (start > -1 && end > -1) {
         SpannableStringBuilder ssb = new SpannableStringBuilder(text);
  for (CharacterStyle c : cs){
   ssb.setSpan(c, start, end, 0);
  }
         ssb.delete(end, end + tokenLen);
         ssb.delete(start - tokenLen, start);
         text = ssb;
 }
        return text;
}

Sunday, June 3, 2012

Pull to refresh in Android

“Pull To Refresh” is a UI gesture made popular by the Twitter for Iphone app. It allows a user to refresh a list by pulling down and releasing from the top of the list. IOS developers have had library support for this feature for some time now. Over in Android-land, only the official Twitter app has managed to implement this gesture. Long-promised to be open-sourced, Twitter’s solution is still secret and Android developers have no official means to implement this increasingly demanded feature.


Its not my own library. I don't know who is written this library.    But i think it will help u more than when compared to other libraries.   Here they implemented via frame layout and a list view. dragging and releasing part has done inside the frame layout. Check an example below.
 

 

            
            
        
       
    
In xml file ....
 
package com.example.helpers;

import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Scroller;
import android.widget.TextView;

import com.example.R;

public class PullToRefresh extends FrameLayout implements
  GestureDetector.OnGestureListener {
 public static final int STATE_CLOSE = 1;
 public static final int STATE_OPEN = 2;
 public static final int STATE_OPEN_MAX = 4;
 public static final int STATE_OPEN_MAX_RELEASE = 5;
 public static final int STATE_OPEN_RELEASE = 3;
 public static final int STATE_UPDATE = 6;
 public static final int STATE_UPDATE_SCROLL = 7;
 private final int MAXHEIGHT = 100;
// private final String TAG = "PullToRefresh";

 private ImageView mArrow;
 private String mDate;
 private GestureDetector mDetector;
 private Flinger mFlinger;
 private boolean mIsAutoScroller;
 private int mPading;
 private ProgressBar mProgressBar;
 private int mState;
 private TextView mTitle;
 private FrameLayout mUpdateContent;

 private UpdateHandle mUpdateHandle;

 private RotateAnimation mFlipAnimation;
 private RotateAnimation mReverseFlipAnimation;
 private Context ctx;

 public PullToRefresh(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  this.ctx = context;
  addUpdateBar();
  init();
 }

 public PullToRefresh(Context context, AttributeSet attrs) {
  super(context, attrs);
  this.ctx = context;
  addUpdateBar();
  init();
 }

 public PullToRefresh(Context context) {
  super(context);
  this.ctx = context;
  addUpdateBar();
  init();
 }

 // private void init() {
 // MAX_LENGHT = getResources().getDimensionPixelSize(
 // R.dimen.updatebar_height);
 // setDrawingCacheEnabled(true);
 // // setBackgroundDrawable(null);
 // setClipChildren(true);
 // this.mDetector.setIsLongpressEnabled(false);
 // }
 @Override
 public boolean dispatchTouchEvent(MotionEvent ev) {
  
  boolean bool1 = this.mIsAutoScroller;
  GestureDetector localGestureDetector = this.mDetector;

  localGestureDetector.onTouchEvent(ev);
  switch (ev.getAction()) {
  case MotionEvent.ACTION_MOVE:
   int i1 = getChildAt(1).getTop();
   if (i1 != 0) {
    updateView();
   }

   break;
  case MotionEvent.ACTION_UP:

   if (this.mState == STATE_OPEN) {
    this.mState = STATE_OPEN_RELEASE;
   }
   if (this.mState == STATE_OPEN_MAX) {
    this.mState = STATE_OPEN_MAX_RELEASE;
   }
  
   release();
   break;
  }
  if (mState != STATE_UPDATE) {
   bool1 = super.dispatchTouchEvent(ev);
  }

  int i1 = getChildAt(1).getTop();
  if (i1 != 0) {
   ev.setAction(3);
   super.dispatchTouchEvent(ev);
   updateView();
  }
  return bool1;
 }

 private void init() {
  GestureDetector localGestureDetector = new GestureDetector(this);
  this.mDetector = localGestureDetector;
  Flinger localFlinger = new Flinger();
  this.mFlinger = localFlinger;
  this.mState = 1;
  setDrawingCacheEnabled(true);
  setClipChildren(true);
  this.mDetector.setIsLongpressEnabled(false);
 }

 private void updateView() {
  View localView1 = getChildAt(0);
  View localView2 = getChildAt(1);
  if (this.mDate == null)
   this.mDate = "";

  switch (this.mState) {
  case STATE_CLOSE:
   if (localView1.getVisibility() != View.INVISIBLE)
    localView1.setVisibility(View.INVISIBLE);
  case STATE_OPEN:
  case STATE_OPEN_RELEASE:
   // STATE_OPEN
   int m = localView2.getTop();
   int n = -this.mPading - m;

   localView2.offsetTopAndBottom(n);
   if (localView1.getVisibility() != 0)
    localView1.setVisibility(View.VISIBLE);
   int i1 = localView1.getTop();// 相对于父窗�的顶部大�
   int i2 = -MAXHEIGHT;
   int i3 = this.mPading;
   int i4 = i2 - i3 - i1;
   localView1.offsetTopAndBottom(i4);
   TextView localTextView1 = this.mTitle;
   String str1 = ctx.getText(R.string.update_when_release_the_finger).toString();
   StringBuilder localStringBuilder1 = new StringBuilder(str1)
     .append("\n");
   // String str2 = this.mDate;
   // String str3 = str2;
   localStringBuilder1.append(this.mDate);
   localTextView1.setText(localStringBuilder1.toString());
   this.mProgressBar.setVisibility(View.INVISIBLE);
   this.mArrow.setVisibility(View.VISIBLE);

   break;
  case STATE_OPEN_MAX_RELEASE:
  case STATE_OPEN_MAX:
   // STATE_OPEN_MAX
   int i5 = localView2.getTop();
   int i6 = -this.mPading - i5;
   localView2.offsetTopAndBottom(i6);
   if (localView1.getVisibility() != View.VISIBLE)
    localView1.setVisibility(View.VISIBLE);
   int i7 = localView1.getTop();
   int i8 = -MAXHEIGHT;
   int i9 = this.mPading;
   int i10 = i8 - i9 - i7;
   localView1.offsetTopAndBottom(i10);
   TextView localTextView2 = this.mTitle;
   String str4 = ctx.getText(R.string.update_when_release_the_finger).toString();// release_update:
   StringBuilder localStringBuilder2 = new StringBuilder(str4).append("\n");

   localStringBuilder2.append(this.mDate);
   localTextView2.setText(localStringBuilder2.toString());

   this.mProgressBar.setVisibility(View.INVISIBLE);
   this.mArrow.setVisibility(View.VISIBLE);

   break;
  case STATE_UPDATE:
   // STATE_UPDATE
   int i11 = localView2.getTop();
   int i12 = -this.mPading - i11;
   localView2.offsetTopAndBottom(i12);
   int i13 = localView1.getTop();
   if (this.mProgressBar.getVisibility() != View.VISIBLE)
    this.mProgressBar.setVisibility(View.VISIBLE);
   if (this.mArrow.getVisibility() != View.INVISIBLE)
    this.mArrow.setVisibility(View.INVISIBLE);
   TextView localTextView3 = this.mTitle;
   String str7 = ctx.getString(R.string.updating).toString();// doing_update:加载中...
   StringBuilder localStringBuilder3 = new StringBuilder(str7)
     .append("\n");

   localStringBuilder3.append(this.mDate);
   localTextView3.setText(localStringBuilder3.toString());
   int i14 = -MAXHEIGHT;
   int i15 = this.mPading;
   int i16 = i14 - i15 - i13;
   localView1.offsetTopAndBottom(i16);
   if (localView1.getVisibility() != 0)
    localView1.setVisibility(0);
   this.mProgressBar.setVisibility(View.VISIBLE);
   this.mArrow.setVisibility(View.GONE);
   mArrow.clearAnimation();
   break;
  }
  invalidate();
 }

 private void addUpdateBar() {
  Context localContext1 = getContext();
  mFlipAnimation = new RotateAnimation(0, -180,
    Animation.RELATIVE_TO_SELF, 0.5f,
    Animation.RELATIVE_TO_SELF, 0.5f);
  mFlipAnimation.setInterpolator(new LinearInterpolator());
  mFlipAnimation.setDuration(200);
  mFlipAnimation.setFillAfter(true);
  mReverseFlipAnimation = new RotateAnimation(-180, 0,
    Animation.RELATIVE_TO_SELF, 0.5f,
    Animation.RELATIVE_TO_SELF, 0.5f);
  mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
  mReverseFlipAnimation.setDuration(200);
  mReverseFlipAnimation.setFillAfter(true);

  View localView = LayoutInflater.from(localContext1).inflate(
    R.layout.vw_update_bar, null);
  localView.setVisibility(4);
  addView(localView);

  this.mArrow = new ImageView(localContext1);

  FrameLayout.LayoutParams localLayoutParams1 = new FrameLayout.LayoutParams(
    android.view.ViewGroup.LayoutParams.FILL_PARENT,
    android.view.ViewGroup.LayoutParams.FILL_PARENT);
  ImageView localImageView2 = this.mArrow;
  ImageView.ScaleType localScaleType = ImageView.ScaleType.FIT_CENTER;
  localImageView2.setScaleType(localScaleType);
  this.mArrow.setLayoutParams(localLayoutParams1);
  this.mArrow.setImageResource(R.drawable.arrow_down);

  this.mUpdateContent = (FrameLayout) getChildAt(0).findViewById(
    R.id.iv_content);
  FrameLayout localFrameLayout2 = this.mUpdateContent;
  localFrameLayout2.addView(this.mArrow);
  FrameLayout.LayoutParams localLayoutParams2 = new FrameLayout.LayoutParams(
    android.view.ViewGroup.LayoutParams.FILL_PARENT,
    android.view.ViewGroup.LayoutParams.FILL_PARENT);
  localLayoutParams2.gravity = Gravity.CENTER_VERTICAL;
  this.mProgressBar = new ProgressBar(localContext1);
  int i = getResources().getDimensionPixelSize(R.dimen.progress_padding);
  this.mProgressBar.setPadding(i, i, i, i);
  this.mProgressBar.setLayoutParams(localLayoutParams2);

  this.mUpdateContent.addView(mProgressBar);
  this.mTitle = (TextView) findViewById(R.id.tv_title);
 }

 @Override
 protected void onLayout(boolean paramBoolean, int paramInt1, int paramInt2,
   int paramInt3, int paramInt4) {
  View localView1 = getChildAt(0);
  int i = -MAXHEIGHT;
  int j = this.mPading;
  int k = i - j;
  int l = getMeasuredWidth();
  int i1 = -this.mPading;
  localView1.layout(0, k, l, i1);

  View localView2 = getChildAt(1);
  int i2 = -this.mPading;
  int i3 = getMeasuredWidth();
  int i4 = getMeasuredHeight();
  int i5 = this.mPading;
  int i6 = i4 - i5;
  localView2.layout(0, i2, i3, i6);
 }

 public void endUpdate(String paramString) {
  this.mDate = paramString;
  if (this.mPading != 0) {
   this.mState = STATE_CLOSE;
   scrollToClose();
  }
 }

 @Override
 public boolean onDown(MotionEvent e) {
  return false;
 }

 @Override
 public void onShowPress(MotionEvent e) {

 }

 @Override
 public boolean onSingleTapUp(MotionEvent e) {
  return false;
 }

 @Override
 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
   float distanceY) {
  @SuppressWarnings("rawtypes")
  AdapterView localAdapterView = (AdapterView) getChildAt(1);
  int k = localAdapterView.getCount();
  if (k == 0) {
   return false;
  }
  k = localAdapterView.getFirstVisiblePosition();// 获�第一个显示项目的position
  if (k == 0) {
   int t = localAdapterView.getChildAt(0).getTop();
   if (t != 0) {
    return false;
   } else {

    this.mPading = (int) (this.mPading + distanceY / 2);

    if (this.mPading > 0)
     this.mPading = 0;
    // if (distanceY < 0) {

    if (Math.abs(this.mPading) <= MAXHEIGHT) {
     this.mState = STATE_OPEN;

    } else {
     this.mState = STATE_OPEN_MAX;

    }

    // }
    updateView();

   }
  }
  return false;
 }

 @Override
 public void onLongPress(MotionEvent e) {

 }

 @Override
 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
   float velocityY) {
  return false;
 }

 @SuppressWarnings("unused")
 private int getScrollRange() {
  int scrollRange = 0;
  if (getChildCount() > 0) {
   View child = getChildAt(0);
   scrollRange = Math.max(0,child.getHeight() - (getHeight() - this.getBottomPaddingOffset() - this .getTopPaddingOffset()));
  }
  return scrollRange;
 }

 private boolean release() {
  int tempStatus = STATE_OPEN_MAX_RELEASE;
  int i = this.mPading;
  if (i >= 0) {
   return true;
  }
  int j = this.mState;
  switch (j) {
  case STATE_OPEN_RELEASE:
   int k = Math.abs(this.mPading);
   int i1 = MAXHEIGHT;
   if (k < i1) {
    tempStatus = STATE_OPEN_MAX_RELEASE;
    this.mState = tempStatus;
   }
   scrollToClose();
   break;
  case STATE_OPEN_MAX_RELEASE:

   this.mState = tempStatus;
   scrollToUpdate();
   break;
  }
  return false;
 }

 private void scrollToClose() {
  Flinger localFlinger = this.mFlinger;
  int i = -this.mPading;
  localFlinger.startUsingDistance(i, 300);
 }

 private void scrollToUpdate() {
  Flinger localFlinger = this.mFlinger;

  int k = -this.mPading - MAXHEIGHT;
  localFlinger.startUsingDistance(k, 300);
 }

 class Flinger implements Runnable {
  private int mLastFlingX;
  private Scroller mScroller;

  public Flinger() {
   Context localContext = PullToRefresh.this.getContext();
   Scroller localScroller = new Scroller(localContext);
   this.mScroller = localScroller;
  }

  private void startCommon() {
   PullToRefresh.this.removeCallbacks(this);
  }

  @Override
  public void run() {
   boolean bool1 = Math.abs(mPading) != MAXHEIGHT;
   Scroller localScroller = this.mScroller;
   boolean bool2 = localScroller.computeScrollOffset();
   int i = localScroller.getCurrX();
   int j = this.mLastFlingX - i;
   PullToRefresh localPullDownView = PullToRefresh.this;

   localPullDownView.move(j, bool1);
   PullToRefresh.this.updateView();
   if (bool2) {
    this.mLastFlingX = i;
    PullToRefresh.this.post(this);
   } else {
    PullToRefresh.this.mIsAutoScroller = bool1;
    PullToRefresh.this.removeCallbacks(this);
   }
  }

  public void startUsingDistance(int paramInt1, int paramInt2) {
   int i = 0;
   if (paramInt1 == 0)
    --paramInt1;
   startCommon();
   this.mLastFlingX = i;
   Scroller localScroller = this.mScroller;

   localScroller.startScroll(i, 0, -paramInt1, 0, paramInt2);
   PullToRefresh.this.mIsAutoScroller = true;
   PullToRefresh.this.post(this);
  }
 }

 /**
  * 
  * 
  * @param f
  * @param bool1
  */
 public void move(float f, boolean bool1) {
  if (this.mState != STATE_CLOSE) {
   if (!bool1) {
    // 刷新
    if (mState == STATE_OPEN_MAX_RELEASE) {
     this.mState = STATE_UPDATE;
     if (mUpdateHandle != null) {
      mUpdateHandle.onUpdate();
     }
    }
   }
   if (this.mState == STATE_OPEN_MAX_RELEASE
     || this.mState == STATE_OPEN_RELEASE) {
    this.mPading += f;

   }
  } else {
   if (mIsAutoScroller) {
    this.mPading += f;
   }
  }

 }

 public abstract interface UpdateHandle {
  public abstract void onUpdate();
 }

 public void setUpdateDate(String paramString) {
  this.mDate = paramString;
 }

 public void setUpdateHandle(UpdateHandle paramUpdateHandle) {
  this.mUpdateHandle = paramUpdateHandle;
 }

 // public void update()
 // {
 // int i = -MAXHEIGHT;
 // this.mPading = i;
 // this.mState = 7;
 // }

 public void updateWithoutOffset() {
  this.mState = STATE_UPDATE_SCROLL;
  invalidate();
 }

}
Values for the strings.
Refresh
    Updating ...
    Last Updated : 
    Release to update..
vw_update_bar layout xml.



    

        
        

        
        
    

    
    


dimension.xml used



 120px
 120px
 20px
 10px
 
 

Update activity class as follows.
package com.example

public class Home extends Activity implements PullToRefresh.UpdateHandle {
private PullToRefresh refresh;
@Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
                refresh = (PullToRefresh) findViewById(R.id.pullDownView1);
  refresh.setUpdateHandle(this);
                // .....
        }
//...
        @Override
 public void onUpdate() {
  // Update call .. do the need ful for updating.
 }
//....
 private final Handler handler = new Handler(Looper.getMainLooper()) {
  @Override
  public void handleMessage(Message msg) {
   refresh.endUpdate(getString(R.string.pulltorefreshhandle_text) + getTime());
  }
 };


}
After adding adapter values means child items to the list view then call this method to finish update.
Message msg = handler.obtainMessage();
handler.sendMessage(msg);