分类归档 Android

通过admin

Android实现多页左右滑动效果,支持子view动态创建和cache

要实现多页滑动效果,主要是需要处理onTouchEvent和onInterceptTouchEvent,要处理好touch事件的子控件和父控件的传递问题。滚动控制可以利用android的Scroller来实现。

对于不清楚android Touch事件的传递过程的,先google一下。

这里提供两种做法:

1、自定义MFlipper控件,从ViewGroup继承,利用Scroller实现滚动,重点是onTouchEvent和onInterceptTouchEvent的重写,要注意什么时候该返回true,什么时候false。否则会导致界面滑动和界面内按钮点击事件相冲突。

由于采用了ViewGroup来管理子view,只适合于页面数较少而且较固定的情况,因为viewgroup需要一开始就调用addView,把所有view都加进去并layout,太多页面会有内存问题。如果是页面很多,而且随时动态增长的话,就需要考虑对view做cache和动态创建,动态layout,具体做法参考下面的方法二;

 

2、从AdapterView继承,参考Android自带ListView的实现,实现子view动态创建和cache,滑动效果等。源码如下:

import android.content.Context;

import android.util.AttributeSet;

import android.util.Log;

import android.util.SparseArray;

import android.view.MotionEvent;

import android.view.VelocityTracker;

import android.view.View;

import android.view.ViewConfiguration;

import android.view.ViewGroup;

import android.widget.AdapterView;

import android.widget.BaseAdapter;

import android.widget.Gallery;

import android.widget.Scroller;

 

/**

* 自定义一个横向滚动的AdapterView,类似与全屏的Gallery,但是一次只滚动一屏,而且每一屏支持子view的点击处理

* @author weibinke

*

*/

public class MultiPageSwitcher extends AdapterView<BaseAdapter> {

 

private BaseAdapter mAdapter = null;

private Scroller mScroller;

private int mTouchSlop;

private float mTouchStartX;

private float mLastMotionX;

private final static String TAG = “MultiPageSwitcher”;

 

private int mLastScrolledOffset = 0;

 

/** User is not touching the list */

private static final int TOUCH_STATE_RESTING = 0;

 

/** User is scrolling the list */

private static final int TOUCH_STATE_SCROLL = 2;

 

private int mTouchState = TOUCH_STATE_RESTING;

private int mHeightMeasureSpec;

private int mWidthMeasureSpec;

private int mSelectedPosition;

private int mFirstPosition;                                //第一个可见view的position

private int mCurrentSelectedPosition;

 

private VelocityTracker mVelocityTracker;

private static final int SNAP_VELOCITY = 600;

 

protected RecycleBin mRecycler = new RecycleBin();

 

private OnPostionChangeListener mOnPostionChangeListener = null;

 

public MultiPageSwitcher(Context context, AttributeSet attrs) {

super(context, attrs);

mScroller = new Scroller(context);

mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

}

 

@Override

protected void onLayout(boolean changed, int left, int top, int right,

int bottom) {

// TODO Auto-generated method stub

MLog.d(“MultiPageSwitcher.onlayout start”);

super.onLayout(changed, left, top, right, bottom);

 

if (mAdapter == null) {

return ;

}

 

recycleAllViews();

detachAllViewsFromParent();

mRecycler.clear();

 

fillAllViews();

 

MLog.d(“MultiPageSwitcher.onlayout end”);

}

 

/**

* 从当前可见的view向左边填充

*/

private void fillToGalleryLeft() {

int itemSpacing = 0;

int galleryLeft = 0;

// Set state for initial iteration

View prevIterationView = getChildAt(0);

int curPosition;

int curRightEdge;

if (prevIterationView != null) {

curPosition = mFirstPosition – 1;

curRightEdge = prevIterationView.getLeft() – itemSpacing;

} else {

// No children available!

curPosition = 0;

curRightEdge = getRight() – getLeft();

}

while (curRightEdge > galleryLeft && curPosition >= 0) {

prevIterationView = makeAndAddView(curPosition, curPosition – mSelectedPosition,

curRightEdge, false);

 

// Remember some state

mFirstPosition = curPosition;

// Set state for next iteration

curRightEdge = prevIterationView.getLeft() – itemSpacing;

curPosition–;

}

}

private void fillToGalleryRight() {

int itemSpacing = 0;

int galleryRight = getRight() – getLeft();

int numChildren = getChildCount();

int numItems = mAdapter.getCount();

// Set state for initial iteration

View prevIterationView = getChildAt(numChildren – 1);

int curPosition;

int curLeftEdge;

if (prevIterationView != null) {

curPosition = mFirstPosition + numChildren;

curLeftEdge = prevIterationView.getRight() + itemSpacing;

} else {

mFirstPosition = curPosition = numItems – 1;

curLeftEdge = 0;

}

while (curLeftEdge < galleryRight && curPosition < numItems) {

prevIterationView = makeAndAddView(curPosition, curPosition – mSelectedPosition,

curLeftEdge, true);

 

// Set state for next iteration

curLeftEdge = prevIterationView.getRight() + itemSpacing;

curPosition++;

}

}

 

/**

*填充view

*/

private void fillAllViews(){

//先创建第一个view,使其居中显示

if (mSelectedPosition >= mAdapter.getCount()&& mSelectedPosition > 0) {

//处理被记录被删除导致当前选中位置超出记录数的情况

mSelectedPosition = mAdapter.getCount() – 1;

if(mOnPostionChangeListener != null){

mCurrentSelectedPosition = mSelectedPosition;

mOnPostionChangeListener.onPostionChange(this, mCurrentSelectedPosition);

}

}

 

mFirstPosition = mSelectedPosition;

mCurrentSelectedPosition = mSelectedPosition;

 

View child = makeAndAddView(mSelectedPosition, 0, 0, true);

 

int offset = getWidth() / 2 – (child.getLeft() + child.getWidth() / 2);

child.offsetLeftAndRight(offset);

 

fillToGalleryLeft();

fillToGalleryRight();

 

}

 

/**

* Obtain a view, either by pulling an existing view from the recycler or by

* getting a new one from the adapter. If we are animating, make sure there

* is enough information in the view’s layout parameters to animate from the

* old to new positions.

*

* @param position Position in the gallery for the view to obtain

* @param offset Offset from the selected position

* @param x X-coordintate indicating where this view should be placed. This

*        will either be the left or right edge of the view, depending on

*        the fromLeft paramter

* @param fromLeft Are we posiitoning views based on the left edge? (i.e.,

*        building from left to right)?

* @return A view that has been added to the gallery

*/

private View makeAndAddView(int position, int offset, int x,

boolean fromLeft) {

 

View child;

 

//        child = mRecycler.get(position);

//        if (child != null) {

//            // Position the view

//            setUpChild(child, offset, x, fromLeft);

//

//            return child;

//        }

//

//        // Nothing found in the recycler — ask the adapter for a view

child = mAdapter.getView(position, null, this);

 

// Position the view

setUpChild(child, offset, x, fromLeft);

 

return child;

}

@Override

protected ViewGroup.LayoutParams generateDefaultLayoutParams() {

/*

* Gallery expects Gallery.LayoutParams.

*/

return new Gallery.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,

ViewGroup.LayoutParams.WRAP_CONTENT);

}

 

/**

* Helper for makeAndAddView to set the position of a view and fill out its

* layout paramters.

*

* @param child The view to position

* @param offset Offset from the selected position

* @param x X-coordintate indicating where this view should be placed. This

*        will either be the left or right edge of the view, depending on

*        the fromLeft paramter

* @param fromLeft Are we posiitoning views based on the left edge? (i.e.,

*        building from left to right)?

*/

private void setUpChild(View child, int offset, int x, boolean fromLeft) {

 

// Respect layout params that are already in the view. Otherwise

// make some up…

Gallery.LayoutParams lp = (Gallery.LayoutParams)

child.getLayoutParams();

if (lp == null) {

lp = (Gallery.LayoutParams) generateDefaultLayoutParams();

}

 

addViewInLayout(child, fromLeft ? -1 : 0, lp);

 

child.setSelected(offset == 0);

 

// Get measure specs

int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec,

0, lp.height);

int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,

0, lp.width);

 

// Measure child

child.measure(childWidthSpec, childHeightSpec);

 

int childLeft;

int childRight;

 

// Position vertically based on gravity setting

int childTop = 0;

int childBottom = childTop + child.getMeasuredHeight();

 

int width = child.getMeasuredWidth();

if (fromLeft) {

childLeft = x;

childRight = childLeft + width;

} else {

childLeft = x – width;

childRight = x;

}

 

child.layout(childLeft, childTop, childRight, childBottom);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

// TODO Auto-generated method stub

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

mWidthMeasureSpec = widthMeasureSpec;

mHeightMeasureSpec = heightMeasureSpec;

}

 

@Override

public int getCount() {

// TODO Auto-generated method stub

return mAdapter.getCount();

}

 

@Override

public BaseAdapter getAdapter() {

// TODO Auto-generated method stub

return mAdapter;

}

 

@Override

public void setAdapter(BaseAdapter adapter) {

// TODO Auto-generated method stub

mAdapter = adapter;

 

removeAllViewsInLayout();

 

requestLayout();

}

 

@Override

public View getSelectedView() {

// TODO Auto-generated method stub

return null;

}

 

@Override

public void setSelection(int position) {

// TODO Auto-generated method stub

}

 

@Override

public boolean onInterceptTouchEvent(MotionEvent event) {

if (!mScroller.isFinished()) {

return true;

}

 

final int action = event.getAction();

MLog.d(“onInterceptTouchEvent action = “+event.getAction());

 

if (MotionEvent.ACTION_DOWN == action) {

startTouch(event);

 

return false;

}else if (MotionEvent.ACTION_MOVE == action) {

return startScrollIfNeeded(event);

}else if (MotionEvent.ACTION_UP == action || MotionEvent.ACTION_CANCEL == action) {

mTouchState = TOUCH_STATE_RESTING;

 

return false;

}

return false;

}

 

@Override

public boolean onTouchEvent(MotionEvent event) {

 

if (!mScroller.isFinished()) {

return true;

}

 

if (mVelocityTracker == null) {

mVelocityTracker = VelocityTracker.obtain();

}

 

mVelocityTracker.addMovement(event);

 

MLog.d(“onTouchEvent action = “+event.getAction());

final int action = event.getAction();

final float x = event.getX();

 

if (MotionEvent.ACTION_DOWN == action) {

startTouch(event);

 

}else if (MotionEvent.ACTION_MOVE == action) {

if (mTouchState == TOUCH_STATE_RESTING) {

startScrollIfNeeded(event);

}else if (mTouchState == TOUCH_STATE_SCROLL) {

int deltaX = (int)(x – mLastMotionX);

mLastMotionX = x;

 

scrollDeltaX(deltaX);

 

}

}else if (MotionEvent.ACTION_UP == action || MotionEvent.ACTION_CANCEL == action) {

if (mTouchState == TOUCH_STATE_SCROLL) {

onUp(event);

}

}

return true;

}

 

 

private void scrollDeltaX(int deltaX){

 

//先把现有的view坐标移动

for (int i = 0; i < getChildCount(); i++) {

getChildAt(i).offsetLeftAndRight(deltaX);

}

 

boolean toLeft = (deltaX < 0);

detachOffScreenChildren(toLeft);

 

if (deltaX < 0) {

//sroll to right

fillToGalleryRight();

}else {

fillToGalleryLeft();

}

 

invalidate();

 

int position = calculteCenterItem() + mFirstPosition;

if (mCurrentSelectedPosition != position) {

mCurrentSelectedPosition = position;

if (mOnPostionChangeListener != null) {

mOnPostionChangeListener.onPostionChange(this, mCurrentSelectedPosition);

}

}

}

 

private void onUp(MotionEvent event){

 

 

final VelocityTracker velocityTracker = mVelocityTracker;

velocityTracker.computeCurrentVelocity(1000);

int velocityX = (int) velocityTracker.getXVelocity();

 

MLog.d( “onUp velocityX:”+velocityX);

 

if (velocityX < -SNAP_VELOCITY && mSelectedPosition < mAdapter.getCount() – 1) {

if (scrollToChild(mSelectedPosition + 1)) {

mSelectedPosition ++;

}

}else if (velocityX > SNAP_VELOCITY && mSelectedPosition > 0) {

if (scrollToChild(mSelectedPosition – 1)) {

mSelectedPosition –;

}

}else{

int position = calculteCenterItem();

int newpostion = mFirstPosition + position;

if (scrollToChild(newpostion)) {

mSelectedPosition = newpostion;

}

}

 

if (mVelocityTracker != null) {

mVelocityTracker.recycle();

mVelocityTracker = null;

}

 

mTouchState = TOUCH_STATE_RESTING;

}

 

/**

* 计算最接近中心点的view

* @return

*/

private int calculteCenterItem(){

View child = null;

int lastpostion = 0;

int lastclosestDistance = 0;

int viewCenter = getLeft() + getWidth() / 2;

for (int i = 0; i < getChildCount(); i++) {

child = getChildAt(i);

if (child.getLeft() < viewCenter && child.getRight() > viewCenter ) {

lastpostion = i;

break;

}else {

int childClosestDistance = Math.min(Math.abs(child.getLeft() – viewCenter), Math.abs(child.getRight() – viewCenter));

if (childClosestDistance < lastclosestDistance) {

lastclosestDistance = childClosestDistance;

lastpostion = i;

}

}

}

 

return lastpostion;

}

 

public void moveNext(){

if (!mScroller.isFinished()) {

return;

}

 

if (0 <= mSelectedPosition && mSelectedPosition < mAdapter.getCount() – 1) {

if (scrollToChild(mSelectedPosition + 1)) {

mSelectedPosition ++;

}else {

makeAndAddView(mSelectedPosition + 1, 1, getWidth(), true);

if (scrollToChild(mSelectedPosition + 1)) {

mSelectedPosition ++;

}

}

}

}

 

public void movePrevious(){

if (!mScroller.isFinished()) {

return;

}

 

if (0 < mSelectedPosition && mSelectedPosition < mAdapter.getCount()) {

if (scrollToChild(mSelectedPosition -1)) {

mSelectedPosition –;

}else {

makeAndAddView(mSelectedPosition – 1, -1, 0, false);

mFirstPosition = mSelectedPosition – 1;

if (scrollToChild(mSelectedPosition – 1)) {

mSelectedPosition –;

}

}

}

}

 

private boolean scrollToChild(int position){

MLog.d( “scrollToChild positionm,FirstPosition,childcount:”+position + “,” + mFirstPosition+ “,” + getChildCount());

View child = getChildAt(position – mFirstPosition );

if (child != null) {

int distance = getWidth() / 2 – (child.getLeft() + child.getWidth() / 2);

 

mLastScrolledOffset = 0;

mScroller.startScroll(0, 0, distance, 0,200);

invalidate();

 

return true;

}

 

MLog.d( “scrollToChild some error happened”);

 

 

return false;

}

 

@Override

public void computeScroll() {

// TODO Auto-generated method stub

if (mScroller.computeScrollOffset()) {

int scrollX = mScroller.getCurrX();

//                        Mlog.d(“MuticomputeScroll ,” + scrollX);

 

scrollDeltaX(scrollX – mLastScrolledOffset);

mLastScrolledOffset = scrollX;

postInvalidate();

}

}

 

private void startTouch(MotionEvent event){

mTouchStartX = event.getX();

 

mTouchState = mScroller.isFinished()? TOUCH_STATE_RESTING : TOUCH_STATE_SCROLL;

 

mLastMotionX = mTouchStartX;

}

 

private boolean startScrollIfNeeded(MotionEvent event){

final int xPos = (int)event.getX();

mLastMotionX = event.getX();

if (xPos < mTouchStartX – mTouchSlop

|| xPos > mTouchStartX + mTouchSlop

) {

// we’ve moved far enough for this to be a scroll

mTouchState = TOUCH_STATE_SCROLL;

return true;

}

return false;

}

 

/**

* Detaches children that are off the screen (i.e.: Gallery bounds).

*

* @param toLeft Whether to detach children to the left of the Gallery, or

*            to the right.

*/

private void detachOffScreenChildren(boolean toLeft) {

int numChildren = getChildCount();

int start = 0;

int count = 0;

int firstPosition = mFirstPosition;

if (toLeft) {

final int galleryLeft = 0;

for (int i = 0; i < numChildren; i++) {

final View child = getChildAt(i);

if (child.getRight() >= galleryLeft) {

break;

} else {

count++;

mRecycler.put(firstPosition + i, child);

}

}

} else {

final int galleryRight = getWidth();

for (int i = numChildren – 1; i >= 0; i–) {

final View child = getChildAt(i);

if (child.getLeft() <= galleryRight) {

break;

} else {

start = i;

count++;

mRecycler.put(firstPosition + i, child);

}

}

}

 

detachViewsFromParent(start, count);

if (toLeft) {

mFirstPosition += count;

}

mRecycler.clear();

}

public void setOnPositionChangeListen(OnPostionChangeListener onPostionChangeListener){

mOnPostionChangeListener = onPostionChangeListener;

}

public int getCurrentSelectedPosition(){

return mCurrentSelectedPosition;

}

/**

* 刷新数据,本来想用AdapterView.AdapterDataSetObserver机制来实现的,但是整个逻辑移植比较麻烦,就暂时用这个替代了

*/

public void updateData(){

requestLayout();

}

private void recycleAllViews() {

int childCount = getChildCount();

final RecycleBin recycleBin = mRecycler;

 

// All views go in recycler

for (int i=0; i<childCount; i++) {

View v = getChildAt(i);

int index = mFirstPosition + i;

recycleBin.put(index, v);

}

}

class RecycleBin {

private SparseArray<View> mScrapHeap = new SparseArray<View>();

 

public void put(int position, View v) {

if (mScrapHeap.get(position) != null) {

Log.e(TAG,”RecycleBin put error.”);

}

mScrapHeap.put(position, v);

}

View get(int position) {

// System.out.print(“Looking for ” + position);

View result = mScrapHeap.get(position);

if (result != null) {

MLog.d(“RecycleBin get hit.”);

mScrapHeap.delete(position);

} else {

MLog.d(“RecycleBin get Miss.”);

}

return result;

}

View peek(int position) {

// System.out.print(“Looking for ” + position);

return mScrapHeap.get(position);

}

void clear() {

final SparseArray<View> scrapHeap = mScrapHeap;

final int count = scrapHeap.size();

for (int i = 0; i < count; i++) {

final View view = scrapHeap.valueAt(i);

if (view != null) {

removeDetachedView(view, true);

}

}

scrapHeap.clear();

}

}

public interface OnPostionChangeListener{

abstract public void onPostionChange(View v,int position);

}

}

通过admin

Android实现欢迎界面滑动效果

Android应用大部分都会有欢迎界面,几张whatsnew图片可以左右滑动,这里贴下自己的源码。大概思路是:重写Gallery,重写onFling()。

为什么不直接用Gallery呢?因为galler默认会有滑动惯性,会出现一次滑动几页的现象,这里明显不合适。

另外,这种方式会有一个小问题,如果你的界面里带了某些控件,而且设置了OnClickListener(),那么用户如果从控件所在区域开始拖动,是不会有拖动效果的,具体原因是onTouchEvent和onInterceptTouchEvent的传递问题。如果想要解决这个问题,可以看下一篇文章,通过重写AdapterView来实现多页滑动效果。

 

 

贴下代码:

import android.content.Context;

import android.util.AttributeSet;

import android.view.KeyEvent;

import android.view.MotionEvent;

import android.view.ViewConfiguration;

import android.widget.Gallery;

public class SingleScrollGallery extends Gallery {

private static final int TOUCH_STATE_REST = 0;

private static final int TOUCH_STATE_SCROLLING = 1;

private int mTouchState = TOUCH_STATE_REST;

private int mTouchSlop;

private float mLastMotionX;

private float mLastMotionY;

 

public SingleScrollGallery(Context context ,AttributeSet attrSet) {

super(context,attrSet);

// TODO Auto-generated constructor stub

mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

}

 

@Override

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,

float velocityY) {

// TODO Auto-generated method stub

//          return super.onFling(e1, e2, velocityX, velocityY);//方法一:只去除翻页惯性

//  return false;//方法二:只去除翻页惯性  注:没有被注释掉的代码实现了开始说的2种效果。

int kEvent;

if(isScrollingLeft(e1, e2)){

//Check if scrolling left

kEvent = KeyEvent.KEYCODE_DPAD_LEFT;

}  else{

//Otherwise scrolling right

kEvent = KeyEvent.KEYCODE_DPAD_RIGHT;

}

onKeyDown(kEvent, null);

return true;

}

 

private boolean isScrollingLeft(MotionEvent e1, MotionEvent e2)

{

return e2.getX() > e1.getX();

}

 

@Override

public boolean onTouchEvent(MotionEvent event) {

// TODO Auto-generated method stub

return super.onTouchEvent(event);

}

 

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

final int action = ev.getAction();

if ((action == MotionEvent.ACTION_MOVE) &&

(mTouchState != TOUCH_STATE_REST)) {

return true;

}

 

final float x = ev.getX();

final float y = ev.getY();

 

switch (action) {

case MotionEvent.ACTION_MOVE:

final int xDiff = (int)Math.abs(mLastMotionX-x);

if (xDiff>0) {

mTouchState = TOUCH_STATE_SCROLLING;

}

break;

 

case MotionEvent.ACTION_DOWN:

mLastMotionX = x;

mLastMotionY = y;

mTouchState = TOUCH_STATE_REST;

break;

 

case MotionEvent.ACTION_CANCEL:

case MotionEvent.ACTION_UP:

mTouchState = TOUCH_STATE_REST;

break;

}

 

return mTouchState != TOUCH_STATE_REST;

}

}

通过admin

Manifest.xml中不要出现重复的uses-permission声明

虽然Android没有明确指定uses-permission不可以重复写,但是最近的经验是最好是不要重复,否则在某些厂商定制的技巧可能出现问题。

 

最近写一个应用,里面有用到网络访问,发现在有些机型下总是访问不了网络。而其他机型都是可以的。出现问题的手机网络都是正常的。

后面发现Manifest.xml中有好几个网络相关的uses-permission都重复写了几个,于是把重复的去掉之后,发现现在访问网络都正常了。

通过admin

android隐藏以及显示软键盘以及不自动弹出键盘的方法

1、//隐藏软键盘

((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(WidgetSearchActivity.this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);

2、//显示软键盘,控件ID可以是EditText,TextView

((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE)).showSoftInput(控件ID, 0);

 

3、不自动弹出键盘:

带有EditText控件的在第一次显示的时候会自动获得focus,并弹出键盘,如果不想自动弹出键盘,有两种方法:

方法一:在mainfest文件中把对应的activity设置

android:windowSoftInputMode=”stateHidden” 或者android:windowSoftInputMode=”stateUnchanged”。

方法二:可以在布局中放一个隐藏的TextView,然后在onCreate的时候requsetFocus。

注意TextView不要设置Visiable=gone,否则会失效

,可以在布局中放一个隐藏的TextView,然后在onCreate的时候requsetFocus。

注意TextView不要设置Visiable=gone,否则会失效

<TextView

android:id=”@+id/text_notuse”

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:focusable=”true”

android:focusableInTouchMode=”true”

/>

 

TextView textView = (TextView)findViewById(R.id.text_notuse);

textView.requestFocus();

通过admin

微软翻译api的使用介绍和注意事项

google翻译api已经收费了,而微软翻译api目前是免费的,支持几种不同的方式访问,如果感兴趣可以自己封装下协议处理。官方介绍:

http://msdn.microsoft.com/en-us/library/hh454950.aspx

这里介绍一下java下的使用。Java下使用微软翻译api可以直接使用一个开源的sdk,http://code.google.com/p/microsoft-translator-java-api/

 

一、首先去http://code.google.com/p/microsoft-translator-java-api/,下载相关jar文件,这里有对微软翻译api的详细使用有作详细介绍。

二,去申请key,进入http://www.bing.com/developers/createapp.aspx,填写相关的你的应用信息就行了。就会有下面的图片中显示的key,中的Application ID就是key。

三、下面给个实例:

Java代码

收藏代码

      1.   /**
      1. * @Title: MicroTranslate.java
      1. * @Description: TODO(用一句话描述该文件做什么)
      1. * @author zengzhaoshuai
      1. * @date 2012-2-13 下午1:17:07
      1. * @version V1.0
      1. */
      1. import com.memetix.mst.language.Language;
      1. import com.memetix.mst.translate.Translate;
      1. /**
      1.  * @ClassName: MicroTranslate
      1.  * @Description: TODO(这里用一句话描述这个类的作用)
      1.  * @author zengzhaoshuai
      2.  * @date 2012-2-13 下午1:17:07
      1.  *
      1.  */
      1. public class MicroTranslate {
      1.     public static void main(String[] args) throws Exception {
      1.         // Set the Microsoft Translator API Key – Get yours at http://www.bing.com/developers/createapp.aspx
      1.        // Translate.setKey(/* Enter your API Key here */);
      1.         Translate.setKey(“自己申请的key”);
      1.         String translatedText = Translate.execute(“属性”, Language.CHINESE_SIMPLIFIED, Language.ENGLISH);
      1.         System.out.println(translatedText);
      1.     }
      1. }

 

四、运行结果:Property

 

这里说下可能出现的问题:

1、android下要用microsoft-translator-java-api-0.6-jar-with-dependencies.jar,否则运行时可能会报错android java.lang.NoClassDefFoundError: org.json.simple.JSONValue。

2、使用过程中出现错误:TranslateApiException: Cannot find an Azure Market Place Translator Subscription associated with the request credentials,则需要到网址上先订阅translate api的免费流量,操作如下:

Make sure you login to azure market place  click on data and select Microsoft Translator. Now click on 2000000 c/moth @ $0 update option. Now I think this error will go away. Try following link also. This is the link where I signed up for 2000000 c/month offer. I was facing the same problem but when I updated my account through following link, this error went away.(参考:http://social.msdn.microsoft.com/Forums/zh-CN/microsofttranslator/thread/1eeb0066-553f-4523-9a1b-0976e4205bb2)

通过admin

尽量不要在android中使用中文路径的问题

在开发过程中发现,有些软件对中文路径支持不大好,如果使用Uri.fromFile转换中文路径为uri的时候,有些软件可能会识别不出来导致功能异常,已知的有两个应用:1、腾讯微博的分享功能;2、酷派D530下调用系统摄像头拍照。

 

如果非要用中文路径,可以采用下面的方式:

String path = getCameraTempFilePath(),;

//有些系统摄像头对中文路径支持不好,通过Uri.fromFile编码之后反而有问题,先手动加上吧

//                 Uri uri = Uri.fromFile(new File(path));

Uri uri = Uri.parse(“file://”+path);

intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);

通过admin

解决Eclipse启动不了,一闪而过的问题

今天系统更新,之后就发现Eclipse启动不了了,双击总是一闪而过,google了一下发现下面的解决方法:

 

eclipse启动不了,双击程序后splash一闪而过,没有任何错误提示。怎么办??

这种情况一般是java配置都正确的情况下发生的。错,绝对不是的,即使你修改了都会没有用的。

一般ECLIPSE都是因为JDK升级导致在C:\windoes \system32下生成这三个文件。

(搜到很多打酱油评论都是说重装系统啦,重装eclipse啦。 好点的说改eclipse.ini啦,设置javahome和path啦。。遇到问题就想闪,来点研究的精神好不好。首先总要看看问题出在哪里吧?)

其实不是的,是C:\Windows\System32多了三个文件啦,只要删除这三个文件,再重启一下就行了。不过我很悲崔,我装的ANDROID adt也删除了,不过大家幸运了,以后没有我这么2了。希望这遍文章不要大家走我这种2路。

删除这三个文件ECLIPSE就可以用

通过admin

Java多线程notify&notifyall的区别

当一个线程进入wait之后,就必须等其他线程notify/notifyall,使用notifyall,可以唤醒

所有处于wait状态的线程,使其重新进入锁的争夺队列中,而notify只能唤醒一个。注意,任何时候只有一个线程可以获得锁,也就是说只有一个线程可以运行synchronized 中的代码,notifyall只是让处于wait的线程重新拥有锁的争夺权,但是只会有一个获得锁并执行。

 

那么notify和notifyall在效果上又什么实质区别呢?

主要的效果区别是notify用得不好容易导致死锁,例如下面提到的例子。

 

public synchronized void put(Object o) {

 

while (buf.size()==MAX_SIZE) {

 

wait(); // called if the buffer is full (try/catch removed for brevity)

 

}

 

buf.add(o);

 

notify(); // called in case there are any getters or putters waiting

 

}

 

 

 

public synchronized Object get() {

 

// Y: this is where C2 tries to acquire the lock (i.e. at the beginning of the method)

 

while (buf.size()==0) {

 

wait(); // called if the buffer is empty (try/catch removed for brevity)

 

// X: this is where C1 tries to re-acquire the lock (see below)

 

}

 

Object o = buf.remove(0);

 

notify(); // called if there are any getters or putters waiting

 

return o;

 

}

 

所以除非你非常确定notify没有问题,大部分情况还是是用notifyall。
更多详细的介绍可以参看:

http://stackoverflow.com/questions/37026/java-notify-vs-notifyall-all-over-again

 

 

通过admin

linux下Google的Protobuf安装及使用笔记

protobuf

项目主页:http://code.google.com/p/protobuf/

下载:http://code.google.com/p/protobuf/downloads/list protobuf-2.4.1.tar.gz

解压后进入protobuf-2.4.1目录进行安装:

1、./configure(注:默认可能会安装在/usr/local目录下,可以加–prefix=/usr来指定安装到/usr/lib下,可以免去路径的设置,路径设置见Linux命令pkg-config

./configure –prefix=/usr/local/protobuf

2、make

3、make check

4、make install(需要超级用户root权限)

二、使用

1、写proto文件,定义消息具体格式。如:helloworld.proto

package lm;

message helloworld

{

required int32 id = 1;//ID

required string str = 2;//str

optional int32 opt = 3;//optional field

}

2、使用protoc来编译生成对应语言的文件

–cpp_out:表示输出c++语言使用格式,–java_out,–python_out等,其他第三方的插件:Third-Party Add-ons for Protocol Buffers

此时会生成helloworld.pb.h及helloworld.pb.cc两个文件

3、Write A message

View Code

4、Read A message

View Code

5、编译及运行

g++ -g -o Writer helloworld.pb.cc writermessage.cpp `pkg-config –cflags –libs protobuf`

g++ -g -o Reader helloworld.pb.cc Readermessage.cpp `pkg-config –cflags –libs protobuf`

通过admin

详解Google-ProtoBuf中结构化数据的编码

原文:http://www.wuzesheng.com/?p=1258

本文的主要内容是google protobuf中序列化数据时用到的编码规则,但是,介绍具体的编码规则之前,我觉得有必要先简单介绍一下google protobuf。因此,本文首先会介绍一些google protobuf相关的内容,让读者朋友对google protobuf有一个初步的印象,然后,再开始进入正题—-深入浅出地介绍google protobuf中用到的编码规则。下面言归正传,开始今天的话题。

1. Google-ProtoBuf是什么

ProtoBuf,全称是Protocol Buffers, 它是谷歌内部用的一种高效的、可扩展的对结构化数据进行编码的格式规范。谷歌自己内部很多程序之间的通信协议都用了ProtoBuf。

ProtoBuf可以支持多种编程语言,目前已经C++, Java和Python,本文中所前的内容用到例子的话,会以C++为例。

2.如何得到Google-ProtoBuf

ProtoBuf在Google Code上的主页是:http://code.google.com/p/protobuf/, 感兴趣的朋友可以在这里下载ProtoBuf的源码,也可以在这里阅读ProtoBuf的详细的文档。

3. 深入浅出Google-ProtoBuf中的编码规则

(1)序列化和反序列化:

在开始本部分的内容之前,首先有必要介绍两个基本概念,一个是序列化,一个是反序列化。这两个概念的定义在网上搜一下都很多的,但大多都讲得比较晦涩,不太好理解,在这里我会用比较通俗的文字来解释,尽可能让读都朋友们一读就明白是怎么回事:

序列化:是指将结构化的数据按一定的编码规范转成指定格式的过程

反序列化:是指将转成指定格式的数据解析成原始的结构化数据的过程

举个例子,Person是一个表示人的对象类型,person是一个Person类型的对象,将person存到一个对应的XML文档中的过程就是一种序列化,而解析XML生成对应Person类型对象person的过程,就是一个反序列化的过程。在这里结构化数据指的就是Person类型的数据,一定的编码规范指的就是XML文档的规范。XML是一种简单的序列化方式,用XML序列化的好处是,XML的通用性比较好,另外,XML是一种文本格式,对人阅读比较友好,但是XML方式比较占空间,效率也不是很高。通常,比较高效的序列化都是采用二进制方式的,将要序列化的结构化数据,按一定的编码规范,转成为一串二进制的字节流存储下来,需要用的时候再从这串二进制的字节流中反序列化出对应的结构化的数据。

通过上面的介绍,我们给protobuf下一个比较正式的定义了:Google ProtoBuf是Google制定的一种用来序列化结构化数据的程序库。

(2)ProtoBuf中的编码:

1) ProtoBuf编码基础——Varints, varints是一种将一个整数序列化为一个或者多个Bytes的方法,越小的整数,使用的Bytes越少。

Varints的基本规则是:

(a)每个Byte的最高位(msb)是标志位,如果该位为1,表示该Byte后面还有其它Byte,如果该位为0,表示该Byte是最后一个Byte。

(b)每个Byte的低7位是用来存数值的位

(c)Varints方法用Litte-Endian(小端)字节序

举个例子:300用Varints序列化的结果是1010 1100 0000 0010,运算过程如下所示:

1010 1100 0000 0010->010 1100 000 0010(去标志位)->

000 0010 010 1100(调整字节序)-> 1 0010 1100 ->256+32+8+4=300(计算值)

2)ProtoBuf中消息的编码规则:

(a)每条消息(message)都是有一系列的key-value对组成的, key和value分别采用不同的编码方式。

(b)对某一条件消息(message)进行编码的时候,是把该消息中所有的key-value对序列化成二进制字节流;而解码的时候,解码程序读入二进制的字节流,解析出每一个key-value对,如果解码过程中遇到识别不出来的类型,直接跳过。这样的机制,保证了即使该消息添加了新的字段,也不会影响旧的编/解码程序正常工作。

(c)key由两部分组成,一部分是在定义消息时对字段的编号(field_num),另一部分是字段类型(wire_type)。字段类型定义如下表所示。

Type Meaning Used For
0 Varint int32, int64, uint32, uint64, sint32, sint64, bool, enum
1 64-bit fixed64, sfixed64, double
2 Length-delimited string, bytes, embedded messages, packed repeated fields
3 Start group groups (deprecated)
4 End group groups (deprecated)
5 32-bit fixed32, sfixed32, float

(d)key的编码方式:field_num << 3 | wire_type

(e)varint类型(wire_type=0)的编码,与第(1)部分中介绍的方法基本一致,但是int32, int64和sint32,sint64有些特别之处:int32和int64就是简单的按varints方法来编码,所以像-1、-2这样负数也会占比较多的Bytes。于是sint32和sint64采用了一种改进的方法:先采用Zigzag方法将所有的整数(正数、0和负数)一一映射到所有的无符号数上,然后再采用varints编码方法进行编码。Zigzag映射函数为:

Zigzag(n) = (n << 1) ^ (n >> 31),  n为sint32时

Zigzag(n) = (n << 1) ^ (n >> 63),  n为sint64时

下表是一个比较直观的映射表,这样映射后再进行编码的好处就是绝对值比较小的负数序列化后的结果占的Bytes数也会比较少。

Signed Original Encoded As
0 0
-1 1
1 2
-2 3
2 4
-3 5
2147483647 4294967294
-2147483648 4294967295

(f)64-bit(wire_type=1)和32-bit(wire_type=5)的编码方式就比较简单了,直接在key后面跟上64bits或32bits,采用Little-Endian(小端)字节序。

(g)length-delimited(wire_type=2)的编码方式:key+length+content, key的编码方式是统一的,length采用varints编码方式,content就是由length指定的长度的Bytes。

(h)wire_type=3和4的现在已经不推荐使用了,因此这里也不再做介绍。

3)ProtoBuf编解码中字段顺序(Field order)的问题:

(a) 编码/解码与字段顺序无关,这一点由key-value机制就能保证

(b)对于未知的字段,编码的时候会把它写在序列化完的已知字段后面。

 

源文档 <http://www.wuzesheng.com/?p=1258>