面向移动设备的矢量绘图平台设计与实现

Design and Implementation of Mobile Device-oriented Vector Drawing Platform

引用本论文: 张云贵. 面向移动设备的矢量绘图平台设计与实现[D]. 北京:北京理工大学软件学院, 2013.

本论文的相似度为0%,是源创论文。欢迎评阅讨论,请勿抄袭,如需更多资料请在博客留言。

如果在研究或论文中使用到,欢迎回复或私信你的学校、姓名、研究领域,并在论文中添加引用或致谢。感谢你对开放成果的尊重和鼓励。

第5章 Android绘图平台的实现

本章阐述了Android绘图平台的实现方法,主要是在跨平台内核的基础上实现Android画布适配器和视图适配器,对图形显示优化技术进行了实验研究。

5.1 开发环境

5.1.1 SWIG的工作原理分析

如图5‑1所示,借助于SWIG实现Android程序的Java代码通过JNI访问C++的类。在编译阶段SWIG工具从C++生成JNI的Java类文件和相应的C++实现文件,该实现文件与原有的C++实现文件一起通过NDK编译为本地动态库。

图5‑1 Android程序调用C++类的原理

如图5‑2所示,利用SWIG的Director特性,指定某个具有虚函数的C++类可重定位,然后再生成C++导出函数文件和JNI的Java类文件。在应用层中从对应的JNI类继承并实现其函数,在执行该C++类的虚函数时对应的Android函数就被执行。

图5‑2 Android类从C++类的虚函数重载的原理

图5‑2中,SwigDirector_SomeClass从C++的SomeClass派生,Android类从JNI的SomeClass类派生,在SwigDirector_SomeClass中通过调用JNIEnv类的CallStaticVoidMethod等函数实现在C++中调用Java的类函数,这样Android类中相应的重载函数便得到调用,实现使用Android SDK的Java类来扩展C++类。

5.1.2 SWIG的运行性能分析

TouchVG平台使用SWIG实现Android程序的Java类与内核的C++类之间的双向调用,即Java类通过JNI调用C++类、C++类利用Director特性回调Java类。

本文对这两种调用方式进行评测,结果见图5‑3。

图5‑3 SWIG在Android中的性能评测结果

图5‑3包含下列四个评测项目:

(1)回调绘图:Android程序通过JNI调用跨平台内核的一个测试函数,在该测试函数中多次回调画布适配器的绘制直线段的函数,在该绘制函数中使用android.graphics包绘图。其性能影响因素有JNI调用、回调和绘图。

(2)回调不绘图:与上一项目的差别是将画布适配器的绘制函数改为空实现,不受图形库的影响。其性能影响因素有JNI调用和回调。

(3)直接绘图:Android程序直接调用绘制直线段的函数,与JNI无关。

(4)正向调用:Android程序通过JNI多次调用跨平台内核的一个测试函数。其性能影响因素是JNI调用,与JNI回调及绘图无关。

评测结果表明,基于虚函数重定位技术的回调方式的性能与普通的JNI调用方式的差别较小,SWIG所增加的封装函数并不会使绘图性能明显下降。

5.1.3 开发方式

Android绘图平台的实现方式如图5‑4所示,编译得到的绘图平台JAR包和内核本地动态库可供应用程序使用。借助于SWIG的Director机制,使用Android SDK实现了画布适配器和视图适配器,实现对内核功能的扩展。

将跨平台内核使用NDK编译到本地动态链接库中,接口形式为JNI和封装类库。采用SWIG将C++类转换为JNI的Java类,SWIG所生成的C++导出函数文件与跨平台内核的代码文件一起编译为动态库。编译过程中使用Python脚本自动修正SWIG所生成的代码中的缺陷,并自动将包含中文字符的文件由UTF8临时转换为GBK编码以便正常编译转换。

图5‑4 Android绘图平台的实现方式

对于Android本地动态链接库的调试定位难题,利用NDK提供的日志输出C函数和库文件,通过输出日志文字的方式来解决。用该方法诊断出了SWIG引起的JNI内存问题所在位置,最终采用Python脚本自动修正SWIG所生成的文件缺陷。

5.1.4 开发工具

使用了下列工具分别在Mac OS X 10.7和Windows 7上开发Android绘图平台:

(1)Android开发包(the ADT Bundle)r21.1,可以在Eclipse中调试本地动态库。

(2)Android NDK r8e,用于开发本地动态库。

(3)SWIG 2.0.10,用于从C++头文件生成JNI的类文件和C++封装文件。

(4)Python 2.7,用于运行Python脚本自动修正SWIG所生成的文件缺陷。

(5)MSYS(Minimalist GNU for Windows)1.0,用于在Windows上模拟UNIX环境,执行Shell编译脚本。

5.1.5 SWIG编译配置

在touchvg.swig文件[1]中配置SWIG编译选项,主要配置内容如下:

(1)在文件前面定义下面两个宏:

SWIG_JAVA_NO_DETACH_CURRENT_THREAD

SWIG_JAVA_ATTACH_CURRENT_THREAD_AS_DAEMON

定义前者以便在每次调用本地代码后不与当前线程断开(使用SWIG的Director机制后,在本地函数调用结束时一些JNI对象还需要继续有效,不能与当前线程断开)。定义后者将JNI环境附加在守护线程上(默认是附加在界面主线程上,在Activity退出时可能会崩溃)。

(2)输出JNI_OnLoad函数。Dalvik虚拟机要求必须实现JNI_OnLoad函数,本平台仅简单返回JNI_VERSION_1_6,由SWIG生成的代码自动注册本地函数。

(3)指定GiCanvas和GiView需要生成重定向类,并导出相应的头文件。

(4)输出要在Android代码中使用的内核接口。例如,GiCoreView类。

(5)添加TmpJOBJ辅助类,在析构函数中自动释放JNI本地引用对象。SWIG生成的Director类中某些形参的本地引用对象没有释放,会因超出256个JNI引用对象的限制而溢出崩溃。例如,在GiCanvas的drawBitmap函数中,name字符串对象所对应的本地引用对象“jstring jname”在调用了NewStringUTF函数后没有调用DeleteLocalRef函数。

本文针对该问题提出的解决方法:将SWIG所生成的封装文件中的“jstring jname = 0”替换为“jstring jname = 0; TmpJOBJ jtmp(jenv, &jname)”,通过TmpJOBJ的析构作用自动调用DeleteLocalRef函数释放引用。使用Python脚本[2]自动进行替换SWIG生成的封装文件中的这类问题。

编写了Shell脚本(mk/swig.sh),用于运行SWIG工具生成JNI导出函数的封装文件(touchvg_java_wrap.cpp)和JNI类文件。JNI类的包名为touchvg.jni,其文件输出到工程的src/touchvg/jni目录下,将与视图适配器的代码(src/touchvg/view目录)共同生成为一个JAR文件。

5.1.6 NDK编译配置

Android绘图平台的代码目录结构见第20页的图3‑7。在工程的jni/Android.mk文件[3]中配置本地动态库的NDK编译选项,主要有:

(1)基于绝对地址$(LOCAL_PATH)/../../../core/include在LOCAL_C_INCLUDES中指定内核的头文件路径,基于相对地址 ../../../core/src 在LOCAL_SRC_FILES中指定跨平台内核的实现文件(*.cpp,使用绝对的路径无法编译)。

(2)因为SWIG的Director代码使用了RTTI运行时类型信息,所以在LOCAL_CFLAGS中指定-frtti选项。

(3)为了使用STL,在jni/Application.mk中指定“APP_STL := stlport_static”。

本文编写了Shell脚本(ndk.sh),在其中进入android\demo\jni目录自动运行ndk-build编译出本地动态链接库libtouchvg.so,在编译过程中自动应用Android.mk中的配置信息。Onur Cinar[4]介绍了在Android.mk中包含脚本的方法,可自动运行脚本。

本文在多个平台编译时发现Shell脚本文件应使用Unix行结束符(LF),不能是DOS结束符或Mac结束符,尽可能避免使用中文字符。

5.2 基于Android Canvas实现画布适配器

在第12页的2.2.3节介绍了Android二维绘图主要涉及的框架。本文主要基于两种视图类设计绘图视图类:android.view.View和android.view.SurfaceView,在绘图视图类中使用Android Canvas画布类(使用android.graphics包)渲染。

5.2.1 画布原语与Android Canvas的映射

本文基于android.graphics包设计画布适配器类touchvg.view.CanvasAdapter,该类实现touchvg.jni.GiCanvas中的画布原语函数,后者是通过SWIG从跨平台内核的GiCanvas接口自动生成的。在内核中调用画布接口GiCanvas的函数时,画布适配器将被回调执行,从而允许使用Android Canvas渲染。

画布适配器主要使用了android.graphics包中这些类:Canvas画布类访问绘图函数接口,Paint类指定颜色等绘图属性,Path类构建路径,Bitmap指定位图数据。在绘图视图的onDraw函数中将Canvas画布对象传入画布适配器,后续绘图将在该画布对象上进行。在离屏位图上渲染时,从位图构建画布对象,接着传入画布适配器。

因为Paint对象只能指定一个颜色,无法区分画笔颜色和画刷颜色,所以画布适配器针对画笔、画刷和文字显示分别使用一个Paint对象:mPen、mBrush、mTextPen。以显示一个红边蓝底的椭圆为例,先设置mPen的颜色为红色、mBrush的颜色为蓝色,然后分别使用mPen和mBrush作为参数绘制椭圆。为了让文字颜色和图形颜色同步,在setPen函数中同时设置画笔mPen和文字属性mTextPen的颜色。

这三种Paint对象的参数设置见表5‑1。

表5‑1 Paint对象的参数设置

画笔

画刷

文字

mPen.setAntiAlias(true)

 

mTextPen.setAntiAlias(true)

mPen.setDither(true)

 

mTextPen.setDither(true)

mPen.setStyle(STROKE)

mBrush.setStyle(FILL)

 

mPen.setPathEffect(null)

mBrush.setColor(0)

 

mPen.setStrokeCap(Cap.ROUND)

   

mPen.setStrokeJoin(Join.ROUND)

   

表5‑1中,画刷默认填充颜色为透明色,即不填充。画笔的默认线型为实线,线端为圆端,这样在绘制短线时更像一个圆点。为了让点线等虚线类型的空白间隙整齐,在setPen函数中对所有虚线类型设置平端的线端类型。

与iOS绘图平台的实现类似,Android画布适配器按表5‑2所示的映射方法实现了画布原语函数。由跨平台内核中的TestCanvas类生成和显示矢量图形和图像。

在实现这些函数时,本文对下列内容进行了特殊处理或总结。

(1)在View中调用画布适配器的clearRect函数,无法使指定区域透明,如图5‑5(i)所示。只能在原有图形基础上填充颜色,指定透明色将填充为黑色。在SurfaceView中调用画布适配器的clearRect函数,可以擦除指定区域内的图形,变为透明区域,如图5‑5(k)所示。

(2)当程序和视图使用了硬件加速特性后,调用clipPath会崩溃,其原因是在硬件加速时不支持clipPath函数。解决方法是在UnsupportedOperationException异常出现后将对应的视图的层类型设置为软件实现方式(LAYER_TYPE_SOFTWARE)。

(3)在SurfaceView视图中使用渲染线程连续绘图能够达到48~56FPS的更新速度,实验效果如图5‑5(n)所示。测试用例为绘制不断延长的三次贝塞尔曲线,测试条件为MOTO MZ606平板电脑(Android 4.0.3,1280×800)。

表5‑2 画布原语与android.graphics的映射

画布原语

测试号

Android函数对应关系

clearRect

i k

mCanvas.drawColor(mBkColor, Mode.CLEAR),需要设置剪裁区域

drawRect

a

mCanvas.drawRect,使用mPen和mBrush

drawEllipse

b

mCanvas.drawOval,宽高不超过1时使用drawPoint

beginPath

多个

创建路径对象mPath

moveTo

多个

mPath.moveTo

lineTo

c

mPath.lineTo

bezierTo

e

mPath.cubicTo

quadTo

f

mPath.quadTo

closePath

c

mPath.close

drawPath

多个

mCanvas.drawPath(mPath, mBrush)、.drawPath(mPath, mPen)

drawHandle

g

mCanvas.drawBitmap,在指定点显示

drawBitmap

g

mCanvas.drawBitmap,指定Matrix矩阵变换对象

drawTextAt

h

mTextPen.setTextSize、mCanvas.drawText,用到FontMetrics

setPen

多个

mPen.setColor、mPen.setStrokeWidth、mTextPen.setColor

mPen.setPathEffect、mPen.setStrokeCap

setBrush

多个

mBrush.setColor

saveClip

m

mCanvas.save(CLIP_SAVE_FLAG)

restoreClip

m

mCanvas.restore()

clipRect

m

mCanvas.clipRect

clipPath

m

mCanvas.clipPath,硬件加速时需要将视图的层改为软件实现类型

drawLine

d

mCanvas.drawLine

注:其中的测试号为图5‑5中的测试子图号。

图5‑5 Android画布适配效果

5.2.2 图像的显示和管理

在绘图视图中管理图像对象,画布适配器从视图获取图像。显示接口函数为:

void drawBitmap(String name, float xc, float yc, float w, float h, float angle)

其中,使用名称name标识图像对象,(xc,yc)为图像的中心显示位置,w和h为显示目标宽高,angle为旋转的角度(世界坐标系中的逆时针方向)。

图像绘制的基点在图像的左上角,画布的坐标系为ULO类型,绘制过程为:

(1)根据name从绘图视图获取Bitmap对象;

(2)计算变换矩阵:将显示基点由图像的左上角平移到中心,反向旋转angle角度(弧度转换为度),将宽高分别放缩到w和h,最后平移到(xc,yc)。

(3)使用此矩阵显示图像对象。

本文实验发现在显示大图片时,加载图片所需时间远大于显示图像的时间,因此减少图片加载次数能加快显示速度。本文采用下面两种方法进行图像管理:

(1)在绘图视图类中使用LruCache缓存图片。定义LruCache<String, Bitmap>类型的成员变量,以图像标识串(drawBitmap中的name)为键值管理图像对象。

(2)加载图片前先检查图片的宽高,如果太大就以降低采样率方式加载图片。

5.3 绘图视图的设计和实验

为了提高视图的显示质量和性能,本文针对View、SurfaceView进行了实验。

5.3.1 实现方式

绘图视图使用画布适配器CanvasAdapter绘图,由跨平台内核中的GiCoreView和TestCanvas类自动显示测试图形。绘图视图类的关系见图5‑6,实现方式说明如下。

(1)GraphView。从View派生,在onDraw中绘图,调用invalidate()重绘。在onDraw中调用内核视图的drawAll函数显示所有图形。在触摸响应函数中调用内核视图的onGesture函数传递手势动作,由后者在某个交互命令中调用视图的redraw等函数,这将回调到GraphView的视图适配器(ViewAdapter),后者调用视图的invalidate()标记需要重绘。

(2)面板表面视图。从SurfaceView派生。调用setZOrderOnTop(true)设置为面板窗口,显示于宿主窗口之上。调用getHolder().setFormat(TRANSPARENT)设置其Surface背景透明,以显示宿主窗口的内容。在Surface就绪和刷新显示时启动渲染线程,在绘图线程中获取画布绘图,由内核视图的drawAll函数显示所有图形。

(3)媒体表面视图。从SurfaceView派生。默认就是媒体窗口,显示于宿主窗口之下,自动在宿主窗口上设置透明区域以便让SurfaceView上的内容可见。在Surface就绪和刷新显示时启动渲染线程,在绘图线程中获取画布绘图。

(4)GraphViewCached。从View派生,使用一个位图缓存图形内容,在onDraw函数中显示该位图。

内核调用regenAll函数时销毁该位图,下次onDraw函数执行时重新生成位图。应用增量绘图技术,添加新图形后调用regenAppend函数,直接在该位图上绘制新图形,下次onDraw函数执行时显示有新内容的位图。

图5‑6 Android渲染视图的类关系

(5)静态View + 动态View。在布局视图中创建两个基于View的视图类(GraphView和DynDrawStdView),分别显示不变的图形和经常改变的内容,前者渲染的内容通常较多。

(6)面板表面视图 + View。在布局视图中创建GraphSfView和DynDrawStdView视图。在GraphSfView中显示静态图形,GraphSfView位于窗口顶端。在DynDrawStdView中显示动态图形。

(7)静态View + 面板表面视图。在布局视图中创建GraphView和DynDrawSfView视图。在GraphView中显示静态图形,在DynDrawSfView中显示动态图形。DynDrawSfView是面板表面视图,在子线程中获取画布绘图,每次刷新显示时启动渲染线程。

(8)面板表面视图 + 面板表面视图。在两个位于窗口顶端的视图类中分别显示静态图形和动态图形。

(9)媒体表面视图 + View。在GraphSfView中显示静态图形,GraphSfView位于根视图层次的底端,在DynDrawStdView中显示动态图形。

(10)媒体表面视图 + 面板表面视图。在两个基于SurfaceView的视图类中分别渲染静态图形和动态图形,静态图形在窗口底端渲染,动态图形在顶端渲染。

以上的视图类按表5‑3调用内核视图的显示函数,由GiCoreView显示图形。

表5‑3 Android视图类与内核显示函数的对应关系

视图类

对应的GiCoreView显示函数

视图类

GiCoreView函数

GraphView

drawAll

DynDrawStdView

dynDraw

GraphSfView

drawAll

DynDrawSfView

dynDraw

GraphViewCached

drawAppend、dynDraw、drawAll

   
5.3.2 实验结果

本文针对View、SurfaceView进行了上述十组实验,实验结果见图5‑7和表5‑4。实验条件为:Android 3.0、模拟器(320×480),其中使用较小分辨率是便于在本文中插入屏幕截图。在MOTO MZ606平板电脑(Android 4.0.3,1280×800)上实验后也得出相同的结论。

从这十组实验得到下列结论:

(1)普通的绘图方式基于View实现定制视图,在onDraw函数中使用Canvas进行绘图。该方式使用简单,适合绘制简单图形。缺点是绘图速度较慢,刷新一个视图会使同级的其他视图被动刷新,容易引起显示性能下降问题。

(2)交互式绘图显示速度快的方式有:使用增量绘图技术的普通视图(GraphViewCached);在SurfaceView中绘制动态图形的双层绘图视图。使用增量绘图技术的优点是可以只需要一个绘图视图,双层绘图视图的优点是可以在子线程中绘图,能提高刷新帧率。可以将两者的优点结合起来,在GraphViewCached中显示静态图形,在SurfaceView中绘制动态图形。

(3)如果要在SurfaceView中异步绘制静态图形,合适的使用条件有:a、与其他内容视图没有重叠区域;b、在窗口顶端透明显示,不要在此区域显示按钮等临时界面控件;c、在窗口底端显示,窗口里没有不透明的大面积界面元素。

图5‑7 Android渲染视图效果

表5‑4 Android渲染视图的组合实验情况

图号

视图搭配类型

显示速度和问题

a

GraphView

b

GraphSfView(面板表面视图)

慢,图形遮挡按钮

c

GraphSfView(媒体表面视图)

d

GraphViewCached

动态和静态绘图都很快

e

静态View + 动态View

慢,另一视图被动刷新

f

面板表面视图 + View

快,静态图形遮挡按钮和动态图形

g

静态View + 面板表面视图

h

面板表面视图 + 面板表面视图

快,动态绘图拖尾明显,遮挡按钮

i

媒体表面视图 + View

快,不透明视图会遮挡静态图形

-

媒体表面视图 + 面板表面视图

快,不透明视图会遮挡静态图形

注:其中的图号为图5‑7中的子图号。

5.4 Android绘图平台的结构

5.4.1 静态结构

根据绘图视图的实验结果,Android绘图平台按图5‑8设计静态类结构(省略了跨平台内核的内部结构和SWIG的Director类),相应类的说明见表5‑5。

图5‑8 Android绘图适配模块的结构

表5‑5 Android绘图适配模块的类

含义和职责

GraphViewHelper

面向应用程序的绘图封装接口类,提供常用API

GraphViewCached

显示静态图形的视图类,使用了基于缓存位图的增量绘图技术,负责触摸手势识别,委托内核的GiCoreView实现图形显示和手势操作

DynDrawSfView

显示动态图形的SurfaceView视图类,委托GiCoreView显示动态图形

ViewAdapter

视图适配器,允许内核回调Android视图,通知刷新显示

CanvasAdapter

使用Android Canvas实现的画布适配器

GiCoreView

跨平台内核的视图分发器,托管图形对象,分发显示请求和手势信息给图形列表和当前命令

应用程序使用绘图视图有两种方式:(1)仅使用GraphViewCached视图,适合图形量不太多的场合。(2)通过GraphViewHelper创建一个布局视图,自动创建GraphViewCached和DynDrawSfView视图,适合动态绘图帧率要求较高的场合。

5.4.2 应用效果

在Android绘图平台(属于TouchVG框架)中应用多层绘图技术分离静态图形视图和动态图形视图,提高了动态交互式绘图的回显速度。在静态图形视图中应用增量绘图技术,在连续绘制曲线图形时没有明显的拖尾现象。因此,绘图体验较流畅。

在跨设备平台的内核中使用绘图命令可以显示各种图形,在内核视图中使用仿射变换可以实现放缩显示。图5‑9展示了在不同Android版本的模拟器和平板电脑上的实际绘图效果。

图5‑9 Android综合绘图效果

5.5 本章小结

本章详细描述了SWIG在Android中的应用方法和扩展机制,针对出现的本地引用问题提出了修正方法。实验表明,SWIG所增加的封装函数并不会使绘图性能明显下降。描述了基于Android Canvas实现画布适配器的方式,实现了图形和图像的矢量化显示。画布适配器的单元测试使用了跨平台内核自动绘制图形,证明在内核中可以使用C++在Android上交互式绘图。

对普通视图、面板表面视图和媒体窗口进行了组合实验,总结出交互式绘图显示速度快、不出现遮挡问题的两种方式:使用增量绘图技术的单一视图方式;在SurfaceView中绘制动态图形的双层视图方式。

最后给出了Android绘图平台的设计结构和应用效果。


[1] 详细的SWIG编译选项见文件:https://raw.github.com/rhcad/vglite/master/android/demo/jni/touchvg.swig 。

[2] Python脚本见文件:https://raw.github.com/rhcad/vglite/master/android/demo/jni/replacejstr.py 。

[3] NDK编译配置文件见:https://raw.github.com/rhcad/vglite/master/android/demo/jni/Android.mk 。

[4] Onur Cinar. Pro Android C++ with the NDK. Berkeley: Apress, 2012

