Facebook Twitter LinkedIn E-mail
magnify
Home 2011 七月

Android RoboGuice 使用指南(1):概述

在开发应用时一个基本原则是模块化,并且近最大可能性地降低模块之间的耦合性。在Java平台上Spring Framework 以及.Net 平台 CAB ,SCSFPrism (WPF,Silverlight)中都有对Dependency injection 的支持。

Dependency injection 大大降低了类之间的依赖性,可以通过annotation (Java)或是SeviceDepdendcy (.Net) 描述类之间的依赖性,避免了直接调用类似的构造函数或是使用Factory来参加所需的类,从而降低类或模块之间的耦合性,以提高代码重用并增强代码的可维护性。

Google Guice提供了Java平台上一个轻量级的 Dependency injection 框架,并可以支持开发Android应用。本指南将使用Android平台来说明Google Guice的用法。

简单的来说:Guice 降低了Java代码中使用 new 和 Factory函数的调用。可以把Guice 的@Inject 看作 new 的一个替代品。使用Guice可能还需要写一些Factory方法,但你的代码不会依赖这些Factory方法来创建实例。 使用Guice 修改代码,单元测试已经代码重用变得更容易。

RoboGuice 为Android平台上基于Google Guice开发的一个库,可以大大简化Android应用开发的代码和一些繁琐重复的代码。比如代码中可能需要大量使用findViewById在XML中查找一个View,并将其强制转换到所需类型,onCreate 中可能有大量的类似代码。RoboGuice 允许使用annotation 的方式来描述id于View之间的关系,其余的工作由roboGuice库来完成。比如:

class AndroidWay extends Activity {
 TextView name;
 ImageView thumbnail;
 LocationManager loc;
 Drawable icon;
 String myName;

 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 name      = (TextView) findViewById(R.id.name);
 thumbnail = (ImageView) findViewById(R.id.thumbnail);
 loc       = (LocationManager) getSystemService(Activity.LOCATION_SERVICE);
 icon      = getResources().getDrawable(R.drawable.icon);
 myName    = getString(R.string.app_name);
 name.setText( "Hello, " + myName );
 }
}

如果使用roboguice 来写:

class RoboWay extends RoboActivity {
 @InjectView(R.id.name)             TextView name;
 @InjectView(R.id.thumbnail)        ImageView thumbnail;
 @InjectResource(R.drawable.icon)   Drawable icon;
 @InjectResource(R.string.app_name) String myName;
 @Inject                            LocationManager loc;

 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 name.setText( "Hello, " + myName );
 }
}

只需使用@InjectView 来描述 view 和Id之间的关系,RoboGuice 自动完成余下的工作,代码简洁易读。在介绍完Google Guice ,再接着介绍RoboGuice 在Android平台上使用方法。

 

Android测试教程(1):概述

测试也是开发过程中一个重要组成部分,Android开发环境集成一个测试框架可以用来测试Android应用的各个方面,单元测试,UI测试等。

本教程基于Android 开发教程英文版。

基本概念包括

  • Android测试的基础知识
  • Activity Testing 侧重于Activity的测试,介绍了如果使用Instrumentation 在正常Activity生命周期之外来控制Activity,然后测试Activity的特定的功能和测试UI的一些技巧。
  • Content Provider Testing  侧重测试Content  Provider。
  • Service Testing 侧重测试Service。
  • 需要测试的内容等。

以及在Eclipse ADT开发环境下如何创建一个测试项目和Android开发工具提供的一些测试工具。在阅读本测试教程之前,你需要有Android开发的一些基本知识,可以参见Android开发教程 ,此外需要了解一些JUnit的基本概念 。

并对ApiDemo中的测试示例进行解析。

 

LWUIT 开发教程(5): Label

Label 控件可以用来显示一行文字,或者文字+图像(文字和图像的位置可以配置)。 如果你需要自定义一个能显示一个字同符串或图像的控件,可以考虑扩展Label。如果自定义控件需要支持用户交互,则可以派生Button控件(Button 为Label 的子类)。

创建一个Label ,可以使用如下构造函数:

Label textLabel = new Label("I am a Label"); // for a text label

创建一个图像的Label:

Image icon = Image.createImage("/images/duke.png");
Label imageLabel = new Label(icon);

Label 的对齐方式可以有:CENTER,LEFT,RIGHT.缺省左对齐。此外,文字还可以自定义和它显示的图像之间的相对位置,可以有TOP,BOTTOM,LEFT,RIGHT ,缺省文字显示在图像的的右边。

  • setTextPosition(int alignment);用来定义文字相对图像的位置。
  • setAlignment(int align): 用来定义文字的定义方式。

下面示例在Form在添加4个Label:

Form mainForm = new Form("Label Demo");
mainForm.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
Label label1=new Label("Text Only Label");
mainForm.addComponent(label1);
try {
 Image icon = Image.createImage("/navigator.png");
 Label label2=new Label(icon);
 mainForm.addComponent(label2);

 Label label3=new Label(icon);
 label3.setText("Image and Text Label");
 mainForm.addComponent(label3);

 Label label4=new Label(icon);
 label4.setText("Image and Text Label at Bottom");
 label4.setTextPosition(Component.BOTTOM);
 mainForm.addComponent(label4);
} catch (IOException ex) {
 ex.printStackTrace();
}

示例代码可以使用SVN 下载svn checkout http://lwuit-tutorials.googlecode.com/svn/trunk/ lwuit-tutorials-read-only  LabelDemo

 

LWUIT 开发教程(4): Form

在LWUIT应用中Form为UI 控件包含关系中的根容器,Form处理顶部标题栏和并支持菜单,中间部分(Content Pane)可以放置其它UI组件,Content Pane 缺省支持滚动。

Form缺省可以包含:Titlebar, MenuBar 和一个ContentPane :

使用addComponent 为Form添加Components实际上是调用ContentPane的addComponent (类似的setLayout, getComponent 都是定义ContentPane对应的方法)。

在包com.pstreets.lwuit.demo.widgets 创建一个FormDemo示例:

// 1. Create a Form
Form mainForm = new Form("Form Title");
// 2. Set LayoutManager
mainForm.setLayout(new BorderLayout());
// 3. Add a Label to the center of Form content pane
mainForm.addComponent(BorderLayout.CENTER, new Label("Form Demo"));
// 4. Set Transitions animation of Fade
mainForm.setTransitionOutAnimator(CommonTransitions.createFade(400));
// 5. Add Command key
mainForm.addCommand(new Command("Left soft key", 2));
mainForm.addCommand(new Command("Right Soft key", 2));
// 6. Show it
mainForm.show();
  1. 第一步调用Form构造函数创建一个Form实例,“Form Title”给出Titlebar 名称。
  2. 第二步为Form设置Layout管理器,和Swing 或Android平台上类似,Container(Form也为一Container)可以设置多种布局管理器(如水平排列,垂直排列子控件等),Layout 将在后面有详细说明。
  3. 第三步在Form在添加一个Label控件,添加控件的方法为 addComponent (Component comp)或addComponent(Object constraints, Component comp) 其中constraints一般用来通知Layout布局管理器要添加的Component的位置参数。
  4. 第四步设置Form的显示或切换不同Form时的动画效果,动画后面有介绍。
  5. 第五步为Form设置MenuBar, LWUIT 中Menubar 显示在屏幕底部,如果只有一个Command,这个Command缺省显示在右边,如果有两个Command,左右各显示一个,多于两个时,第一个Command显示在左边,余下的Command以Menu列表显示在右边(后面详细介绍Menu)。
  6. 第六步在屏幕上显示这个Form。

示例代码可以使用SVN 下载svn checkout http://lwuit-tutorials.googlecode.com/svn/trunk/ lwuit-tutorials-read-only

 

Android OpenGL ES 开发教程(27):材质及光照示例

设置物体表面材料(Material)的反光属性(颜色和材质)的方法如下:

public void glMaterialf(int face,int pname,float param)
public void glMaterialfv(int face,int pname,float[] params,int offset)
public void glMaterialfv(int face,int pname,FloatBuffer params)

  • face : 在OpenGL ES中只能使用GL_FRONT_AND_BACK,表示修改物体的前面和后面的材质光线属性。
  • pname: 参数类型,可以有GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMISSION, GL_SHININESS。这些参数用在光照方程。
  • param:  参数的值。

其中GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR ,GL_EMISSION为颜色RGBA值,GL_SHININESS 值可以从0到128,值越大,光的散射越小:

此外,方法glLightModleXX给出了光照模型的参数

public void glLightModelf(int pname,float param)
public void glLightModelfv(int pname,float[] params,int offset)
public void glLightModelfv(int pname,FloatBuffer params)

  • pname: 参数类型,可以为GL_LIGHT_MODEL_AMBIENT和GL_LIGHT_MODEL_TWO_SIDE
  • params: 参数的值。

最终顶点的颜色由这些参数(光源,材质光学属性,光照模型)综合决定(光照方程计算出)。

