Tuesday, May 6, 2014

Lấy tất cả Resource trong drawable của Android


Đoạn mã sau cung cấp cách để lấy ra tất cả resource trong drawable của android.
final R.drawable drawableResources = new R.drawable();
final Class<R.drawable> c = R.drawable.class;
final Field[] fields = c.getDeclaredFields();

for (int i = 0, max = fields.length; i < max; i++) {
    final int resourceId;
    try {
        resourceId = fields[i].getInt(drawableResources);
    } catch (Exception e) {
        continue;
    }
    /* make use of resourceId for accessing Drawables here */
}

Wednesday, April 23, 2014

Đặc điểm của Vector, ArrayList trong Java


ArrayList và Vector trong java

Các lớp Vector và ArrayList được triển khai xây dựng dựa trên mảng Object[] dùng để lưu trữ các phần tử. Việc truy xuất đến các phần tử cũng đơn giản thông qua việc truy xuất theo chỉ mục(index) như trong mảng.

Đặc điểm của Vector và ArrayList là chúng ta có thể thêm những phần tử mới vào mà không gặp trở ngại về “sức chứa” như Array thông thường là phải định rõ độ lớn(chiều dài) của mảng.

Vậy, chúng “giãn nở” như thế nào ? Như đã nói ở trên Vector & ArrayList được xây dựng dựa trên mảng các Object[]. Mảng này có thể lớn hơn độ lớn các phần tử cấu thành lên Vector/ArrayList object nhằm giữ khả năng có thể thêm phần tử mới khi cần. Khi tận dụng hết khả năng sức chứa của mảng này thì Vector/ArrayList object phải tạo ra một mảng mới có độ lớn (sức chứa) hơn mảng cũ và những phần tử trước đó sẽ được sao chép chuyển sang mảng mới này. Về độ lớn của mảng mới tạo ra so với mảng cũ sẽ tùy thuộc vào các version SDK mà dao động trong khoảng 50 – 100 (%). 2 đoạn code dưới đây là một minh chứng :
public void ensureCapacity(int minCapacity) {
    int oldCapacity = elementData.length;
    if (minCapacity > oldCapacity) {
        Object oldData[] = elementData;
        int newCapacity = (oldCapacity * 3) / 2 + 1;
        if (newCapacity < minCapacity) newCapacity = minCapacity;
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
}

public void ensureCapacity(int minCapacity) {
    int oldCapacity = elementData.length;
    if (minCapacity > oldCapacity) {
        Object oldData[] = elementData;
        int newCapacity = Math.max(oldCapacity * 2, minCapacity);
        elementData = new Object[newCapacity];
        System.arrayscopy(oldData, 0, elementData, 0, size);
    }
}


Tính hiệu quả khi chèn phần tử mới vào Vector & ArrayList :
- Chèn vào vị trí index = 0 sẽ cho tính hiệu quả kém nhất (the worst performance) vì tất cả những phần tử trước đó sẽ phải dịch chuyển lên trên.
- Chèn vào vị trí sau phần tử đứng cuối cùng sẽ cho hiệu quả tốt nhât (the best performance) vì các phần tử trước đó vẫn giữ nguyên vị trí không có một sự xáo trộn nào xảy ra.
- Từ đây ta cũng có thể hiển được tính hiệu quả khi chèn vào vị trí bất kì nào khác 2 vị trí trên.


Điểm khác biệt chính giữa Vector và ArrayList là sử dụng cơ chế đồng bộ (synchronization). Ngoài 2 methods sử dụng serialize thì ArrayList không có một methods nào được đồng bộ hóa. Ngược lại với Vector, hầu hết các phương thức (method) của Vector được đồng bộ hóa. Vì thế Vector là thread-safe còn ArrayList thì không. Trong những ứng dụng đa luồng thì việc sử dụng Vector là hợp lý hơn vì tính đồng bộ của nó thích hợp cho việc giải quyết nhiều tương tác trong một thời điểm. Còn các phương thức của ArrayList sẽ cho tốc độ xử lý nhanh hơn trong trường hợp đơn giản không đòi hỏi xử lý nhiều tương tác trong một thời điểm. Sự cách biệt về tốc độ xử lý giữa 2 class này càng ngày càng được thu hẹp lại với những version JVMs (máy ảo Java) mới nhất.
(Sưu tầm)

Saturday, March 15, 2014

OpenGL ES 2.0 trên android - Trả lời sự kiện chạm

Trả lời sự kiện chạm

Làm cho đối tượng di chuyển theo một chương trình định sẵn như hình tam giác xoay rất hữu ích để có được một số sự chú ý, nhưng những gì nếu bạn muốn có người dùng tương tác với đồ họa OpenGL ES của bạn? Chìa khóa để làm ứng dụng cảm ứng OpenGL ES của bạn tương tác được mở rộng thực hiện của bạn GLSurfaceView để ghi đè lên onTouchEvent () để lắng nghe cho các sự kiện liên lạc.
Bài học này cho bạn thấy làm thế nào để lắng nghe cho các sự kiện liên lạc cho phép người dùng xoay một đối tượng OpenGL ES.

1.1.   Cài đặt một Touch Listener

Để làm cho ứng dụng OpenGL ES phản ứng với các sự kiện chạm vào, bạn phải thực hiện onTouchEvent() trong lớp GLSurfaceView của bạn. Việc thực hiện ví dụ dưới đây cho thấy làm thế nào để lắng nghe cho các sự kiện MotionEvent.ACTION_MOVE và dịch chúng vào một góc quay cho một shape.
@Override

public boolean onTouchEvent(MotionEvent e) {

    // MotionEvent reports input details from the touch screen
    // and other input controls. In this case, you are only
    // interested in events where the touch position changed.

    float x = e.getX();
    float y = e.getY();

    switch (e.getAction()) {
        case MotionEvent.ACTION_MOVE:

            float dx = x - mPreviousX;
            float dy = y - mPreviousY;

            // reverse direction of rotation above the mid-line
            if (y > getHeight() / 2) {
              dx = dx * -1 ;
            }

            // reverse direction of rotation to left of the mid-line
            if (x < getWidth() / 2) {
              dy = dy * -1 ;
            }

            mRenderer.setAngle(
                    mRenderer.getAngle() +
                    ((dx + dy) * TOUCH_SCALE_FACTOR);  // = 180.0f / 320
            requestRender();
    }

    mPreviousX = x;
    mPreviousY = y;
    return true;
}
Chú ý rằng sau khi tính toán góc quay, phương pháp này gọi requestRender () để cho các renderer rằng đó là thời gian để làm cho khung. Phương pháp này là hiệu quả nhất trong ví dụ này vì khung không cần phải được vẽ lại, trừ khi có một sự thay đổi trong vòng quay. Tuy nhiên, nó không có bất kỳ tác động hiệu quả trừ khi bạn cũng yêu cầu các renderer chỉ vẽ lại khi dữ liệu thay đổi bằng cách sử dụng hàm setRenderMode(), do đó hãy chắc chắn rằng dòng này là không chú thích trong renderer:
public MyGLSurfaceView(Context context) {

    ...
    // Render the view only when there is a change in the drawing data
    setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

}

1.2.   Phơi bày các góc quay

Mã ví dụ trên yêu cầu bạn tiếp xúc với các góc quay thông qua renderer của bạn bằng cách thêm một thành viên public. Kể từ khi mã renderer đang chạy trên một thread khác từ phía giao diện người dùng chính thread của ứng dụng của bạn, bạn phải khai báo biến công cộng này là volatile. Đây là mã để làm điều đó:
public class MyGLRenderer implements GLSurfaceView.Renderer {

    ...
    public volatile float mAngle;

1.3.   Áp dụng phép xoay

Áp dụng phép xoay được tạo ra bởi đầu vào cảm ứng, chú thích ra các mã để tạo một góc và thêm mAngle, trong đó có các đầu vào tạo ra góc cảm ứng:
public void onDrawFrame(GL10 gl) {

    ...
    float[] scratch = new float[16];

    // Create a rotation for the triangle
    // long time = SystemClock.uptimeMillis() % 4000L;
    // float angle = 0.090f * ((int) time);
    Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);

    // Combine the rotation matrix with the projection and camera view
    // Note that the mMVPMatrix factor *must be first* in order
    // for the matrix multiplication product to be correct.
    Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);

    // Draw triangle
    mTriangle.draw(scratch);
}
Khi bạn đã hoàn thành các bước mô tả ở trên, chạy chương trình và kéo tay của bạn trên màn hình để xoay hình tam giác:

Figure 1. Triangle being rotated with touch input (circle shows touch location).

OpenGL ES 2.0 trên android - Thêm chuyển động

Thêm chuyển động

Vẽ các đối tượng trên màn hình là một tính năng khá cơ bản của OpenGL, nhưng bạn có thể làm điều này với các lớp học framwork đồ họa Android khác, bao gồm cả Canvas và các đối tượng drawable. OpenGL ES cung cấp khả năng bổ sung cho việc di chuyển và chuyển đối tượng được vẽ với không gian ba chiều hoặc theo những cách độc đáo khác để tạo ra những trải nghiệm người dùng hấp dẫn.
Trong bài học này, bạn lấy một bước chuyển tiếp vào sử dụng OpenGL ES bằng cách học làm thế nào để thêm chuyển động với một shape với phép xoay.

1.1.   Xoay một Shape

Quay một đối tượng vẽ với OpenGL ES 2.0 là tương đối đơn giản. Bạn tạo ra một ma trận biến đổi (một ma trận xoay) và sau đó kết hợp nó với chiếu của bạn với camera ma trận biến đổi:
private float[] mRotationMatrix = new float[16];

public void onDrawFrame(GL10 gl) {

    ...

    float[] scratch = new float[16];

    // Create a rotation transformation for the triangle
    long time = SystemClock.uptimeMillis() % 4000L;
    float angle = 0.090f * ((int) time);
    Matrix.setRotateM(mRotationMatrix, 0, angle, 0, 0, -1.0f);

    // Combine the rotation matrix with the projection and camera view
    // Note that the mMVPMatrix factor *must be first* in order
    // for the matrix multiplication product to be correct.
    Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);

    // Draw triangle
    mTriangle.draw(scratch);
}
Nếu tam giác của bạn không quay sau khi thực hiện những thay đổi này, chắc chắn rằng bạn đã chú thích thiết lập GLSurfaceView.RENDERMODE_WHEN_DIRTY, như được mô tả trong phần tiếp theo.

1.2.   Cho phép Rendering liên tục

Nếu bạn đã tinh tấn làm theo cùng với các mã ví dụ trong lớp này đến thời điểm này, chắc chắn rằng bạn nhận xét ra các dòng thiết lập chế độ làm chỉ vẽ khi thay đổi, nếu không OpenGL chỉ quay một lần và chờ đợi cho một cuộc gọi đến requestRender () từ container GLSurfaceView:
Trừ khi bạn có các đối tượng thay đổi mà không cần bất kỳ tương tác người dùng, nó thường là một ý tưởng tốt có lá cờ này bật. Hãy sẵn sàng để bỏ ghi chú mã này, bởi vì bài học tiếp theo làm cho cuộc gọi này được áp dụng một lần nữa.

OpenGL ES 2.0 trên android - Áp dụng phép chiếu và camera

Áp dụng phép chiếu và camera

Trong môi trường OpenGL ES, phép chiếu và máy quay cho phép bạn hiển thị các đối tượng hình vẽ theo cách giống cách bạn nhìn thấy đối tượng vật lý với đôi mắt của bạn. Mô phỏng vật lý này được thực hiển với biến đối toán học của tọa độ hình vẽ:
·         Chiếu - chuyển đổi này điều chỉnh tọa độ của đối tượng được vẽ dựa trên chiều rộng và chiều cao của GLSurfaceView nơi chúng được hiển thị. Mà không cần tính toán này, các đối tượng được vẽ bởi OpenGL ES đang sai lệch bởi tỷ lệ đồng đều của cửa sổ xem. Một chuyển đổi chiếu thường chỉ phải được tính toán khi tỷ lệ của khung nhìn OpenGL được thành lập hoặc thay đổi trong onSurfaceChanged() của renderer của bạn. Để biết thêm thông tin về OpenGL ES dự và phối hợp ánh xạ, xem bản đồ tọa độ cho các đối tượng được vẽ.
·         Camera - chuyển đổi này điều chỉnh tọa độ của đối tượng được vẽ dựa trên một vị trí máy quay ảo. Điều quan trọng cần lưu ý là OpenGL ES không định nghĩa một đối tượng máy ảnh thực tế, nhưng thay vì cung cấp phương pháp hữu ích mà mô phỏng một máy ảnh bằng cách biến đổi màn hình hiển thị của các đối tượng vẽ. Một biến đổi camera có thể được tính toán một lần khi bạn thiết lập GLSurfaceView của bạn, hoặc có thể thay đổi tự động dựa trên các hành động sử dụng hay chức năng ứng dụng của bạn.
Bài học này mô tả làm thế nào để tạo ra một chiếu và xem máy ảnh và áp dụng nó cho Shapes được vẽ trong GLSurfaceView của bạn.