论文第5章:Android绘图平台的实现的更多相关文章

  1. Android群英传》读书笔记 (3) 第六章 Android绘图机制与处理技巧 + 第七章 Android动画机制与使用技巧

    第六章 Android绘图机制与处理技巧 1.屏幕尺寸信息屏幕大小:屏幕对角线长度,单位“寸”:分辨率:手机屏幕像素点个数,例如720x1280分辨率:PPI(Pixels Per Inch):即DP ...

  2. 第三章Android移植平台工具介绍

    第三章Android移植平台工具介绍 进行 Android 移植的学习并不一定需要一款 Android 手机,但必须要有一款主流的开发板,开发板是用来进行嵌入式系统开发的电路板,包括中央处理器.存储器 ...

  3. 第三章 Android绘图机制与处理技巧

    1.屏幕尺寸信息 屏幕大小:屏幕对角线长度,单位“寸”:分辨率:手机屏幕像素点个数,例如720x1280分辨率:PPI(Pixels Per Inch):即DPI(Dots Per Inch),它是对 ...

  4. 论文第4章:iOS绘图平台的实现

    面向移动设备的矢量绘图平台设计与实现 Design and Implementation of Mobile Device-oriented Vector Drawing Platform 引用本论文 ...

  5. 《Android开发艺术探索》读书笔记 (6) 第6章 Android的Drawable

    本节和<Android群英传>中的第六章Android绘图机制与处理技巧有关系,建议先阅读该章的总结 第6章 Android的Drawable 6.1 Drawable简介 (1)Andr ...

  6. Android群英传笔记——第六章:Android绘图机制与处理技巧

    Android群英传笔记--第六章:Android绘图机制与处理技巧 一直在情调,时间都是可以自己调节的,不然世界上哪有这么多牛X的人 今天就开始读第六章了,算日子也刚好一个月了,一个月就读一半,这效 ...

  7. Android进阶加密-第1章-Android系统架构-读书笔记

    第 1 章 Android 系统架构 1.1 Android 系统架构 Android 系统架构分为五层,从上到下依次是应用层.应用框架层.系统运行库层.硬件抽象层和 Linux 内核层. 应用层(S ...

  8. 【风马一族_Android】第4章Android常用基本控件

    第4章Android常用基本控件 控件是Android用户界面中的一个个组成元素,在介绍它们之前,读者必须了解所有控件的父类View(视图),它好比一个盛放控件的容器. 4.1View类概述 对于一个 ...

  9. [Learn Android Studio 汉化教程]第一章 : Android Studio 介绍

    注:为了看上去比较清晰这里只转载了中文 原地址:  [Learn Android Studio 汉化教程]第一章 : Android Studio 介绍 本章将引导您完成安装和设置开发环境,然后你就可 ...

随机推荐

  1. jQuery/javascript实现简单网页计算器

    <html> <head> <meta charset="utf-8"> <title>jQuery实现</title> ...

  2. Leetcode 219 Contains Duplicate II STL

    找出是否存在nums[i]==nums[j],使得 j - i <=k 这是map的一个应用 class Solution { public: bool containsNearbyDuplic ...

  3. sqlserver卡号段分组

    之前给上海一家电子商务公司做一个卖卡系统,遇到了卡号段分组的问题.刚开始没什么好的实现方法,遂在博客园求助但未果,没法自己研究sql,终于搞定. 问题描述: 有个卡库存表,有个卡号字段,假设数据:16 ...

  4. [原创]IBM BLM模型思维导图

    [原创]IBM BLM模型思维导图 IBM业务领先模型 http://wenku.baidu.com/view/1d1d247af242336c1eb95e3b.html?from=search

  5. Node + Express + Mysql的CMS小结

    因为之前用过上述的组合完成过很多系统,而这一次是为了实现一个帮助系统的静态网页发布.因为很久不写,重点说遇到的几个坑: 1.库版本的问题 比如mysql连接数据库一直报错,因为系统重装过,所以重新安装 ...

  6. PlaceholderImageView

    PlaceholderImageView 说明 1. PlaceHolderImageView基于SDWebImage编写 2. 给定一个图片的urlString,以及一个placeholderIma ...

  7. 了解 JavaScript (4)– 第一个 Web 应用程序

    在下面的例子中,我们将要构建一个 Bingo 卡片游戏,每个示例演示 JavaScript 的不同方面,通过每次的改进将会得到最终有效的 Bingo 卡片. Bingo 卡片的内容 美国 Bingo ...

  8. mysql慢日志设置

    mysql的慢日志查询对于sql的优化还是很有意义的,具体说下如何开启这个mysql慢查询日志(默认是开启的). 关于设置在mysql的官方手册或网上都有很多,但是要注意的是,mysql5.6与之前的 ...

  9. hibernateTemplate.find或hibernateTemplate.save()执行操作没有反应,但是有sql语句

    今天使用ssh框架搭建的项目,进行查询和保存操作,使用的是 public Collection<T> getAllEntry() { return this.hibernateTempla ...

  10. ECSHOP会员登录后直接进用户中心

    ECSHOP系统在会员登录成功后,不是直接进入用户中心,而是跳转回了上一个页面或者是跳转到了首页. 注意:这里说的是,用户没有主动点击前往哪个页面,让系统自动跳转. 那如何让会员登录成功后自动进入“用 ...