2015年10月17日 星期六

Android Unit Test (一)

Android Unit Test (一)

由於最近上了SkillTreeTDD課程,加上學費也不少…沒有整理的話應該很快就會忘,所以我就嘗試以Android 的方式來重現上課的內容。觀念會稍微提到而已,最主要的內容會是實做為主。


Unit Test 的觀念

這些觀念其實網路上都有很多資源可以查的到,在這裡只是提供關鍵字

3A 原則

  • Arrange : 初始化
  • Act : 執行測試動作
  • Assert : 驗證

FIRST

  • Fast : 快速驗證
  • Independent : 測試之間不會有相依關係
  • Repeatable : 每次執行的測試都是會是一樣的
  • Self-Validating : 能自我驗證
  • Timely : 測試碼要比production code 早完成

Android 建置環境

接下來的幾篇都會以下列的環境為主

  • Android Studio 1.4
  • JDK 7

開始第一個Unit Test

這邊要驗證的是一個簡單的加法,為了快速上手。暫時不採用TDD的做法(先寫測試)

1. 建立空白專案

要開甚麼專案都行,Android TV , Android Wear 也沒關係,本節重點是放在測試程式

2. 建立 MyMath 類別並實做加法


public class MyMath {

    public int add(int first, int second){
        return first + second;
    }
}

3. 建立測試類別

請見下圖,Android Studio 專案的測試程式預設是放在 src/androidTest/java/(packageName) 底下,在這裡建立一個”MyMathTest”的類別

4. 撰寫測試程式碼

要驗證加法是不是正確,我們需要輸入實際輸出、以及期待的輸出結果。在這個例子中,輸入是12,期待的輸出結果是3,要是實際輸出等於期待輸出,本次測試就會通過。

public class MyMathTest extends AndroidTestCase{

    public void test_add_first_1_second_2_equals_3(){
        //arrange
        int first = 1;
        int second = 2;
        int expect = 3;
        MyMath myMath = new MyMath();

        //act
        int actual = myMath.add(first, second );

        //assert
        assertEquals(expect, actual);
    }

}

Tip:

  • 為了能夠運行測試,MyMathTest 要繼承AndroidTestCase
  • assert為單元測試的基礎,assert的結果會決定這次測試的是否通過,在本例中expect 與 actual 值一樣的話 assertEquals()就會通過

5. 執行測試

可選擇使用模擬器或實機來執行測試

等待一段時間後,可以看到綠燈,代表測試通過!!


2015年4月11日 星期六

Android 魔術方塊開發筆記(四) 投影與旋轉

投影

不知道各位有沒有注意到一件事
上一章的正方形不是正的是長的!!

造成這個的原因
就是因為我們的GLSurfaceView本來就是長的
畫出來的正方形就會因此而拉長!!


(取自google API guide)

解決方法其實也很簡單
只要將我們的座標點
經由矩陣運算投影
就能畫出真正的正方形

1. 更改shader code

    我們可以將座標與矩陣的運算交給底層,JAVA層的運算越少越好
    在GLShaderFactory做了以下修改:



    MVP 是 Model View Projection的縮寫
    在這裡將uMVPMatrix帶進去做運算

2. 建立Projection Matrix


    在GLES20Randerer 的 onCreate有View的長寬資訊:width, height
    將width, height相除得到長寬的比值ratio
    接著呼叫Native function : Matrix.frustumM(float[] m, int offset, float left, float right, float bottom, float top, float near, float far)
    得到4*4矩陣mProjectionMatrix


攝影機

接下來我們可以決定從哪裡觀察
下面這張圖可以讓大家有個初步的概念
這裡一樣是矩陣運算

3. 建立 View Matrix

    Matrix.setLookAtM(...)可以很簡單的建立上述的矩陣

4. 組合MVP Matrix

   要注意矩陣是沒有交換律的,矩陣相乘順序不能放錯
   完整程式碼:

5. 改寫Square

   這邊其實也沒做太大的變動
   只有取得uMVPMatrix的handle
   並將我們計算得到的MVP Matrix傳給底層

   如此一來已經大功告成,正常顯示出一個正方形了
   *可以更改看看frustumM(), setLookAtM()的參數,會更加了解上面這幾張圖所代表的意義

旋轉

直到現在都是很無聊的一張圖
加個旋轉讓他動起來吧!!

6. 建立Rotation Matrix

Matrix一樣提供了一個簡單的函式來計算旋轉矩陣


這樣就有動畫效果啦!!

Source Code:
Version : e013248db0

Reference:



2015年4月6日 星期一

Android 魔術方塊開發筆記(三) 繪製多邊形



1.繪製多邊形有以下三種方法:


上圖的數字代表繪圖的順序
也就是我們給OpenGL  ByteBuffer的順序

跟三角形一樣
先定義出正方形四個點的座標
然後其餘程式碼不變


對照上圖,top left 為編號1
                    bottom left 為編號2
                    bottom right 為編號3
                    top right 為編號4

依GL_TRIANGLE_FAN 的繪圖次序就會繪製出一個正方形
以下分別為GL_TRIANGLES以及GL_TRIANGLE_STRIP的畫面 


如果要讓GL_TRIAGLES 也能顯示正方形,
需要在squareCoords[] 中加入bottom right, top left兩點
 
GL_TRIANGLE_STRIP則是squareCoords[]中的順序調一下即可

2.glDrawElements()

除了glDrawArrays()之外,
OpenGL還提供了另外一個繪製方法glDrawElements
這邊的順序就由我們自己來定義
跟vertex相同,需要一個byteBuffer將值傳給OpenGL