1.1.   Định nghĩa phép chiếu

Dữ liệu cho một biến đổi của phép chiếu được tính toán trong hàm onSurfaceChanged() của lớp GLSurfaceView.Renderer. Ví dụ dưới đây lấy chiều cao và rộng của GLSurfaceView và sử dụng để chứa biến đổi ma trận phép chiếu sử dụng hàm Matrix.frustumM().
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {

    GLES20.glViewport(0, 0, width, height);

    float ratio = (float) width / height;

    // this projection matrix is applied to object coordinates
    // in the onDrawFrame() method
    Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
Mã này chứa một ma trận chiếu, mProjectionMatrix mà bạn có thể kết hợp với sự chuyển đổi camera quan sát trong hàm onDrawFrame(), được thể hiện trong phần tiếp theo.
Lưu ý: Chỉ cần áp dụng một phép chiếu cho đối tượng vẽ của bạn, nếu không kết quả sẽ là một màn hình trống rỗng. Nói chung, bạn cũng phải áp dụng các chuyển camera để cho bất cứ điều gì để hiển thị trên màn hình.

1.2.   Định nghĩa một Camera

Hoàn tất quá trình chuyển đối tượng vẽ của bạn bằng cách thêm một biến đổi camera như một phần của quá trình vẽ. Trong mã ví dụ sau đây, việc chuyển đổi camera được tính toán bằng cách sử dụng Matrix.setLookAtM () và sau đó kết hợp với ma trận chiếu tính trước đó. Các ma trận biến đổi kết hợp này sau đó được thông qua để vẽ ra shape.
@Override

public void onDrawFrame(GL10 unused) {

    ...

    // Set the camera position (View matrix)
    Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

    // Calculate the projection and view transformation
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);

    // Draw shape
    mTriangle.draw(mMVPMatrix);
}

1.3.   Áp dụng phép chiếu và camera

Để sử dụng chiếu kết hợp với camera ma trận biến đổi thể hiện trong phần xem trước, chỉnh sửa hàm draw () của đối tượng đồ họa của bạn để chấp nhận các ma trận biến đổi kết hợp và áp dụng nó vào shape:
public void draw(float[] mvpMatrix) { // pass in the calculated transformation matrix

    ...

    // get handle to shape's transformation matrix
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");

    // Pass the projection and view transformation to the shader
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

    // Draw the triangle
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
    ...
}
Một khi bạn đã tính toán một cách chính xác và áp dụng phép chiếu với camera chuyển đổi, các đối tượng đồ họa của bạn được rút ra theo tỷ lệ chính xác và sẽ giống như thế này:
Figure 1. Triangle drawn with a projection and camera view applied.
Bây giờ bạn có một ứng dụng hiển thị shape của bạn với tỷ lệ chính xác, đã đến lúc để thêm chuyển động cho hình của bạn.