下面例子在场景中设置一个白色光源:

public void initScene(GL10 gl){
 float[] amb = { 1.0f, 1.0f, 1.0f, 1.0f, };
 float[] diff = { 1.0f, 1.0f, 1.0f, 1.0f, };
 float[] spec = { 1.0f, 1.0f, 1.0f, 1.0f, };
 float[] pos = { 0.0f, 5.0f, 5.0f, 1.0f, };
 float[] spot_dir = { 0.0f, -1.0f, 0.0f, };
 gl.glEnable(GL10.GL_DEPTH_TEST);
 gl.glEnable(GL10.GL_CULL_FACE);

 gl.glEnable(GL10.GL_LIGHTING);
 gl.glEnable(GL10.GL_LIGHT0);
 ByteBuffer abb
 = ByteBuffer.allocateDirect(amb.length*4);
 abb.order(ByteOrder.nativeOrder());
 FloatBuffer ambBuf = abb.asFloatBuffer();
 ambBuf.put(amb);
 ambBuf.position(0);

 ByteBuffer dbb
 = ByteBuffer.allocateDirect(diff.length*4);
 dbb.order(ByteOrder.nativeOrder());
 FloatBuffer diffBuf = dbb.asFloatBuffer();
 diffBuf.put(diff);
 diffBuf.position(0);

 ByteBuffer sbb
 = ByteBuffer.allocateDirect(spec.length*4);
 sbb.order(ByteOrder.nativeOrder());
 FloatBuffer specBuf = sbb.asFloatBuffer();
 specBuf.put(spec);
 specBuf.position(0);

 ByteBuffer pbb
 = ByteBuffer.allocateDirect(pos.length*4);
 pbb.order(ByteOrder.nativeOrder());
 FloatBuffer posBuf = pbb.asFloatBuffer();
 posBuf.put(pos);
 posBuf.position(0);

 ByteBuffer spbb
 = ByteBuffer.allocateDirect(spot_dir.length*4);
 spbb.order(ByteOrder.nativeOrder());
 FloatBuffer spot_dirBuf = spbb.asFloatBuffer();
 spot_dirBuf.put(spot_dir);
 spot_dirBuf.position(0);


 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, ambBuf);
 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, diffBuf);
 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, specBuf);
 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, posBuf);
 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPOT_DIRECTION,
 spot_dirBuf);
 gl.glLightf(GL10.GL_LIGHT0, GL10.GL_SPOT_EXPONENT, 0.0f);
 gl.glLightf(GL10.GL_LIGHT0, GL10.GL_SPOT_CUTOFF, 45.0f);

 gl.glLoadIdentity();
 GLU.gluLookAt(gl,0.0f, 4.0f, 4.0f, 0.0f, 0.0f, 0.0f,
 0.0f, 1.0f, 0.0f);

}

绘制一个球,并使用蓝色材质:

public void drawScene(GL10 gl) {
 super.drawScene(gl);

 float[] mat_amb = {0.2f * 0.4f, 0.2f * 0.4f,
 0.2f * 1.0f, 1.0f,};
 float[] mat_diff = {0.4f, 0.4f, 1.0f, 1.0f,};
 float[] mat_spec = {1.0f, 1.0f, 1.0f, 1.0f,};


 ByteBuffer mabb
 = ByteBuffer.allocateDirect(mat_amb.length*4);
 mabb.order(ByteOrder.nativeOrder());
 FloatBuffer mat_ambBuf = mabb.asFloatBuffer();
 mat_ambBuf.put(mat_amb);
 mat_ambBuf.position(0);

 ByteBuffer mdbb
 = ByteBuffer.allocateDirect(mat_diff.length*4);
 mdbb.order(ByteOrder.nativeOrder());
 FloatBuffer mat_diffBuf = mdbb.asFloatBuffer();
 mat_diffBuf.put(mat_diff);
 mat_diffBuf.position(0);

 ByteBuffer msbb
 = ByteBuffer.allocateDirect(mat_spec.length*4);
 msbb.order(ByteOrder.nativeOrder());
 FloatBuffer mat_specBuf = msbb.asFloatBuffer();
 mat_specBuf.put(mat_spec);
 mat_specBuf.position(0);

 gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,
 GL10.GL_AMBIENT, mat_ambBuf);
 gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,
 GL10.GL_DIFFUSE, mat_diffBuf);
 gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,
 GL10.GL_SPECULAR, mat_specBuf);
 gl.glMaterialf(GL10.GL_FRONT_AND_BACK,
 GL10.GL_SHININESS, 64.0f);

 sphere.draw(gl);

}

本例下载

 

Android OpenGL ES 开发教程(26):设置光照效果Set Lighting

上一篇简单介绍了OpenGL中使用的光照模型,本篇结合OpenGL ES API说明如何使用光照效果:

  • 设置光源
  • 定义法线
  • 设置物体材料光学属性

光源

OpenGL ES中可以最多同时使用八个光源,分别使用0到7表示。

OpenGL ES光源可以分为

  • 平行光源(Parallel light source), 代表由位于无限远处均匀发光体,太阳可以近似控制平行光源。
  • 点光源(Spot light source)  如灯泡就是一个点光源,发出的光可以指向360度,可以为点光源设置光衰减属性(attenuation)或者让点光源只能射向某个方向(如射灯)。
  • 可以为图形的不同部分设置不同的光源。

下面方法可以打开某个光源,使用光源首先要开光源的总开关:

gl.glEnable(GL10.GL_LIGHTING);

然后可以再打开某个光源如0号光源:

gl.glEnable(GL10.GL_LIGHTI0);

设置光源方法如下:

  • public void glLightfv(int light,int pname, FloatBuffer params)
  • public void glLightfv(int light,int pname,float[] params,int offset)
  • public void glLightf(int light,int pname,float param)
  • light 指光源的序号,OpenGL ES可以设置从0到7共八个光源。
  • pname: 光源参数名称,可以有如下:GL_SPOT_EXPONENT, GL_SPOT_CUTOFF, GL_CONSTANT_ATTENUATION,  GL_LINEAR_ATTENUATION, GL_QUADRATIC_ATTENUATION, GL_AMBIENT, GL_DIFFUSE,GL_SPECULAR, GL_SPOT_DIRECTION, GL_POSITION
  • params 参数的值(数组或是Buffer类型)。

其中为光源设置颜色的参数类型为GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,可以分别指定R,G,B,A 的值。

指定光源的位置的参数为GL_POSITION,值为(x,y,z,w):

平行光将w 设为0.0,(x,y,z)为平行光的方向:

对于点光源,将 w 设成非0值,通常设为1.0. (x,y,z)为点光源的坐标位置。

将点光源设置成聚光灯,需要同时设置GL_SPOT_DIRECTION,GL_SPOT_CUTOFF等 参数,GL_POSITION的设置和点光源类似:将 w 设成非0值,通常设为1.0. (x,y,z)为点光源的坐标位置。而对于GL_SPOT_DIRECTION 参数,设置聚光的方向(x,y,z)

GL_SPOT_CUTOFF 参数设置聚光等发散角度(0到90度)

GL_SPOT_EXPONENT 给出了聚光灯光源汇聚光的程度,值越大,则聚光区域越小(聚光能力更强)。

对应点光源(包括聚光灯),其它几个参数GL_CONSTANT_ATTENUATION,  GL_LINEAR_ATTENUATION,  GL_QUADRATIC_ATTENUATION 为点光源设置光线衰减参数,公式有如下形式,一般无需详细了解:

在场景中设置好光源后,下一步要为所绘制的图形设置法线(Normal),只有设置了法线,光源才能在所会物体上出现光照效果。三维平面的法线是垂直于该平面的三维向量。曲面在某点P处的法线为垂直于该点切平面的向量

和设置颜色类似,有两个方法可以为平面设置法线,一是

public void glNormal3f(float nx,float ny,float nz)

这个方法为后续所有平面设置同样的方向,直到重新设置新的法线为止。

为某个顶点设置法线:

public void glNormalPointer(int type,int stride, Buffer pointer)

  • type  为Buffer 的类型,可以为GL_BYTE, GL_SHORT, GL_FIXED,或 GL_FLOAT
  • stride: 每个参数之间的间隔,通常为0.
  • pointer: 法线值。

打开法线数组

gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);

用法和Color, Vertex 类似。参见Android OpenGL ES 开发教程(8):基本几何图形定义

规范化法向量,比如使用坐标变换(缩放),如果三个方向缩放比例不同的话,顶点或是平面的法线可能就有变好,此时需要打开规范化法线设置:

gl.glEnable(GL10.GL_NORMALIZE);

经过规范化后法向量为单位向量(长度为1)。同时可以打开缩放法线设置

gl.glEnable(GL10.GL_RESCALE_NORMAL);

设置好法线后,需要设置物体表面材料(Material)的反光属性(颜色和材质)。

将在下篇介绍设置物体表面材料(Material)的反光属性(颜色和材质)并给出一个光照的示例。