結果:



完整程式碼:

Source Code:
版本:a3ffd93481

Reference:


2015年4月5日 星期日

Android 魔術方塊開發筆記(二) shader以及繪製三角形

接下來這邊對C不熟悉的人可能會痛苦一點了
OpenGL ES的語法其實都是直接CALL native Function
跟JAVA的思維不一樣

1. 建立3D座標

這裡所繪製的是3維座標,
我們要設定一點就必須給他x,y,z座標
以下triangleCoords就代表了一個三角形的3個點的座標

要繪製圖形除了座標之外還需要顏色
跟Android resource的順序有點不太一樣,這邊是RGBA
而且範圍在0.0~1.0之間

Android 底層閱讀Byte的順序可能與Java不一樣
我們要傳送給Opengl就要先轉成ByteBuffer
並設定為native order
才能讓Opengl理解

2. OpenGL ES Shading Language


如上圖
Shading Language會在橘色區塊中執行
這邊已經很底層的元件了
我們必須將他撰寫成String
再交給OpenGL去編譯
----> GLES20.glCompileShader(shader)

這邊所使用的是最基本用法

SHADER_CODE_VERTEX
用來處理點座標
SHADER_CODE_FRAGMENT
用來處理渲染效果

這邊的vPosition, vColor是我們定義的變數名稱
用來連結openGL ES及我們撰寫的java

gl_Position, gl_FragColor則是openGL ES所認得的變數名稱
我們經過運算後必需要傳到這些變數
才能顯示出來

其他部分有興趣的可以參考SPEC


如果只有接觸過上層程式語言的人可能會很納悶
為什麼這邊都是用int來進行操作
其實這邊的int可以把它當成物件的ID
OpenGL ES 將會根據這些ID做相對應的處理

這邊就不一行一行解說
從method的名稱就大概知道裡面的作用了

完整程式碼:

3. 建立Triangle class

這邊就結合上面2步
連結我們的3D座標以及Shader

這邊直接看draw()
mProgram 是剛剛GLShaderFactory裡得到的ID
藉由他我可以拿到vPosition, vColor的ID(positionHandle, colorHandle)
再來呼叫glVertexAttribPointer(),glUniform4fv()
將數值帶進去
最後呼叫glDrawArrays()
三角形就出來啦~~

還有一步



Android 魔術方塊開發筆記(一) OPENGL ES 的 hello world

有鑑於網路上有關於android OpenGL的資源並不多(幾乎都英文)
再加上我想要做這個已經想很久了
於是我就來邊開發邊寫一下筆記
希望能夠幫助到想學習OpenGL ES的初學者
(也希望我會堅持寫下去...)

小小介紹一下OpenGL ES

OPENGL ES(OpenGL for Embedded Systems)

是專門為嵌入式系統設計的OpenGL
API用法其實跟原來版本的OpenGL沒差多少
Android 中所有畫面其實也是由OpenGL ES畫出來的

1. 建立專案

    在這裡我使用的是Android studio,開啟新Blank Activity,這裡就不詳細描述了

2. 檢查OpenGL 版本

    本專案我以OpenGL 2.0為主
    下圖來自Android Developers官網(2015/4/5)
    https://developer.android.com/about/dashboards/index.html?utm_source=suzunone
    可見現在所有的裝置已經至少都2.0以上了
    網路上1.0的舊資料基本上可以跳過不用看了


    上述程式碼用來檢查手機的GLES版本
    如果熟悉Android的開發者應該馬上就知道這邊做了甚麼事
    參考一下官方文件:

public int reqGlEsVersion

Added in API level 4
The GLES version used by an application. The upper order 16 bits represent the major version and the lower order 16 bits the minor version.
   簡單的來說2開頭就是支援到2.0,3開頭支援到3.0

   知道了GLES版本後我們就來做個小小的限制
   讓不支援2.0版本的裝置無法安裝
   在AndroidManifest.xml 裡加入


3. GLSurfaceView

    顯示文字我們用TextView, 
    要顯示OpenGL 就要使用GLSurfaceView了
    跟一般Android APP一樣
    第一步先建立好xml檔

    

    再來在MainActivity加入下列程式碼


    這邊有一個重點
    GLSurfaceView 一定要搭配GLSurfaceView.Renderer才能渲染出圖形
    這個Renderer的責任包含了視角的轉換以及圖形的繪製等等
    然而原始的GLSurfaceView.Renderer是abstract class
    我們必須實做他所有的Methods

4. Renderer

    總共要實做3個Method
    onSurfaceChanged(GL10 gl, int width, int height) : surface 改變大小時呼叫
    onSurfaceCreated(GL10 gl, EGLConfig config) : surface 建立時呼叫
    onDrawFrame(GL10 gl) : 繪圖時呼叫

    *當手機進行休眠狀態時,onSurfaceCreated會去重新呼叫一次,
      如果想避免他重新呼叫,
      就要在GLSurfaceView初始化時setPreserveEGLContextOnPause(boolean) 設為true
      並且在Activity 的onPause(),onResume()中加入
      GLSurfaceView.onPause(), GLSurfaceView.onResume()

    由於我們使用的是2.0版本,已經不需要GL10這參數
    我參(ㄊㄡ)考(ㄌㄞˊ)了網路上的高手
    改寫成以下版本



    改寫成這版本後只需要注意兩件事
    1. 初始化時需要做甚麼
    2. 每個Frame我們應該要Show甚麼

5. 執行

    以上做完後就可以得到一個國防布啦
    下一篇就會開始繪製圖形


    


SourceCode:
版本號671fb71eaa

Reference: