[转载]android UI进阶之仿iphone的tab效果(二)

mikel阅读(976)

[转载]android UI进阶之仿iphone的tab效果(二) – noTice520 – 博客园.

今天把这个仿iphone效果的tab写完,这个例子参考国外rolle3k共享的代码,感谢rolle3k。

上篇博客我们写了一个Itab类,介绍了背景的绘制和简单的一个图的贴图方法。我们继续来完成Itab这个类,同时把他放到 MainAcitvity(继承Activity)这个类内部,这样,整个程序只需一个类就可以了。(上篇博客例子运行需要再建一个Activity的子 类来作为lanucher)。废话不多说了,看看代码

1 public static class iTab extends View 2 { 3 private Paint mPaint;//背景画笔 4   private Paint mActiveTextPaint;//选中 5   private Paint mInactiveTextPaint;//未选中 6   private ArrayList<TabMember> mTabMembers;//tab成员 7   private int mActiveTab; 8 private OnTabClickListener mOnTabClickListener = null; 9 10 public iTab( Context context, AttributeSet attrs ) //构造器,在里面初始化画笔 11   { 12 super(context, attrs); 13 14 mTabMembers = new ArrayList<MainActivity.iTab.TabMember>( ); 15 16 mPaint = new Paint( ); 17 mActiveTextPaint = new Paint( ); 18 mInactiveTextPaint = new Paint( ); 19 20 mPaint.setStyle( Paint.Style.FILL ); 21 mPaint.setColor( 0xFFFFFF00 ); 22 mPaint.setAntiAlias(true); 23 24 mActiveTextPaint.setTextAlign( Align.CENTER ); 25 mActiveTextPaint.setTextSize( 12 ); 26 mActiveTextPaint.setColor( 0xFFFFFFFF ); 27 mActiveTextPaint.setAntiAlias(true); 28 29 30 mInactiveTextPaint.setTextAlign( Align.CENTER ); 31 mInactiveTextPaint.setTextSize( 12 ); 32 mInactiveTextPaint.setColor( 0xFF999999 ); 33 mInactiveTextPaint.setAntiAlias(true); 34 mActiveTab = 0; 35 36 } 37 38 @Override 39 protected void onDraw( Canvas canvas ) 40 { 41 super.onDraw( canvas ); 42 43 Rect r = new Rect( ); 44 this.getDrawingRect( r ); 45 46 // 计算每个标签能使用多少像素 47   int singleTabWidth = r.right / ( mTabMembers.size( ) != 0 ? mTabMembers.size( ) : 1 ); 48 49 50 // 绘制背景 51   canvas.drawColor( 0xFF000000 ); 52 mPaint.setColor( 0xFF434343 ); 53 canvas.drawLine( r.left, r.top + 1, r.right, r.top + 1, mPaint ); 54 55 int color = 46; 56 57 for( int i = 0; i < 24; i++ ) 58 { 59 mPaint.setARGB( 255, color, color, color ); 60 canvas.drawRect( r.left, r.top + i + 1, r.right, r.top + i + 2, mPaint ); 61 color--; 62 } 63 64 // 绘制每一个tab 65   for( int i = 0; i < mTabMembers.size( ); i++ ) 66 { 67 TabMember tabMember = mTabMembers.get( i ); 68 69 Bitmap icon = BitmapFactory.decodeResource( getResources( ), tabMember.getIconResourceId( ) ); 70 Bitmap iconColored = Bitmap.createBitmap( icon.getWidth(), icon.getHeight(), Bitmap.Config.ARGB_8888 ); 71 Paint p = new Paint( Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); 72 Canvas iconCanvas = new Canvas( ); 73 iconCanvas.setBitmap( iconColored ); 74 75 if( mActiveTab == i )//为已选中的tab绘制一个白蓝的渐变色,未选中的绘制一个白灰的渐变色 76 { 77 p.setShader( new LinearGradient( 0, 0, icon.getWidth(), icon.getHeight(), 78 0xFFFFFFFF, 0xFF54C7E1, Shader.TileMode.CLAMP ) ); 79 } 80 else { 81 p.setShader( new LinearGradient( 0, 0, icon.getWidth(), icon.getHeight(), 82 0xFFA2A2A2, 0xFF5F5F5F, Shader.TileMode.CLAMP ) ); 83 } 84 85 iconCanvas.drawRect( 0, 0, icon.getWidth( ), icon.getHeight( ), p ); 86 87 for( int x = 0; x < icon.getWidth(); x++ ) 88 { 89 for( int y = 0; y < icon.getHeight(); y++ ) 90 { 91 if( ( icon.getPixel(x, y) & 0xFF000000 ) == 0 ) 92 { 93 iconColored.setPixel( x, y, 0x00000000 ); 94 } 95 } 96 } 97 98 // 计算tab图片的位置 99 int tabImgX = singleTabWidth * i + ( singleTabWidth / 2 - icon.getWidth( ) / 2 ); 100 101 // 绘制tab图片 选中的和未选中的 102 if( mActiveTab == i ) 103 { 104 mPaint.setARGB( 37, 255, 255, 255 ); 105 canvas.drawRoundRect( new RectF( r.left + singleTabWidth * i + 3, r.top + 3, 106 r.left + singleTabWidth * ( i + 1 ) - 3, r.bottom - 2 ), 5, 5, mPaint ); 107 canvas.drawBitmap( iconColored, tabImgX , r.top + 5, null ); 108 canvas.drawText( tabMember.getText( ), 109 singleTabWidth * i + ( singleTabWidth / 2), r.bottom - 2, mActiveTextPaint ); 110 } else 111 { 112 canvas.drawBitmap( iconColored, tabImgX , r.top + 5, null ); 113 canvas.drawText( tabMember.getText( ), 114 singleTabWidth * i + ( singleTabWidth / 2), r.bottom - 2, mInactiveTextPaint ); 115 } 116 } 117 118 } 119 /* 120 * 触摸事件 121 */ 122 @Override 123 public boolean onTouchEvent( MotionEvent motionEvent ) 124 { 125 Rect r = new Rect( ); 126 this.getDrawingRect( r ); 127 float singleTabWidth = r.right / ( mTabMembers.size( ) != 0 ? mTabMembers.size( ) : 1 ); 128 129 int pressedTab = (int) ( ( motionEvent.getX( ) / singleTabWidth ) - ( motionEvent.getX( ) / singleTabWidth ) % 1 ); 130 131 mActiveTab = pressedTab; 132 133 if( this.mOnTabClickListener != null) 134 { 135 this.mOnTabClickListener.onTabClick( mTabMembers.get( pressedTab ).getId( ) ); 136 } 137 138 this.invalidate(); 139 140 return super.onTouchEvent( motionEvent ); 141 } 142 143 void addTabMember( TabMember tabMember ) 144 { 145 mTabMembers.add( tabMember ); 146 } 147 148 void setOnTabClickListener( OnTabClickListener onTabClickListener ) 149 { 150 mOnTabClickListener = onTabClickListener; 151 } 152 153 public static class TabMember//处理tab成员 154 { 155 protected int mId; 156 protected String mText; 157 protected int mIconResourceId; 158 159 TabMember( int Id, String Text, int iconResourceId ) 160 { 161 mId = Id; 162 mIconResourceId = iconResourceId; 163 mText = Text; 164 } 165 166 public int getId( ) 167 { 168 return mId; 169 } 170 171 public String getText( ) 172 { 173 return mText; 174 } 175 176 public int getIconResourceId( ) 177 { 178 return mIconResourceId; 179 } 180 181 public void setText( String Text ) 182 { 183 mText = Text; 184 } 185 186 public void setIconResourceId( int iconResourceId ) 187 { 188 mIconResourceId = iconResourceId; 189 } 190 } 191 192 public static interface OnTabClickListener 193 { 194 public abstract void onTabClick( int tabId ); 195 } 196 }

这是MainActivity这个类里面的两个static类,看我写的注释和上篇博客的内容应该都能理解。其中还定义了触摸事件,实现点击tab出现不同布局的效果。接下来我们只需要在我们的layout上添加就可以了,我们继续写一个内部类

1 public static class iRelativeLayout extends RelativeLayout//注意,还是声明为静态 2 { 3 private Paint mPaint; 4 private Rect mRect; 5 6 public iRelativeLayout( Context context, AttributeSet attrs ) 7 { 8 super(context, attrs); 9 10 mRect = new Rect( ); 11 mPaint = new Paint( ); 12 13 mPaint.setStyle( Paint.Style.FILL_AND_STROKE ); 14 mPaint.setColor( 0xFFCBD2D8 ); 15 } 16 17 @Override 18 protected void onDraw( Canvas canvas ) 19 { 20 super.onDraw( canvas ); 21 22 canvas.drawColor( 0xFFC5CCD4 ); 23 24 this.getDrawingRect( mRect ); 25 26 for( int i = 0; i < mRect.right; i += 7 )//绘制屏幕背景的纹理效果 27 { 28 canvas.drawRect( mRect.left + i, mRect.top, mRect.left + i + 2, mRect.bottom, mPaint ); 29 } 30 31 } 32 } 33 34 35 private static final int TAB_HIGHLIGHT = 1; 36 private static final int TAB_CHAT = 2; 37 private static final int TAB_LOOPBACK = 3; 38 private static final int TAB_REDO = 4; 39 private iTab mTabs; 40 private LinearLayout mTabLayout_One; 41 private LinearLayout mTabLayout_Two; 42 private LinearLayout mTabLayout_Three; 43 private LinearLayout mTabLayout_Four; 44 private LinearLayout mTabLayout_Five; 45 46 @Override 47 public void onCreate(Bundle savedInstanceState) 48 { 49 super.onCreate(savedInstanceState); 50 setContentView(R.layout.main); 51 52 53 mTabs = (iTab) this.findViewById( R.id.Tabs ); 54 mTabLayout_One = (LinearLayout) this.findViewById( R.id.TabLayout_One ); 55 mTabLayout_Two = (LinearLayout) this.findViewById( R.id.TabLayout_Two ); 56 mTabLayout_Three = (LinearLayout) this.findViewById( R.id.TabLayout_Three ); 57 mTabLayout_Four = (LinearLayout) this.findViewById( R.id.TabLayout_Four ); 58 mTabLayout_Five = (LinearLayout) this.findViewById( R.id.TabLayout_Four );//偷个懒,不写第五个界面啦 59 60 mTabs.addTabMember( new TabMember( TAB_HIGHLIGHT, "精选", R.drawable.jingxuan ) ); 61 mTabs.addTabMember( new TabMember( TAB_CHAT, "类别", R.drawable.cat ) ); 62 mTabs.addTabMember( new TabMember( TAB_LOOPBACK, "25大排行榜", R.drawable.rank ) ); 63 mTabs.addTabMember( new TabMember( TAB_REDO, "搜索", R.drawable.search ) ); 64 mTabs.addTabMember( new TabMember( TAB_REDO, "更新", R.drawable.download ) );//添加tab 65 66 /*初始显示第一个界面*/ 67 mTabLayout_One.setVisibility( View.VISIBLE ); 68 mTabLayout_Two.setVisibility( View.GONE ); 69 mTabLayout_Three.setVisibility( View.GONE ); 70 mTabLayout_Four.setVisibility( View.GONE ); 71 72 mTabs.setOnTabClickListener( new OnTabClickListener( ) { 73 @Override 74 public void onTabClick( int tabId )//实现点击事件 75 { 76 if( tabId == TAB_HIGHLIGHT ) 77 { 78 mTabLayout_One.setVisibility( View.VISIBLE ); 79 mTabLayout_Two.setVisibility( View.GONE ); 80 mTabLayout_Three.setVisibility( View.GONE ); 81 mTabLayout_Four.setVisibility( View.GONE ); 82 } else if( tabId == TAB_CHAT ) 83 { 84 mTabLayout_One.setVisibility( View.GONE ); 85 mTabLayout_Two.setVisibility( View.VISIBLE ); 86 mTabLayout_Three.setVisibility( View.GONE ); 87 mTabLayout_Four.setVisibility( View.GONE ); 88 } else if( tabId == TAB_LOOPBACK ) 89 { 90 mTabLayout_One.setVisibility( View.GONE ); 91 mTabLayout_Two.setVisibility( View.GONE ); 92 mTabLayout_Three.setVisibility( View.VISIBLE ); 93 mTabLayout_Four.setVisibility( View.GONE ); 94 } else if( tabId == TAB_REDO ) 95 { 96 mTabLayout_One.setVisibility( View.GONE ); 97 mTabLayout_Two.setVisibility( View.GONE ); 98 mTabLayout_Three.setVisibility( View.GONE ); 99 mTabLayout_Four.setVisibility( View.VISIBLE ); 100 } 101 } 102 }); 103 }

其中onDraw()方法里面实现了背景的纹理效果,配合xml里面背景色的配置,实现了如下图所示的效果:

是不是非常漂亮呢。下面就是xml里面的配置了

代码

1 <?xml version="1.0" encoding="utf-8"?> 2 3 <view xmlns:android="http://schemas.android.com/apk/res/android" 4 class="com.notice520.MainActivity$iRelativeLayout" 5 android:orientation="vertical" 6 android:layout_width="fill_parent" 7 android:layout_height="fill_parent" 8 android:background = "#C5CCD4FF" 9 > 10 <LinearLayout 11 android:id = "@+id/TabLayout_One" 12 android:layout_width = "fill_parent" 13 android:layout_height = "fill_parent" 14 android:layout_above = "@+id/Tabs" 15 > 16 <ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content"> 17 <RelativeLayout 18 android:layout_width = "fill_parent" 19 android:layout_height = "fill_parent" 20 android:visibility = "visible" 21 > 22 <TextView 23 android:textColor="@android:color/black" 24 android:textSize="30sp" 25 android:layout_width = "wrap_content" 26 android:layout_height = "wrap_content" 27 android:text = "春节快乐!!" 28 /> 29 </RelativeLayout> 30 </ScrollView> 31 </LinearLayout> 32 33 <LinearLayout 34 android:id = "@+id/TabLayout_Two" 35 android:layout_width = "fill_parent" 36 android:layout_height = "fill_parent" 37 android:layout_above = "@+id/Tabs" 38 > 39 <ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content"> 40 <RelativeLayout 41 android:layout_width = "fill_parent" 42 android:layout_height = "fill_parent" 43 android:visibility = "visible" 44 android:layout_above = "@+id/Tabs" 45 > 46 <Button 47 android:layout_width = "wrap_content" 48 android:layout_height = "wrap_content" 49 android:text = "祝大家事业有成!" 50 android:textSize = "30sp" 51 /> 52 </RelativeLayout> 53 </ScrollView> 54 </LinearLayout> 55 <LinearLayout 56 android:id = "@+id/TabLayout_Three" 57 android:layout_width = "fill_parent" 58 android:layout_height = "fill_parent" 59 android:layout_above = "@+id/Tabs" 60 > 61 <ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content"> 62 <RelativeLayout 63 android:layout_width = "fill_parent" 64 android:layout_height = "fill_parent" 65 android:visibility = "visible" 66 android:layout_above = "@+id/Tabs" 67 > 68 <ImageView 69 70 android:layout_width = "fill_parent" 71 android:layout_height = "fill_parent" 72 android:src="@drawable/newq" 73 /> 74 </RelativeLayout> 75 </ScrollView> 76 </LinearLayout> 77 <LinearLayout 78 android:id = "@+id/TabLayout_Four" 79 android:layout_width = "fill_parent" 80 android:layout_height = "fill_parent" 81 android:layout_above = "@+id/Tabs" 82 > 83 <ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content"> 84 <RelativeLayout 85 android:id = "@+id/TabLayout_Four" 86 android:layout_width = "fill_parent" 87 android:layout_height = "fill_parent" 88 android:visibility = "visible" 89 android:layout_above = "@+id/Tabs" 90 > 91 <TextView 92 android:textColor="@android:color/black" 93 android:layout_width = "wrap_content" 94 android:layout_height = "wrap_content" 95 android:text = "很简单,是么" 96 /> 97 </RelativeLayout> 98 </ScrollView> 99 </LinearLayout> 100 <view 101 class="com.notice520.MainActivity$iTab" 102 android:id="@+id/Tabs" 103 android:layout_width = "fill_parent" 104 android:layout_height = "49px" 105 android:layout_alignParentBottom = "true" 106 /> 107 </view> 108

来看看最终的效果吧

是不是还不错呢  希望大家喜欢,有问题可以留言交流。

[转载]android UI进阶之仿iphone的tab效果

mikel阅读(1027)

[转载]android UI进阶之仿iphone的tab效果 – noTice520 – 博客园.

相信很多人都喜欢iphone 酷炫的界面,虽然Android的原生控件已经足够漂亮,但是往往不能满足用户越来越挑剔的眼光。其实,我们完全可以自己来绘制界面。今天我就来分享下做一个和iphone一样的tab界面。下面先来看下iphone上的效果

在开始之前,我们必须掌握最基础的,也就是Android中图形界面的绘制。首先讲下简单图形的绘制,这里我们就借绘制这个的背景部分来讲下吧。直接看代码

代码

1 public class Itab extends View { 2 3 private Paint mPaint; 4 5 public Itab(Context context, AttributeSet attrs) {//构造器,View下构造器有三种方式,在xml中配置必须实现这种方式 6   super(context, attrs); 7 8 } 9 10 @Override 11 protected void onDraw( Canvas canvas ) 12 { 13 14 super.onDraw( canvas ); 15 16 mPaint = new Paint( );//创建画笔 17 mPaint.setStyle( Paint.Style.FILL );//设置画笔 为实心 18 19 Rect r = new Rect( );//创建一个矩形 20 this.getDrawingRect( r ); 21 22 canvas.drawColor( 0xFF000000 ); 23 mPaint.setColor( 0xFF434343 ); 24 canvas.drawLine( r.left, r.top + 1, r.right, r.top + 1, mPaint );//绘制这个矩形图形 25 } 26 }

在xml中这样配置

代码

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#C5CCD4FF" > <com.notice520.itab.Itab android:id="@+id/Tabs" android:layout_width="fill_parent" android:layout_height = "49px" android:layout_alignParentBottom = "true" /> </RelativeLayout>

这样就会得到如下的效果,这显然不是我们想要的。

不过别着急,我们只要在onDraw()这个方法里面添加如下一段代码:

代码

int color = 46; for( int i = 0; i < 24; i++ ) { mPaint.setARGB( 255, color, color, color ); canvas.drawRect( r.left, r.top + i + 1, r.right, r.top + i + 2, mPaint ); color--; }

通过循环的绘制,我们就可以得到如下的效果

是不是很简单呢。图形绘制中还有一个比较重要的是贴图的绘制。同样这个例子,我们在这个背景上绘制一个图标,非常的简单,同样在onDraw()这个方法里面添加如下代码

代码

1 Bitmap icon = BitmapFactory.decodeResource( getResources( ), R.drawable.monitor ); 2 Paint p = new Paint( Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); 3 p.setColor(Color.WHITE); 4 canvas.drawBitmap(icon, 10, 10, p);

代码非常简单,第一行获得图片资源,第二行第一一个画笔,同时打开抗锯齿和过滤,第三行设置画笔颜色,最后一行绘制图片。

来看看效果

还不错吧,当然要实现完全的tab效果,这还是远远不够的。今天就写到这吧,天冷啊,手都冻僵了,明天或者后天我再接着写,从而最终实现和iphone一样的tab,当然也有完全可以替代原生tab的功能。大家有什么问题可以留言讨论哈。

[转载]12个有趣的HTML5实例

mikel阅读(1712)

[转载]12个有趣的HTML5实例 – Alexis – 博客园.

上一周,未来的Web有了自己的logo。无论你喜不喜欢,HTML5来了并且将成为新的标准。本文将介绍一些HTML5新的实例。

HTML5logo

1.The Wilderness Downtown by Google & The Arcade Fire

很有中国风的应用,输入城市名即可。。

HTML5logo

2.Jolicloud

HTML5logo

3.Wordmark.it

使得文本拥有同你电脑中一样的字体。

HTML5logo

4.Z-Type

一款有HTML打造的游戏。

HTML5logo

5.Nike Better World

HTML5logo

6.Klowdz

这个应用让我想起了去年十分流行的一句话,“神马都是浮云”,这就是使用HTML5绘制的神马!

HTML5logo

7.Canvas Cycle

又一款十分酷的Chorme试验品。Canvas Cycle就像在你的任天堂上有一个编辑面板。你可以选择不挺的场景,控制音量、缩放宿舍,循环类型等。

HTML5logo

8.GraphyCalc

这个是有HTML5绘制的3D图形,并且能够根据你的鼠标去旋转。

HTML5logo

9.Google Maps + Dynamic Canvas

谷歌地图和动态的画板。

HTML5logo

10.Darkroom

这个Web应用可以让我们在线编辑图片。

HTML5logo

11.20 Things

一个非常清爽简洁的网站,可以阅读电子书。

HTML5logo

12.Agent 8-Ball

HTML5logo

原文链接http://webdesignledger.com/inspiration/12-fun-clever-examples-of-html5

一些HTML5的资源

http://www.chromeexperiments.com/

http://www.html5gallery.com/

http://www.apple.com/

[转载]小泥鳅解剖系列之模板机制

mikel阅读(1393)

[转载]小泥鳅解剖系列之模板机制 – 小泥鳅博客技术交流区 – 博客园.

为了给小泥鳅实现一套好的模板机制,曾经花了大量时间来分析目前互联网上的成熟,流行的通用程序,包括blog,cms,shop,bbs/.net,php,asp等,总结下来主要有以下几种:

1、CSS

通过加载不同的CSS文件来实现不同的展现效果。

相信熟悉CSS的话,便知CSS的强大,ASP.NET的默认主题基于此实现

优点:维护方便,速度快

缺点:2/8原则,可以实现大部分功能,灵活性不够

2、模板引擎

通过加载不同的模板文件(模板文件内容可不同),使用模板引擎自己的语言机制动态替换数据,来实现不同的展现效果。

优点:灵活,可实现绝大部分需求

缺点:影响性能,需要引入第三方模板引擎(当然可以自己开发),增加复杂度。

3、.ascx用户控件,母版页.Net平台独有

通过加载不同的.ascx用户控件来实现不同的展现效果。当然也可以动态加载. master母版页。

原理和使用第三方模板引擎类似。

优点:可使用.net语言,比模板引擎更灵活,可实现任何需求

缺点:通过反射机制影响性能(据说,未验证),.net特征偏多,对美工不友好

4、生成.aspx文件

需要使用一次模板引擎生成.aspx文件,利用URL重写加载不同的.aspx文件,运用时与模板引擎和模板文件无关。

优点:灵活,速度快

缺点:维护相对麻烦,修改模板后需要重新生成.aspx文件, 加入第三方模板引擎,增加复杂度。

5,xml+xslt

名词解释:XSL 指扩展样式表语言(EXtensible Stylesheet Language),XSLT 指XSL 转换

设计思想跟模板引擎一样,不过xslt是通用标准

优点:标准,跨平台,跨语言

缺点:不够灵活,容易出错, 对美工来说,偏复杂

问题来了,哪种更合适小泥鳅的呢?受Community Server,BlogEngine.NET等国外程序的影响,老农开始选择了第3种,通过动态加载不同用户控件的方式来实现模板机制,功能很给力,并且 在相当长的内部开发阶段使用了这种方式(胎死腹中),同时也是在这个阶段,在与其它职业的同事,朋友交流中,慢慢觉得这可能不是一种最合适的方式(实践出 真知),对于广大普通用户,特别是主题设计者,太多的.net特性会让他们看花了眼。

小泥鳅的定位一个成熟,通用,面向所有人群的博客程序,最后把焦点放在了模板引擎上,

现在.net平台的主要模板引擎有Nvelocity, StringTemplate等,经过多方面的测试,评估,最终选择了NVelocity,当然不排除今后有能力,有时间自己造轮子。

NVelocity源自Java,历史悠久,语法优雅,减少了重复学习的成本

如以下代码用于输出最新日志(简单就是美):

1 <div id="recentposts" class="widget">
2 <h3>最新日志</h3>
3 <ul>
4 #foreach($item in ${recentposts})
5 <li>${item.link}</li>
6 #end
7 </ul>
8 </div>

根据发布以来的反馈统计,效果还不错,大家也来做皮吧 ^_^

附:

源码下载:http://files.cnblogs.com/wei/Loachs_1.2_src.rar

官方网站http://www.loachs.com/

QQ群:12018034

[转载]C# 用Linq的方式实现对Xml文件的基本操作(创建xml文件、增删改查xml文件节点信息)

mikel阅读(775)

[转载]C# 用Linq的方式实现对Xml文件的基本操作(创建xml文件、增删改查xml文件节点信息) – Eric Sun – 博客园.

我的上一篇文章描述了用普通方法实现对xml文件的基本操作,感谢各位园友给我提的每一个建议,大家主要在说:用Linq去实现对xml的操作 更加方便简洁,于是乎我就现学习了一下Linq to xml,由于是刚刚接触Linq,理解肯定不会很深,所以请各位园友不吝赐教,有建议尽管说,在此先谢过大家啦~

LINQ to XML 为创建 XML 元素提供了一种称为“函数构造”的有效方式。函数构造是指在单个语句中创建 XML 树的能力。

启用函数构造的 LINQ to XML 编程接口有几个重要功能:

XElement 构造函数可以对内容采用多种类型的参数。 例如,可以传递另一个 XElement 对象,该对象将成为一个子元素。 可以传递一个 XAttribute 对象,该对象将成为该元素的一个属性。 也可以传递任何其他类型的对象,该对象将转换为字符串并成为该元素的文本内容。

XElement 函数采用类型为 Objectparams 数组,因此可以向该构造函数传递任意数目的对象。 这使您可以创建具有复杂内容的元素。如果对象实

IEnumerable<T>,则枚举对象中的集合,并添加集合中的所有项。

如果集合包含 XElementXAttribute 对象,则单独添加集合中的每一项。这一功能很重要,因为它允许您将 LINQ 查询的结果传递给构造函数。

本文的主要模块为:

① :生成xml文件

② :遍历xml文件的节点信息

③ :修改xml文件的节点信息

④ :向xml文件添加节点信息

⑤ :删除指定xml文件的节点信息


①:生成xml文件假设我们想生成这样的一个xml文件结构,如下所示:

<?xml version=”1.0″ encoding=”utf-8″ ?>
<Users>
<User ID=”111111>
<name>EricSun</name>
<password>123456</password>
<description>Hello I’m from Dalian</description>
</User>
<User ID=”222222>
<name>Ray</name>
<password>654321</password>
<description>Hello I’m from Jilin</description>
</User>
</Users>
用我的上篇文章也能够很容的实现,不过下面我要用Linq to xml的方式实现生成这个xml文件,请看下面代码:

1 using System; 2  using System.Collections.Generic; 3  using System.Linq; 4  using System.Text; 5  using System.Xml.Linq; 6 7  namespace OperateXmlLinq 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 //xml文件存储路径 14   string myXmlPath = "E:\\MyUsers.xml"; 15 //创建xml文件 16   GenerateXmlFile(myXmlPath); 17 } 18 19 private static void GenerateXmlFile(string xmlPath) 20 { 21 try 22 { 23 //定义一个XDocument结构 24   XDocument myXDoc = new XDocument( 25 new XElement("Users", 26 new XElement("User", new XAttribute("ID", "111111"), 27 new XElement("name", "EricSun"), 28 new XElement("password", "123456"), 29 new XElement("description", "Hello I'm from Dalian") 30 ), 31 new XElement("User", new XAttribute("ID", "222222"), 32 new XElement("name", "Ray"), 33 new XElement("password", "654321"), 34 new XElement("description", "Hello I'm from Jilin") 35 ) 36 ) 37 ); 38 //保存此结构(即:我们预期的xml文件) 39   myXDoc.Save(xmlPath); 40 } 41 catch (Exception ex) 42 { 43 Console.WriteLine(ex.ToString()); 44 } 45 } 46 }

【注:由于使用了Linq to xml的方式,所以要引入命名空间System.Xml.Linq】,通过运行上面这段代码,就可以创建我们预想的xml文件结构,并且可以看出用 Linq这种方式,在代码中就可以很清楚明了知道我们创建xml文件的结构(如:构造函数的参数所示)

②:【遍历xml文件的节点信息】创造出了xml文件之后,我们就要知道如何获得xml文件的各个节点的信息,请看如下代码:

1 private static void GetXmlNodeInforOld(string xmlPath) 2 { 3 try 4 { 5 XDocument myXDoc = XDocument.Load(xmlPath); 6 XElement rootNode = myXDoc.Element("Users"); 7 foreach (XElement node in rootNode.Elements("User")) 8 { 9 Console.WriteLine("User ID = {0}", node.Attribute("ID").Value); 10 11 string name = node.Element("name").Value; 12 string password = node.Element("password").Value; 13 string description = node.Element("description").Value; 14 Console.WriteLine("name = {0} \npassword = {1} \ndescription = {2}", name, password, description); 15 } 16 } 17 catch (Exception ex) 18 { 19 Console.WriteLine(ex.ToString()); 20 } 21 } 22 23 private static void GetXmlNodeInformation(string xmlPath) 24 { 25 try 26 { 27 //定义并从xml文件中加载节点(根节点) 28   XElement rootNode = XElement.Load(xmlPath); 29 //查询语句: 获得根节点下name子节点(此时的子节点可以跨层次:孙节点、重孙节点......) 30   IEnumerable<XElement> targetNodes = from target in rootNode.Descendants("name") 31 select target; 32 foreach (XElement node in targetNodes) 33 { 34 Console.WriteLine("name = {0}", node.Value); 35 } 36 37 //查询语句: 获取ID属性值等于"111111"并且函数子节点的所有User节点(并列条件用"&&"符号连接) 38   IEnumerable<XElement> myTargetNodes = from myTarget in rootNode.Descendants("User") 39 where myTarget.Attribute("ID").Value.Equals("111111") && myTarget.HasElements 40 select myTarget; 41 foreach (XElement node in myTargetNodes) 42 { 43 Console.WriteLine("name = {0}", node.Element("name").Value); 44 Console.WriteLine("password = {0}", node.Element("password").Value); 45 Console.WriteLine("description = {0}", node.Element("description").Value); 46 } 47 } 48 catch (Exception ex) 49 { 50 Console.WriteLine(ex.ToString()); 51 } 52 }

上 面用了两种方法去实现对xml文件节点信息的读取,第一种方法是那种比较老的模式:通过父节点获得它的子节点(一层一层的获得),然后获取目标节点的信 息;第二中方法用到的是Linq to xml的查询模式,根据我们的需求获得符合条件的所有节点,然后对这些节点的信息进行读取。

接下来我们要简单的讲述一下Linq to xml的查询模式(语法一看便懂,这里就不过多阐述了),LINQ to XML 的一个最重要的性能优势(与 XmlDocument 相比)为:LINQ to XML 中的查询是静态编译的,而 XPath 查询则必须在运行时进行解释,此功能是 LINQ to XML 的内置功能。

在 调试程序的时候我们发现,第二种方法的IEnumerable<XElement> targetNodes = from target in rootNode.Descendants(“name”) select target;的这句话执行完毕后,得到的targetNodes依然是null,直到遍历的时候才获得相应的对象信息,这种方式就做延迟执行,【延迟执行】:意味着表达式的计算延迟,直到真正需要它的实现值为止。 当必须操作大型数据集合,特别是在包含一系列链接的查询或操作的程序中操作时,延迟执行可以大大改善性能。 在最佳情况下,延迟执行只允许对源集合的单个循环访问。

【注:查询条件写在where语句中,并列条件用”&&”符号连接,或条件用”||”符号连接】

③:【修改xml文件的节点信息】知道了如何查询xml文件的节点信息之后,对相应节点信息做相应的修改,就显得很容易了。请看如下代码:

1 private static void ModifyXmlNodeInforOld(string xmlPath) 2 { 3 try 4 { 5 XDocument myXDoc = XDocument.Load(xmlPath); 6 myXDoc.Element("Users").Element("User").Attribute("ID").Value = "777777"; 7 foreach (XElement node in myXDoc.Element("Users").Elements("User").Elements("description")) 8 { 9 node.SetValue("Hello, I'm from China."); 10 } 11 myXDoc.Save(xmlPath); 12 } 13 catch (Exception ex) 14 { 15 Console.WriteLine(ex.ToString()); 16 } 17 } 18 19 private static void ModifyXmlNodeInformation(string xmlPath) 20 { 21 try 22 { 23 //定义并从xml文件中加载节点(根节点) 24 XElement rootNode = XElement.Load(xmlPath); 25 //查询语句: 获取ID属性值等于"222222"或者等于"777777"的所有User节点(或条件用"||"符号连接) 26 IEnumerable<XElement> targetNodes = from target in rootNode.Descendants("User") 27 where target.Attribute("ID").Value == "222222" || target.Attribute("ID").Value.Equals("777777") 28 select target; 29 //遍历所获得的目标节点(集合) 30 foreach (XElement node in targetNodes) 31 { 32 //将description节点的InnerText设置为"Hello, I'm from USA." 33 node.Element("description").SetValue("Hello, I'm from USA."); 34 } 35 //保存对xml的更改操作 36 rootNode.Save(xmlPath); 37 } 38 catch (Exception ex) 39 { 40 Console.WriteLine(ex.ToString()); 41 } 42 }

这里也用了两种方法去获取相应节点信息的,具体过程请看代码就可以啦。

④:【向xml文件添加节点信息】下面的代码是向原有xml文件中添加一个节点

1 private static void AddXmlNodeInformation(string xmlPath) 2 { 3 try 4 { 5 //定义并从xml文件中加载节点(根节点) 6 XElement rootNode = XElement.Load(xmlPath); 7 //定义一个新节点 8 XElement newNode = new XElement("User", new XAttribute("ID","999999"), 9 new XElement("name", "Rose"), 10 new XElement("password", "456123"), 11 new XElement("description", "Hello, I'm from UK.")); 12 //将此新节点添加到根节点下 13 rootNode.Add(newNode); 14 //保存对xml的更改操作 15 rootNode.Save(xmlPath); 16 } 17 catch (Exception ex) 18 { 19 Console.WriteLine(ex.ToString()); 20 } 21 }

简单做一个总结:下面的方法将子内容添加到 XElement 或 XDocument 中:

方法                 说明

Add                  在 XContainer 的子内容的末尾添加内容。

AddFirst           在 XContainer 的子内容的开头添加内容。

下面的方法将内容添加为 XNode 的同级节点。 向其中添加同级内容的最常见的节点是 XElement,不过你也可以将有效的同级内容添加到其他类型的节点,

例如 XText 或 XComment。

方法                         说明

AddAfterSelf            在 XNode 后面添加内容。

AddBeforeSelf          在 XNode 前面添加内容。

⑤:【删除指定xml文件的节点信息】如何将刚刚加入的那个节点删除掉呢?请看如下代码:

1 private static void DeleteXmlNodeInformation(string xmlPath) 2 { 3 try 4 { 5 //定义并从xml文件中加载节点(根节点) 6 XElement rootNode = XElement.Load(xmlPath); 7 //查询语句: 获取ID属性值等于"999999"的所有User节点 8 IEnumerable<XElement> targetNodes = from target in rootNode.Descendants("User") 9 where target.Attribute("ID").Value.Equals("999999") 10 select target; 11 12 //将获得的节点集合中的每一个节点依次从它相应的父节点中删除 13 targetNodes.Remove(); 14 //保存对xml的更改操作 15 rootNode.Save(xmlPath); 16 } 17 catch (Exception ex) 18 { 19 Console.WriteLine(ex.ToString()); 20 } 21 }

至此,我们就完成对xml文件的基本操作:创建、读取、修改、添加、删除。由于刚刚学习Linq,理解的很浅显,如有不合适的地方,欢迎大家指出~~

[转载]android中隐藏的layout 抽屉的运用

mikel阅读(1098)

[转载]android中隐藏的layout 抽屉的运用 – noTice520 – 博客园.

最近在写一个应 用,想把设置页面和应用页面放在一起,这样就能实现用户可以实时看到自己的设置对UI的影响,从而更方便的设置用户喜欢的界面。想了一段时间,发现用 slidingDrawer这个控件可以实现这个效果。也就是一个抽屉。拉开抽屉,占据半个屏幕,另外半个屏幕还是显示应用页面。效果还是不错的。

今天就和大家分享一下Android中这个抽屉效果。其实在Android的lanucher就是一个抽屉,打开它就可以看到安装的应用。相信大家都见过用过。下面我们就来做个相同的效果,当然只是UI上差不多相同的效果。

slidingDrawer这个控件使用非常简单,基本在xml里面配置就可以。代码如下所示。

<?xml version=”1.0″ encoding=”utf-8″?>
<RelativeLayout
xmlns:Android=”http://schemas.android.com/apk/res/android
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
>
<TextView
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”@string/hello”
android:textSize=”20sp”
/>
<SlidingDrawer
android:id=”@+id/sd”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:handle=”@+id/iv”
android:content=”@+id/myContent”
android:orientation=”vertical”
>

<ImageView
android:id=”@+id/iv”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:src=”@drawable/open1″
/>

<GridView
android:id=”@id/myContent”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:numColumns=”3″
android:background=”@drawable/background”
android:gravity=”center”
/>

</SlidingDrawer>
</RelativeLayout>

在SlidingDrawer这个标签下android:handle:指示的就是抽屉的图片。android:content:指向的就是抽屉里面的布局。有了这个布局,其实一个抽屉就出来了。

下面我们看Chouti这个类的代码

public class Chouti extends Activity {

private GridView gv;
private SlidingDrawer sd;
private ImageView iv;
private int[] icons={R.drawable.browser,R.drawable.gallery,
R.drawable.camera,R.drawable.gmail,
R.drawable.music,R.drawable.market,
R.drawable.phone,R.drawable.messages,R.drawable.maps};
private String[] items={“浏览器”,”图片”,”相机”,”时钟”,”音乐”,”市场”,”拨号”,”信息”,”地图”};

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
gv = (GridView)findViewById(R.id.myContent);
sd = (SlidingDrawer)findViewById(R.id.sd);
iv=(ImageView)findViewById(R.id.iv);
MyAdapter adapter=new MyAdapter(this,items,icons);//自定义MyAdapter来实现图标加item的显示效果
gv.setAdapter(adapter);
sd.setOnDrawerOpenListener(new SlidingDrawer.OnDrawerOpenListener()//开抽屉
{
@Override
public void onDrawerOpened()
{
iv.setImageResource(R.drawable.close1);//响应开抽屉事件 ,把图片设为向下的
}
});
sd.setOnDrawerCloseListener(new SlidingDrawer.OnDrawerCloseListener()
{
@Override
public void onDrawerClosed()
{
iv.setImageResource(R.drawable.open1);//响应关抽屉事件
}
});
}
}

在整个类里面将布局导入,同时设置开关抽屉的监听事件。这里面我们需要自定义一个MyAdapter来显示带文字下标的图片。

下面是MyAdapter这个类的代码
public class MyAdapter extends BaseAdapter
{
private Context _ct;
private String[] _items;
private int[] _icons;

public MyAdapter(Context ct,String[] items,int[] icons) //构造器
{
_ct=ct;
_items=items;
_icons=icons;
}

@Override
public int getCount()
{
return _items.length;
}

@Override
public Object getItem(int arg0)
{
return _items[arg0];
}

@Override
public long getItemId(int position)
{
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater factory = LayoutInflater.from(_ct);
View v = (View) factory.inflate(R.layout.gv, null);//绑定自定义的layout
ImageView iv = (ImageView) v.findViewById(R.id.icon);
TextView tv = (TextView) v.findViewById(R.id.text);
iv.setImageResource(_icons[position]);
tv.setText(_items[position]);
return v;
}
}

也是非常的简单,其中用到的布局如下

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout
xmlns:android=”http://schemas.android.com/apk/res/android
android:orientation=”vertical”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
>
<ImageView
android:id=”@+id/icon”
android:layout_width=”wrap_content”
android:layout_height=”40px”
android:layout_gravity=”center”
/>
<TextView
android:id=”@+id/text”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:gravity=”center”
android:textColor=”#ffffffff”
/>
</LinearLayout>

这样,我们的抽屉就完成啦 来看下效果

就写这么多啦。抽屉这个控件非常实用,除了我在开头所说的我在程序中的应用外,还有很多的用途, 发挥你的想象力,抽屉将为你的应用增色不少。

[转载]以异步的方式操作TCP/IP套接字—以异步方式实现简单的聊天室

mikel阅读(969)

[转载]以异步的方式操作TCP/IP套接字——以异步方式实现简单的聊天室 – 风尘浪子 – 博客园.

普通的TCP/IP开发方式大家都应该非常熟练,但在系统开发的时候往往会遇到问题。

比如:在开发一个简单的聊天室的时候,一般情况下,Windows应用程序会处于同步方式运行,当监听的客户端越多,服务器的负荷将会越重,信息发送与接收都会受到影响。这时候,我们就应该尝试使用异步的TCP/IP通讯来缓解服务器的压力。

下面以一个最简单的聊天室服务器端的例子来说明异步TCP/IP的威力,先开发一个ChatClient类作为客户管理的代理类,每当服务器接收到信息时,就会把信息处理并发送给每一个在线客户。

void Main()
{
IPAddress ipAddress = IPAddress.Parse(“127.0.0.1”
);            //默认地址
TcpListener tcpListener = new TcpListener(ipAddress,500
);
tcpListener.Start();
while
(isListen)                //以一个死循环来实现监听
{
ChatClient chatClient = new
ChatClient(tcpListener.AcceptTcpClient());    //调用一个ChatClient对象来实现监听

}
tcpListener.Stop();

}


ChatClient中存在着一个Hashtabel类的静态变量 clients,此变量用来存贮在线的客户端信息,每当对一个客户端进行监听时,系统就生成一个ChatClient对象,然后在变量clients中加 入此客户端的信息。在接收客户端信息时,信息会调用Receive(IAsyncResult async)方法,把接收到的信息发送给每一个在线客户。

值得注意的是,每当接收到客户信息时,系统都会利用Stream.BeginRead()的方法去接收信息,然后把信息发送到每一个在线客户,这样做就可以利用异步的方式把信息进行接收,从而令主线程及早得到释放,提高系统的性能。

public class ChatClient

{
private
TcpClient _tcpClient;
private byte
[] byteMessage;
private string _clientEndPoint;

public volatile string message;
public static Hashtable clients= new
Hashtable();          //以此静态变量存处多个客户端地址

public ChatClient(TcpClient tcpClient)
{
_tcpClient =
tcpClient;
_clientEndPoint =
_tcpClient.Client.RemoteEndPoint.ToString();
Console.WrtieLine(“连接成功,客户端EndPoint为”+_clientEndPoint);

ChatClient.clients.Add(_clientEndPoint, this
);       //每创建一个对象,就会将客户端的ChatClient对象存入clients;

byteMessage=new byte[_tcpClient.ReceiveBufferSize];

lock (_tcpClient.GetStream())        //接收信息,使用lock避免数据冲突

{

_tcpClient.GetStream().BeginRead(byteMessage, 0, _tcpClient.ReceiveBufferSize, new AsyncCallback(Receive), null);

//就在此处使用异步的IO线程进行数据读取,这样每个一客户端的都处于一个IO线程中处理,使主线程及早得到释放

//这样做就缓解了服务器端压力。
}
}

public void Receive(IAsyncResult iAsyncResult)
{
try

{
int length;

lock (_tcpClient.GetStream())    //信息接收,使用lock避免数据冲突
{
length=
_tcpClient.GetStream().EndRead(iAsyncResult);
}
if (length < 1
)
{
MessageBox.Show(_tcpClient.Client.RemoteEndPoint + “已经断线”
);
clients.Remove(_tcpClient);
return
;
}

message=Encoding.Unicode.GetString(byteMessage,0,length);
SendToEveryone(message);

//在此时我们可以在此处调用SendToEveryone方法,利用clients变量以Stream.Write方法为每个客户端发送信息。


lock
(_tcpClient.GetStream())    //再次监听,使用lock避免数据冲突
{
_tcpClient.GetStream().BeginRead(byteMessage, 0, _tcpClient.ReceiveBufferSize, new AsyncCallback(Receive), null
);

//再次调用Stream.BeginRead方法,以监听以下次客户的信息
}
}
catch
(Exception ex)
{
clients.Remove(_tcpClient);
_tcpClient.GetStream().Close();
_tcpClient.Close();
}
}

//通过Send方法把信息转换成二进制数据,然后发送到客户端

public void Send(string message)
{
try
{
NetworkStream ns;
lock (_tcpClient.GetStream())
{
ns = _tcpClient.GetStream();
}
byte[] byteMessage = Encoding.ASCII.GetBytes(message);
ns.Write(byteMessage, 0, byteMessage.Length);
ns.Flush();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

//由于客户端信息记录在HashTabel变量clients中,当信息接收后,就会通过此变量把信息发送给每一个在线客户。

public void SendToEveryone(string message)
{
foreach (DictionaryEntry client in clients)
{
ChatClient chatClient = (ChatClient)client.Value;
chatClient.Send(message);
}
}

}

测试结果:

至于窗口的设计和客户端的设计在这里就省略不说,这里的目的只是要你了解服务器端多线程TCP/IP信息接收的原理。

这个例子里,ChatClient类使用异步的IO线程进行数据读取,这样每个一客户端的都处于一个IO线程中处理,使主线程及早得到释放,这样做就缓解了服务器端压力。

这时候你可以做一个测试,此聊天室在默认情况下可接受大约3000个客户端连接,仍然能够正常工作。

[转载]Android 中文 API (100) —— ScrollView

mikel阅读(1035)

[转载]Android 中文 API (100) —— ScrollView – 农民伯伯 – 博客园.

前言

春节即至,谨代表Android中文翻译组全体同仁祝大家身体健 康,工作顺利!从第一篇译稿2010年8月27发布至今天2011年1月27整5个月,共发布100篇译文,3个合集,在新的一年里,翻译组仍将坚持 Android相关的翻译工作,秉承开源、合作、共享和坚持的信念打持久战,感谢大家的关心和支持!

本章内容是 android.widget.ScrollView,版本为Android 2.3 r1,翻译来自”pengyouhong”,再次感谢”pengyouhong” !期待你一起参与Android API的翻译,联系我over140@gmail.com。

声明

欢迎转载,但请保留文章原始出处:)

博客园:http://www.cnblogs.com/

Android中文翻译组:http://goo.gl/6vJQl

正文

一、结构

public class ScrollView extends FrameLayout

java.lang.Object

android.view.View

android.view.ViewGroup

android.widget.FrameLayout

android.widget.ScrollView

二、概述

一种可供用户滚动的层次结构布局容器,允许显示比实际多的内容。ScrollView是一种FrameLayout,意味需要在其上放置有自己滚动内容的子元素。子元素可以是一个复杂的对象的布局管理器。通常用的子元素是垂直方向的LinearLayout,显示在最上层的垂直方向可以让用户滚动的箭头。

TextView类也有自己的滚动功能,所以不需要使用ScrollView,但是只有两个结合使用,才能保证显示较多内容时候的效率。但只有两者结合使用才可以实现在一个较大的容器中一个文本视图效果。

ScrollView只支持垂直方向的滚动。

三、构造函数

public ScrollView (Context context)

创建一个默认属性的ScrollView实例。

public ScrollView (Context context, AttributeSet attrs)

创建一个带有attrs属性的ScrollView 实例。

public ScrollView (Context context, AttributeSet attrs, int defStyle)

创建一个带有attrs属性,并且指定其默认样式的ScrollView实例。

四、公共方法

public void addView (View child)

添加子视图。如果事先没有给子视图设置layout参数,会采用当前ViewGroup的默认参数来设置子视图。

参数

child 所添加的子视图

public void addView (View child, int index)

添加子视图。如果事先没有给子视图设置layout参数,会采用当前ViewGroup的默认参数来设置子视图。

参数

child 所添加的子视图

index 添加子视图的位置

public void addView (View child, int index, ViewGroup.LayoutParams params)

根据指定的layout参数添加子视图

参数

child 所添加的子视图

index 添加子视图的位置

params 为子视图设置的layout参数

public void addView (View child, ViewGroup.LayoutParams params)

根据指定的layout参数添加子视图。

参数

child 所添加的子视图

params 为子视图设置的layout参数

public boolean arrowScroll (int direction)

响应点击上下箭头时对滚动条滚动的处理。

参数

direction 按下的箭头所对应的方向

返回值

如果我们处理(消耗)了此事件返回true,否则返回false

public void computeScroll ()

被父视图调用,用于必要时候对其子视图的值(mScrollX和mScrollY)进行更新。典型的情况如:父视图中某个子视图使用一个Scroller对象来实现滚动操作,会使得此方法被调用。

public boolean dispatchKeyEvent (KeyEvent event)

发送一个key事件给当前焦点路径的下一个视图。此焦点路径从视图树的顶层执行直到当前焦点视图。如果此视图为焦点视图,将为自己发送。否则,会为当前焦点路径的下一个节点发送。此方法也会激起一个key监听器。

参数

event 发送的key事件

返回值

事件被处理返回true,否则返回false

public void draw (Canvas canvas)

手动绘制视图(及其子视图)到指定的画布(Canvas)。这个视图必须在调用这个函数之前做好了整体布局。当实现一个视图时,不需要继承这个方法;相反,你应该实现onDraw(Canvas)方法。

参数

canvas 绘制视图的画布

public boolean executeKeyEvent (KeyEvent event)

当接收到key事件时,用户可以调用此函数来使滚动视图执行滚动,类似于处理由视图体系发送的事件。

参数

event 需要执行key的事件

返回值

事件被处理返回true,否则返回false

public void fling (int VelocityY)

滚动视图的滑动(fling)手势。(译者注: 如何监听android的屏幕滑动停止事件

参数

VelocityY Y方向的初始速率。正值表示手指/光标向屏幕下方滑动,而内容将向上滚动。

public boolean fullScroll (int direction)

对响应“home/end”短按时响应滚动处理。此方法将视图滚动到顶部或者底部,并且将焦点置于新的可视区域的最顶部/最底部组件。若没有适合的组件做焦点,当前的ScrollView会收回焦点。

参数

direction 滚动方向:FOCUS_UP表示视图向上滚动;FOCUS_DOWN表示视图向下滚动

返回值

key事件被消耗(consumed)返回true,其他情况返回false

public int getMaxScrollAmount ()

返回值

当前滚动视图响应箭头事件能够滚动的最大数。

public boolean isFillViewport ()

指示当前ScrollView的内容是否被拉伸以填充视图可视范围(译者注:viewport可视范围,参见决定Scrollviewer里面Control的可视范围)。

返回值

内容填充视图返回true,否则返回false

public boolean isSmoothScrollingEnabled ()

返回值

按箭头方向滚动时,是否显示滚动的平滑效果。

public boolean onInterceptTouchEvent (MotionEvent ev)

实现此方法是为了拦截所有触摸屏幕时的运动事件。可以像处理发送给子视图的事件一样去监视这些事件,并且获取当前手势在任意点的ownership

使用此方法时候需要注意,因为它与View.onTouchEvent(MotionEvent)有相当复杂的交互,并且前提需要正确执行View.onTouchEvent(MotionEvent)。事件将按照如下顺序接收到:

1. 收到down事件

2. Down事件或者由视图组的一个子视图处理,或者被用户自己的onTouchEvent()方法处理;此处理意味你应该执行onTouchEvent()时返回true,这样才能继续看到剩下的手势(取代找一个父视图处理)。如果onTouchEvent()返回true时,你不会收到onInterceptTouchEvent()的任何事件并且所有对触摸的处理必须在onTouchEvent()中发生。

3. 如果此方法返回false,接下来的事件(up to and including the final up)将最先被传递当此,然后是目标的onTouchEvent()

4. 如果返回true,将不会收到以下任何事件:目标view将收到同样的事件但是会伴随ACTION_CANCEL,并且所有的更进一步的事件将会传递到你自己的onTouchEvent()方法中而不会再在这里出现。

参数

ev 体系向下发送的动作事件

返回值

如果将运动事件从子视图中截获并且通过onTouchEvent()发送到当前ViewGroup ,返回true。当前目标将会收到ACTION_CANCEL事件,并且不再会有其他消息传递到此。

(译者注:onInterceptTouchEventonTouchEvent调用时序

public boolean onTouchEvent (MotionEvent ev)

执行此方法为了处理触摸屏幕的运动事件。

参数

ev 运动事件

返回值

事件被处理返回true,其它返回false

public boolean pageScroll (int direction)

响应短按“page up/ down”时候对滚动的处理。此方法将向上或者向下滚动一屏,并且将焦点置于新可视区域的最上/最下。如果没有适合的component作为焦点,当前scrollView将收回焦点。

参数

direction 滚动方向:FOCUS_UP表示向上翻一页,FOCUS_DOWN表示向下翻一页。

返回值

key事件被消耗(cosumed)返回true,其他返回false

public void requestChildFocus (View child, View focused)

当父视图的一个子视图的要获得焦点时,调用此方法。

参数

child 要获得焦点的父视图的子视图。此视图包含了焦点视图。如果没有特殊徐要求,此视图实际上就是焦点视图。

focused 子视图的子孙视图并且此子孙视图是真正的焦点视图

public boolean requestChildRectangleOnScreen (View child, Rect rectangle, boolean immediate)

当组里的某个子视图需要被定位在屏幕的某个矩形范围时,调用此方法。重载此方法的ViewGroup可确认以下几点:

* 子项目将是组里的直系子项

* 矩形将在子项目的坐标体系中

重载此方法的ViewGroup应该支持以下几点:

* 若矩形已经是可见的,则没有东西会改变

* 为使矩形区域全部可见,视图将可以被滚动显示

参数

child 发出请求的子视图

rectangle 子项目坐标系内的矩形,即此子项目希望在屏幕上的定位

immediate 设为true,则禁止动画和平滑移动滚动条

返回值

进行了滚动操作的这个组(group),是否处理此操作。

public void requestLayout ()

当有改变引起当前视图重新布局时,调用此函数。它将规划一个视图树的layout路径。

public void scrollTo (int x, int y)

设置当前视图滚动到的位置。此函数会引起对onScrollChanged(int, int, int, int)函数的调用并且会让视图更新。

当前版本取消了在子视图中的滚动。

参数

x 滚动到的X位置

y 滚动到的Y位置

public void setFillViewport (boolean fillViewport)

设置当前滚动视图是否将内容高度拉伸以填充视图可视范围(译者注:viewport可视范围,参见决定Scrollviewer里面Control的可视范围)。

参数

fillViewport 设置为true表示拉伸内容高度来适应视口边界;其他设为false

public void setOverScrollMode (int mode)

为视图设置over-scroll模式。有效的over-scroll模式有OVER_SCROLL_ALWAYS(缺省值),OVER_SCROLL_IF_CONTENT_SCROLLS(只允许当视图内容大过容器时,进行over-scrolling)和OVER_SCROLL_NEVER。只有当视图可以滚动时,此项设置才起作用。

译者注:这个函数是2.3 r1 中新增的,API Level 9关于over-scroll这里译为弹性滚动,即,参见帖子:类似iPhone的弹性ListView滚动

参数

mode       The new over-scroll mode for this view.

public void setSmoothScrollingEnabled (boolean smoothScrollingEnabled)

用来设置箭头滚动是否可以引发视图滚动。

参数

smoothScrollingEnabled 设置箭头滚动是否可以引起内容的滚动的bool

public final void smoothScrollBy (int dx, int dy)

类似于scrollBy(int, int),但是滚动时候是平缓的而不是立即滚动到某处。

参数

dx X方向滚动的像素数

dy Y方向滚动的像素数

public final void smoothScrollTo (int x, int y)

类似于scrollTo(int, int),但是滚动时候是平缓的而不是立即滚动到某处。

参数

x 要滚动到位置的X坐标

y 要滚动到位置的Y坐标

五、受保护方法

protected int computeScrollDeltaToGetChildRectOnScreen (Rect rect)

计算X方向滚动的总合,以便在屏幕上显示子视图的完整矩形(或者,若矩形宽度超过屏幕宽度,至少要填满第一个屏幕大小)。

参数

rect 矩形

返回值

滚动差值

protected int computeVerticalScrollOffset ()

计算垂直方向滚动条的滑块的偏移。此值用来计算滚动条轨迹的滑块的位置。

范围可以以任意单位表示,但是必须与computeVerticalScrollRange()computeVerticalScrollExtent()的单位一致。

缺省的偏移是在当前视图滚动的偏移。

返回值

滚动条的滑块垂直方向的偏移。

protected int computeVerticalScrollRange ()

滚动视图的可滚动范围是所有子元素的高度。

返回值

由垂直方向滚动条代表的所有垂直范围,缺省的范围是当前视图的画图高度。

protected float getBottomFadingEdgeStrength ()

返回滚动底部的能见度。能见度的值的范围是0.0(没有消失)到1.0(完全消失)之间。缺省的执行返回值为0.0或者1.0,而不是他们中间的某个值。滚动时子类需要重载这个方法来提供一个平缓的渐隐的实现。

返回值

滚动底部能见度,值的范围在浮点数0.0f1.0f之间。

protected float getTopFadingEdgeStrength ()

返回滚动顶部的能见度。能见度的值的范围是0.0(没有消失)到1.0(完全消失)之间。缺省的执行返回值为0.0或者1.0,而不是他们中间的某个值。滚动时子类需要重载这个方法来提供一个平缓的渐隐的实现。

返回值

滚动顶部能见度,值的范围在浮点数0.0f1.0f之间。

protected void measureChild (View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec)

要求当前视图的一个子视图测量自己,同时兼顾到当前视图的MeasureSpec的要求和它的空白。子视图必须有MarginLayoutParams。比较复杂的工作是在getChildMeasureSpec中完成的。

参数

child 需要自己测量的子视图

parentWidthMeasureSpec 当前视图要求的宽度

parentHeightMeasureSpec 当前视图要求的宽度

protected void measureChildWithMargins (View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed)

要求当前视图的一个子视图测量自己,同时兼顾到当前视图的MeasureSpec的要求和它的空白和边界。子视图必须有MarginLayoutParams。比较复杂的工作是在getChildMeasureSpec中完成的。

参数

child 需要测量的子视图

parentWidthMeasureSpec 当前视图要求的宽度

widthUsed 水平方向上由父视图使用的空白 (也可能是视图的其他子视图使用的)

parentHeightMeasureSpec 当前视图要求的宽度

heightUsed 垂直方向上由父视图使用的空白 (也可能是视图的其他子视图使用的)

protected void onLayout (boolean changed, int l, int t, int r, int b)

当前视图需要为子视图分配大小和位置时候调用,子类继承必须要重载此方法并调用自己子视图的layout函数。

参数

changed 当前视图的新的大小或者位置

l 相对父视图,左边界位置

t 相对父视图,上边界位置

r 相对父视图,右边界位置

b 相对父视图,下边界位置

protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)

测量视图以确定其内容宽度和高度。此方法被measure(int, int)调用。需要被子类重写以提供对其内容准确高效的测量。

约定:当重写此方法时,你必须调用setMeasuredDimension(int, int)来保存当前视图view的宽度和高度。不成功调用此方法将会导致一个IllegalStateException异常,是由measure(int, int)抛出。所以调用父类的onMeasure(int, int)方法是必须的。

父类的实现是以背景大小为默认大小,除非MeasureSpec(测量细则)允许更大的背景。子类可以重写onMeasure(int,int)以对其内容提供更佳的尺寸。

如果此方法被重写,那么子类的责任是确认测量高度和测量宽度要大于视图view的最小宽度和最小高度(getSuggestedMinimumHeight() getSuggestedMinimumWidth()),使用这两个方法可以取得最小宽度和最小高度。

参数

widthMeasureSpec   受主窗口支配的水平空间要求。这个需求通过 View.MeasureSpec.进行编码。

heightMeasureSpec 受主窗口支配的垂直空间要求。这个需求通过 View.MeasureSpec.进行编码。

protected void onOverScrolled (int scrollX, int scrollY, boolean clampedX, boolean clampedY)

overScrollBy(int, int, int, int, int, int, int, int, boolean)调用,来对一个over-scroll操作的结果进行响应。(译者注:这个函数是2.3 r1 中新增的,API Level 9

参数

scrollX 新的X滚动像素值

scrollY 新的Y滚动像素值

clampedX scrollXover-scroll的边界限制时,值为true

clampedY scrollYover-scroll的边界限制时,值为true

protected boolean onRequestFocusInDescendants (int direction, Rect previouslyFocusedRect)

当在滚动视图的子视图中查找焦点视图时,需要注意不要将焦点设置在滚动出屏幕外的控件上。此方法会比执行缺省的ViewGroup代价高,否则此行为也会设置为缺省

参数

direction 指定下列常量之一:FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT

previouslyFocusedRect 能够给出一个较好的提示的矩形(当前视图的坐标系统)表示焦点从哪里得来。如果没有提示为null

返回值

是否取得了焦点

protected void onSizeChanged (int w, int h, int oldw, int oldh)

布局期间当视图的大小发生改变时调用。如果只是添加到视图,调用时显示的是旧值0。(译者注:也就是添加到视图时,oldwoldh返回的是0)。

参数

w 视图当前宽度

h 视图当前高度

oldw 视图改变前的宽度

oldh 视图改变前的高度

六、补充

七、译者其他译文

android 中文 api (64) —— Scroller

八、通知

由于年前事情较多,合集4将推迟到年后发布,时间约为2011年2月9日或10日,请大家谅解 🙂

[转载]Hadoop in Action 翻译 第一章

mikel阅读(833)

[转载]Hadoop in Action 翻译 第一章 – 王新的博客 – 博客园.

Hadoop介绍

内容简介:

1. 编写可扩展的,分布式的,海量数据处理的程序的基础

2. 介绍hadoopMapREduce

3. 编写一个简单的MapReduce程序

今天,我们被数据所围绕,人们上传视频,手机拍照,给朋友发信息,更新facebook状态,论坛回帖,点击广告,等等.另外,机器本身也在不停的产生大量数据.甚至也许各位看官就在电脑旁读着电子书,当然,你的购买记录已经记录在书店的系统之中了.

海量数据的不停增长,现在已经给各大厂商带来了极大地挑战.他们需要在以兆记的数据中挖掘出有用的信息,比如哪些网页是大众喜闻乐见的,等等信息.Google是第一个公布使用MapReduce系统来处理他们的快速增长的数据的大型互联网企业。

由于各大厂商也遇到了同样的问题(scaling challenges),我们不可能指望每个遇到这种问题的厂商都自己去开发一套类似与Google MapReduce的产品,所以Hadoop框架迅速引起了大家的关注 .DC 认识到这是一个机会,进而开发了一套开源的mapReduce 系统,也就是我们所说的Hadoop.不久,Yahoo等厂商就迅速投入到这个项目中,支持这个项目.今天,Hadoop 已经成为了很多大型互联网公司的基础技术设施了,其中包括Yahoo Facebook LinkedIn Twitter.特别是很多传统行业也开始使用这个项目,比如传媒,通信行业等.

很快,编写可扩展的分布式数据处理程序将成为很多程序员的重要技能之一.曾经,我们这样定义一个优秀的程序员,他必须懂关系型数据库,会网络编程,安全编程.相似的,不久,分布式数据处理的能力也将成为程序员的重要技能之一了.本书就是知道你如何快速的将hadoop实践到你的数据处理中.

这一章主要介绍hdoop为何构建distributed system,及分布式系统,以及数据处理系统的.它将让你对mapreduce有一个宏观的认识.一个简单的word counting的例子.我们将讨论hadoop的历史,以及

Why “Hadoop in Action”?

实话实说,我第一次被Hadoop引起兴趣之前也饱受hadoop中的例子教程的打击。Hadoop官方文档非常全面,但是却不能够简单明了的解决我们学习中遇到的问题。而此书的目的就是解决这个问题。此书将引导你快速创建hadoop项目,在实践中告诉你什么是hadoop,而不是关注理论细节。

What is Hadoop?

hadoop 是一个帮助开发者构建处理大量数据并发应用的开源框架。分布式是一个很广的领域。而hadoop的主要特征包括:

可接入,易于接入。—-Hadoop运行在一个大型集群上,或者运行在一些云服务上,客户端可以方便的接入到。

容错性。

可扩展性。

简单

Hadoop 的可接入性与简洁性使其在分布式程序方面有很大的优势。甚至即便是大学中的学生也可以简单快速的构建自己的Hadoop集群。另外,它的容错性与扩展性使其很适合做YahooFacebook等大型网站的后台服务。所以Hadoop在学术界和工业界都很受欢迎。

理解分布式系统与Hadoop

摩尔定律在过去很多年都正常发挥着作用。但是当大型系统遇到系统需要大规模扩展时,摩尔定律似乎就不再像以前那么准确的发挥作用了。很重要一点是程序很可能部署在很多低性能的或者廉价的机器之上。

了解一下目前流行的大型分布式系统,从目前的IO技术的价格成本方面考虑,一台高性能的服务器有4I/O channel。每一个I/O channel100MB/sec的处理能力。那么处理一个4TB的数据集,就会需要3个小时。使用Hadoop,这个数据集,将会被分割微很多小的数据块(一般来说是64MB),这些小块的数据块将会被独立的存放在Hadoop Distributed File SystemHDFS)上。而HDFS是建立在许多廉价机器上的一个集群。即便是谦虚的说,服务器集群会提供更加强大的数据读取速度。而且廉价机器集群的成本要比一个高性能服务器的成本低得多。我们所说的廉价机器就是指的PC机。

以前都用hadoop 与传统体系的系统比较,来凸显hadoop的优势。现在,我们用hadoop与其他分布式系统相比教。SETI@home(在家搜寻外星智慧(地外文明也就是我们常说的外星人)),是一个通过互联网利用家用个人计算机处理天文数据的分布式计算项目。该项目试图通过分析雷西博射电望远镜采集的无线电信号,搜寻能够证实外星智能生物存在的证据。该项目由美国加州大学伯克利分校的空间科学实验室主办。在SETI@home体系中,一个中央存储单独提同空间与服务器,其通过互联网,将分配好的数据分发给每个家用电脑,每个家用电脑经过计算,再将计算好的数据反馈给中央存储。

Hadoop 不同于seti@home之处在于Hadoop物理指向数据。seti@home将数据反复的传送与中央服务器与各个客户端之间。其中传输成本很大,但是如果是计算密集型的数据,那么这种方式是合适的,而hadoop处理的是数据密集型的数据。hadoop处理的数据本事都是非常巨型的。根本无法像SETI@home这种方式将数据在集群中自由的传输。Hadoop关注于移动代码而不是vice versa.对比图1.1,我们看到数据与计算都在hadoop集群内部.客户端只是发送MapReduce程序去执行,并且这些程序常常很小.hadoop集群中移动的是代码而不是无理数据本身数据.数据被分解并分布在集群之中.而且尽可能的每一片数据的处理都集中在一台相同的机器上,既数据数据都在本地处理.

这种传递代码,而不是传递数据的做法就是hadoop针对数据密集型程序所做的特殊设计.程序运行的代码都是短小精悍的而且易于传输的.每次都将要运行的代码传输到数据所在的机器.这样就可以不去动已经保存在机器上的数据了.

Now that you know how Hadoop fits into the design of distributed systems, let’s see

how it compares to data processing systems, which usually means SQL databases.

SQL 数据库 VS. Hadoop

Hadoop是一个数据处理的框架,对于高负荷的数据处理,什么使其优于传统的关系型数据库呢?

其中一个原因就是 SQL是用来处理结构化的数据.hadoop 使用场景往往是非结构化数据,比如text文本数据.从这个观点出发,hadoop提供了more general paradigm than SQL.如果处理的是结构化数据,那么hadoopSQL数据库的差别是微小的.理论上,SQLHadoop都可以处理,作为一种查询语言,也可以在hadoop之上实现一套SQL查询语言,并将其作为数据操作引擎.但是在具体实践中,SQL数据库基本上都已经有很多年的传统了.有一些老牌的数据库提供商,为很多历史悠久的软件提供服务.这些已有的数据库都无法解决hadoop所针对的那些问题.

(略)

理解Hadoop

你也许很喜欢像pipelines和消息队列这样的数据处理模型。这些模型再开发数据处理程序时发挥这很重要的作用。最有名的pipelineUnix pipesPipelines可以复用处理单元;其可以简单的将现有的模块与新模块相链接。消息队列可以异步的处理消息单元,程序员可以控制生产者或者消费者,而其执行时间由系统控制。类似的,MapReduce同样是一个数据处理模型。而其最大的优点在于可以在多台电脑上延展你的数据处理。在此模型之下,数据处理单元称之为mapppersreducers。其在内部将数据处理程序分解为mappersreducers。一旦你使用MapReduce编写你的数据处理程序,将其扩展为一个成百上千台机器上的集群只不过是修改一些配置那么简单而已。简单快速的扩展性正是那么多程序选择MapReduce模型的原因。

1.5.1 Scaling a simple program manually

在正式进入MapReduce之前,我们通过一小段练习,来处理一个大型的数据集,并扩展这个程序。你将看到扩展这个程序的挑战,并且将欣赏MapReduce在扩展性方面给开发人员带来的好处。

这个练习就是计算在一个文档中出现每个单词出现的次数。在这个例子中,我们待处理的文档中只有一句话。

Do as I say, not as I do.

我们将调用这个小例子

define wordCount as Multiset;

for each document in documentSet {

T = tokenize(document);

for each token in T {

wordCount[token]++;

}

}

display(wordCount);

程序将遍历所有文档,在每个文档中,将是用tokenization程序一个一个等计算单词出现的次数。最终display方法将wordCount打印出来。这个程序将运行正常,知道你要处理的文件越来越大。

比 如说,你要建立一个垃圾邮件过滤器,过滤所有的邮件,以便于统计数以百万记的垃圾邮件中每个词汇出现的频率。你将使用数台服务器遍历所有的文档。每台机器 处理不同的文件。当所有的服务器完成这项工作,下一步就是将收集说有服务器上的处理结果。之前看到的伪码,将被部署到多台服务器上,我们将会吧wordCount定义为一个集合,用来存储多台服务器上的运算结果。

第一部分处理单元的代码为:

for each document in documentSubset {

T = tokenize(document);

for each token in T {

wordCount[token]++;

}

}

sendToSecondPhase(wordCount);

第二部分处理单元为:

define totalWordCount as Multiset;

for each wordCount received from firstPhase {

multisetAdd (totalWordCount, wordCount);

}

看上去,这并不难,但是一些细节问题将会阻碍它像我们想象中的运行。

首 先,我们忽略了读取文件的性能。如果所有的文件存储在一个中央存储服务器上,那么这台服务器的总线带宽将成为一个传输瓶颈。更多的数据处理服务器将提升数 据处理的能力,但是数据存储服务器并不能一直维持性能,因为它有限的带宽无法及时的将需要处理的数据发往各个数据处理服务器上去。所以我们需要先将这些文 件分分别存到各个数据处理服务器上去。这样当各个数据处理服务器需要处理数据时,就不用再从中央存储服务器上获取文件了。特别要重申的是,对于数据密集型 应用程序来说,将数据存储与数据处理放置在统一台服武器上,是非常重要的。

另外一个问题就是最终的结果集存储在内存中。当数据量超大时,请不要将数据结果集存放在服务器内存中,这样做很可能会超出内存数据存储的极限。比如wordCount中不仅仅只是存储英文单词,还包括所有可能存在的字母组合,所有其数据集的大小很难把握。

OkwordCount也许不太适合存储在内存中了;我们将不得不修改我们的程序,将其存储在硬盘中。这意味着我们将实现一个基于硬盘的hash table, 这意味着我们将写大量的代码。此外,我们的第二部分处理单元(就是汇总所有处理结果的部分)只有一台服务器,这的确显得有点笨拙。特别是如果我们在第一部 分处理单元中使用多台服务器用于处理数据,我们的第二部分处理单元(就是汇总所有处理结果的部分)必将成为一个瓶颈。此时我们理所应当的想法就是以分布式 的形式,使用多台服务器处理这部分数据。为了在这部分数据处理中使用分布式,我们就需要将数据分割,以便与在多台服务器上独立计算。你需要将第一部分处理 完的数据以某种形式分割,比如现在有26台服务器用于处理第二部分,那么你就可以按照首字母的顺序,将所有结果集分为26个部分,将其分布到26台服务器上进行第二部分的处理,这26台服务器中的每一台服务器都处理以某个大写字母开头的单词。不同与单机版的wordConunt,此时我们将有26wordCount wordCount-a, wordCount-b等等。此时,我们要对第一部分处理单元做一下调整。当第一部分数据处理时,将数据按照首字母分割一次。这样将其处理完毕后,每台处理第一部分数据的服务器都会将wordCount-a 发往处理A字母开头的单词的服务器上去。以此类推,每台处理第二部数据单元的服务器都会处理一个字母开头的单词。终于,这个分布式的计数器程序就可以完工了。为了使其工作在分布式集群上,我们需要增加或者修改一些处理流程:

1. 再多台服务器上存储并处理数据。

2. 在硬盘上存放数据的处理结果,而不是内存中。

3. 将第一部分的数据结果集在每台服务器上先分割好,以备于第二次数据处理时用。

4. 将第一部分处理好,并分割好的数据分发给第二部分数据处理单元的机器集群。

靠,我们只是想做一个简单的单词计数器,竟然要高的如此复杂,这还没有考虑容错问题呢。这也就是为什么我们需要hadoop这种框架的原因了。

Scaling the same program in MapReduce(待续)

MapReduce programs are executed in two main phases, called mapping and reducing.

Each phase is defined by a data processing function, and these functions are called

mapper and reducer, respectively. In the mapping phase, MapReduce takes the input

data and feeds each data element to the mapper. In the reducing phase, the reducer

processes all the outputs from the mapper and arrives at a final result.

In simple terms, the mapper is meant to filter and transform the input into something

that the reducer can aggregate over. You may see a striking similarity here with the two

phases we had to develop in scaling up word counting. The similarity is not accidental.

The MapReduce framework was designed after a lot of experience in writing scalable,

distributed programs. This two-phase design pattern was seen in scaling many programs,

and became the basis of the framework.

In scaling our distributed word counting program in the last section, we also had to

write the partitioning and shuffling functions. Partitioning and shuffling are common

design patterns that go along with mapping and reducing. Unlike mapping and

reducing, though, partitioning and shuffling are generic functionalities that are not too

dependent on the particular data processing application. The MapReduce framework

provides a default implementation

that works in most situations.

[转载]Android 分享两个你学习android 平台开发必须碰到的几个知识点的组件【天气预报、日期】View 组件

mikel阅读(835)

[转载]Android 分享两个你学习android 平台开发必须碰到的几个知识点的组件【天气预报、日期】View 组件 – Terry_龙 – 博客园.

本篇文章将分享两个VIEW组件,一个天气组件和一个日期组件,这两个组件本来是一个App Widget 后来,我看着好玩,将他们弄成一个VIEW的组件,可以像使用Windows Phone 7 的用户控件一样拖放到你想要的项目中。本篇将演示这两个组件的编写过程,工程文件如下:

包名介绍:

  • com.terry.weather  程序的入口包
  • com.yaomei.adapter  天气预报组件使用到的数据源
  • com.yaomei.model  天气预报使用到的模型包
  • com.yaomei.util  获取天气信息的工具包
  • com.yaomei.widget  天气预报组件、日期组件的存放位置

从包名可以看出,编写一个天气预报所需要的代码量比编写一个日期VIEW所需要的代码量要多得多 ,那么我们先把天气预报的一些实现思路跟大家讲讲。

首先,本实例使用的天气预报是一个可以自己国际化的天气组件VIEW,可以看上图,将所需要的URL都放入Android 自己的国际化文件夹里面,比如中文的话就这样写:

<string name=”googleWeatherApi”>
<![CDATA[http://www.google.com/ig/api?hl=zh-cn&weather=]]>
</string>

那么是英语环境的就只需要在默认的VALUES里面的string.xml这样写即可:

<string name=”googleWeatherApi”>
<![CDATA[http://www.google.com/ig/api?hl=en&weather=]]>
</string>

这是本篇一个要注意的一点,另外还有需要注意的是,这个天气组件提供可供用户选择更新频率,这里比如我们使用3个小时更新一次,那么当用户退出 程序时,再打开是否还要再去Google 上面读天气呢?答案是NO,因为既然用户选择了更新频率,那么在一定的时间内,我们最好不要自动去更新,除非用户自己点击更新才去执行。那么要如何得到之 前的数据呢?

这里使用到的是SharePreference 将一些天气的信息保存进去,连同天气的图片也一并保存。保存天气图片是将google 天气的图片使用Base64转成字符串,然后保存进Sharepreference ,如果更新频率条件未满足则进去SharePrference 将天气预报数据取出来 。因为Android 并未提供将图片转成字符串的API,这里使用到的是apache 的一个Jar包,可在这里下载:点击这里

思路上面给出了,下面给出天气预报组件VIEW的核心代码,其他附属代码可在后面的附件下载得到,代码如下:

package com.yaomei.widget;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.commons.codec.binary.Base64;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.text.Html;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.terry.weather.R;
import com.yaomei.adapter.weatherAdapter;
import com.yaomei.model.WeatherMdoel;
import com.yaomei.util.strHelpeUtil;

public class WeatherView extends LinearLayout {

private static final String Hour_COMPARE = hour_compare;
private static final String DAY_OF_WEEK = day_of_week;
private static final String LOW = low;
private static final String HIGH = high;
private static final String CONDITION = condition;
private static final String IMAGE = image;
private static final String DATE_COMPARE = date_compare;
private static final String CITYNAE_SHARE = cityNameShare;

private ImageView iv_weather;
private TextView tv_state, tv_position, tv;

WeatherMdoel model;
private List<WeatherMdoel> weatherList = null;
GridView gv;
Timer timer;
Handler handler
= new Handler() {
public void handleMessage(Message msg) {
if (msg.arg1 == 1) {
if (weatherList.size() > 0) {
gv
.setAdapter(
new weatherAdapter(getContext(),
weatherList));
init();
}
else {
Toast.makeText(getContext(),
查询不到数据, 1000).show();
}
// msg.recycle();
}
};
};

/**
* 自动加载天气
*/
private boolean autoLoad = false;

public boolean getAutoLoad() {
return autoLoad;
}

public void setAutoLoad(boolean isLoad) {
this.autoLoad = isLoad;
}

/**
* 城市名称
*/
private String cityName = “”;

public String getCityName() {
return cityName;
}

public void setCityName(String cityName) {
this.cityName = cityName;
}

/**
* 设置每几小时更新一次
*/
private int updateHour;

public int getUpdateHour() {
return updateHour;
}

public void setUpdateHour(int hour) {
this.updateHour = hour;
}

public WeatherView(Context context) {
this(context, null);
// TODO Auto-generated constructor stub
}

public WeatherView(Context context, AttributeSet attrs) {
super(context, attrs);
int resouceID = 1;
TypedArray tyedArray
= context.obtainStyledAttributes(attrs,
R.styleable.WeatherView);
int N = tyedArray.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = tyedArray.getIndex(i);
switch (attr) {
case R.styleable.WeatherView_AutoLoad:
setAutoLoad(tyedArray.getBoolean(
R.styleable.WeatherView_AutoLoad,
false));
break;

case R.styleable.WeatherView_CityName:
resouceID
= tyedArray.getResourceId(
R.styleable.WeatherView_CityName,
0);
setCityName(resouceID
> 0 ? tyedArray.getResources().getText(
resouceID).toString() : tyedArray
.getString(R.styleable.WeatherView_CityName));
break;
case R.styleable.WeatherView_UpdateHour:
setUpdateHour(tyedArray.getInteger(
R.styleable.WeatherView_UpdateHour,
3));
break;
}
}

View view = LayoutInflater.from(getContext()).inflate(
R.layout.weather_layout,
this);

tv = (TextView) view.findViewById(R.id.tv_temperature);

gv = (GridView) view.findViewById(R.id.grid);
iv_weather
= (ImageView) view.findViewById(R.id.iv_weather);
tv_state
= (TextView) view.findViewById(R.id.tv_state);
tv_position
= (TextView) view.findViewById(R.id.tv_position);
timer
= new Timer();

if (getAutoLoad()) {
startLoadWeather();
}
tyedArray.recycle();
}

/**
* 开始加载
*/
public void startLoadWeather() {
timer.schedule(
new TimerTask() {

@Override
public void run() {

SharedPreferences share = getContext().getSharedPreferences(
weather, Activity.MODE_PRIVATE);
long time = System.currentTimeMillis();
final Calendar mCalendar = Calendar.getInstance();
mCalendar.setTimeInMillis(time);
String tempDate
= mCalendar.get(Calendar.YEAR) +
+ mCalendar.get(Calendar.MONTH) +
+ mCalendar.get(Calendar.DAY_OF_MONTH);
if (share.contains(DATE_COMPARE)) {
if (share.getString(CITYNAE_SHARE, “”).equals(cityName)) {
int time_cop = mCalendar.get(Calendar.HOUR)
share.getInt(Hour_COMPARE, 0);
String date
= share.getString(DATE_COMPARE, “”);

if (time_cop >= getUpdateHour()
|| !date.equals(tempDate)) {
saveWeatherList(mCalendar.get(Calendar.HOUR),
tempDate);

} else if (time_cop < getUpdateHour()) {
weatherList
= new ArrayList<WeatherMdoel>();
for (int i = 0; i < 4; i++) {
WeatherMdoel model
= new WeatherMdoel();
model.setWeek(share.getString(DAY_OF_WEEK
+ i,
“”));
model.setLowTemp(share.getString(LOW
+ i, “”));
model
.setHighTemp(share.getString(HIGH
+ i,
“”));
model.setConditions(share.getString(CONDITION
+ i, “”));
String image
= share.getString(IMAGE + i, “”);
byte[] base64Bytes = Base64.decodeBase64(image
.getBytes());
ByteArrayInputStream bais
= new ByteArrayInputStream(
base64Bytes);
model.setImageUrl(
“”);
model
.setImageDrawable(Drawable
.createFromStream(bais,
weather_image));

weatherList.add(model);
}
}
} else {
saveWeatherList(mCalendar.get(Calendar.HOUR), tempDate);
}

} else {
saveWeatherList(mCalendar.get(Calendar.HOUR), tempDate);
}
// 把必要的操作放在于线程中执行,不阻塞UI
if (handler.hasMessages(1))
handler.obtainMessage().recycle();

else {
Message msg
= handler.obtainMessage();
msg.arg1
= 1;
msg.sendToTarget();
}
}
},
0, getUpdateHour() * 3600 * 1000);
}

/**
* 第一次或者另外重新加载
*/
void saveWeatherList(int hour, String day) {
weatherList
= new ArrayList<WeatherMdoel>();
weatherList
= strHelpeUtil.searchWeather(Html.fromHtml(
getContext().getResources()
.getString(R.string.googleWeatherApi)).toString(),
getCityName());

SharedPreferences.Editor shareEditor = getContext()
.getSharedPreferences(
weather, Activity.MODE_PRIVATE).edit();
shareEditor.clear();
int i = 0;
for (WeatherMdoel model : weatherList) {

shareEditor.putString(DAY_OF_WEEK + i, model.getWeek());
shareEditor.putString(LOW
+ i, model.getLowTemp());
shareEditor.putString(HIGH
+ i, model.getHighTemp());
shareEditor.putString(CONDITION
+ i, model.getConditions());
/**
* 将图片存入
*/
ByteArrayOutputStream baos
= new ByteArrayOutputStream();
((BitmapDrawable) strHelpeUtil.loadImage(model.getImageUrl()))
.getBitmap().compress(CompressFormat.JPEG,
50, baos);

String ImageBase64 = new String(Base64.encodeBase64(baos
.toByteArray()));
shareEditor.putString(IMAGE
+ i, ImageBase64);
i
++;
}
shareEditor.putString(DATE_COMPARE, day);
shareEditor.putInt(Hour_COMPARE, hour);
shareEditor.putString(CITYNAE_SHARE, cityName);
shareEditor.commit();
}

/**
* 初始化组件 信息
*/
void init() {
model
= weatherList.get(0);
iv_weather.setImageDrawable(model.getImageUrl()
== “” ? model
.getImageDrawable() : strHelpeUtil.loadImage(model
.getImageUrl()));
tv_state.setText(model.getConditions());
tv_position.setText(getCityName());
tv.setText(getContext().getResources().getString(R.string.temp_format,
model.getLowTemp(), model.getHighTemp()));
}

/**
* 释放对象
*/
public void releaseTimer() {
timer.cancel();
weatherList
= null;
}

}

学习这个类,你能够学到的知识点为:为应用程序添加属性,编写组件,SharePreference 的使用,Timer和Handler 异步处理UI等知识点。

日期VIEW显示VIEW组件,是一个显示当前系统时间的组件,当第一次运行时,得到当前的秒数在以60秒减去当前秒,得到第一次运行时下一次 运行需要的秒数,当这一次更新完毕后,下一次每次60秒更新一次时间,这个组件也是以分更新UI的操作,学习本类,你可以学到两个Handler 是如何协作处理UI,代码如下:

package com.yaomei.widget;

import java.util.Calendar;
import java.util.Date;

import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.terry.weather.R;
import com.yaomei.util.strHelpeUtil;

public class DateView extends FrameLayout {

private TextView tv_date_time, tv_week, tv_date;

int second;

Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
init();
handler.sendMessageDelayed(handler.obtainMessage(),
60 * 1000);
};
};

public DateView(Context context) {
this(context, null);
}

public DateView(Context context, AttributeSet attrs) {
super(context, attrs);
//this.setBackgroundDrawable(getContext().getResources().getDrawable(
// R.drawable.date_background));

View view
= LayoutInflater.from(getContext()).inflate(
R.layout.date_layout,
this);

tv_date_time = (TextView) view.findViewById(R.id.tv_date_time);
tv_week
= (TextView) view.findViewById(R.id.tv_week);
tv_date
= (TextView) view.findViewById(R.id.tv_date);
init();
final Calendar calendar = Calendar.getInstance();
second
= calendar.get(Calendar.SECOND);
handler.sendMessageDelayed(handler.obtainMessage(),
(
60 second) * 1000);
}

void init() {
java.text.DateFormat df
= new java.text.SimpleDateFormat(HH:mm);
tv_date_time.setText(df.format(
new Date()));
tv_week.setText(strHelpeUtil.getWeekOfDate(
new Date()));
strHelpeUtil str
= new strHelpeUtil(getContext());
tv_date.setText(str.toString());
}

}

上篇运行效果如下:

由于没有为其提供背景颜色,使用的同学可以自己为它们加上一个好看的背景颜色,效果会更加。

上面的天气组件,其实可以使用AsyncTask也是起到同样的效果,AsyncTask使用起来会觉得优雅一点,这里也顺便把一些AsyncTask在使用上一些注意事项跟大家谈一谈:

  • 在doInBackground 里面不要直接操作UI,比如设置UI的可见性操作。
  • 在doInBackground 所在的操作只负责帮你得到数据,然后把UI处理都放在onPostExecute 里面。
  • 同时启动几个AsyncTask 注意线程加锁,使用synchronized
  • 必须每次都创建一个新的AsyncTask 对象,否则会提示“a task can be executed only once” 的错误信息。

本篇的所有源码下载地址:组件