14 thg 3, 2012

[Networking Tut] Làm việc với networking sử dụng Thread và AsyncTask

Làm việc trên môi trường network với  Thread và AsyncTask giúp cho ứng dụng xử lý tốt hơn trong khi đang load data về từ internet.
Các bạn kham khảo các vấn đề cần quan tâm trong bài này là :
Thread in android , đối tượng Handler, và lớp AsyncTask . và cách thức làm việc của các lớp này.
Hoàn thành bài này sẽ có kết quả như sau :


Class StringLoaderTask lấy data kiểu String extends từ lớp AsyncTask như sau :

private class StringLoaderTask extends AsyncTask<String, Integer, String>{

@Override
protected String doInBackground(String... params) {
String result = null;
if (params.length <= 0) {
return null;
}
for (int i = 0; i < params.length; i++) {
String aURL = params[i];
try {
HttpClient httpclient = (HttpClient) new DefaultHttpClient();
HttpGet getobj = new HttpGet(aURL);
HttpResponse response = httpclient.execute(getobj);
if (response.getStatusLine().getStatusCode() == 200) {
HttpEntity anEntity = response.getEntity(); 
Header aHeader = anEntity.getContentType();
if (aHeader.getValue().contains("text/")) {
result = EntityUtils.toString(anEntity);
}
}
} catch (ClientProtocolException e) {
Log.e(LOG_TAG, "Falied at ClientProtocolException with error: " + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
Log.e(LOG_TAG, "Falied at IOException with error: " + e.getMessage());
e.printStackTrace();
} catch (Exception e) {
Log.e(LOG_TAG, "Falied at Exception with error: " + e.getMessage());
e.printStackTrace();
}
}
return result;
}

@Override
protected void onPostExecute(String result) {
if (result != null && result.length() > 0) {
mOutputContent.setText(result);
}
}
}

Class BitmapLoaderTask lấy data kiểu Bitmap extends từ lớp AsyncTask như sau : 

private class BitmapLoaderTask extends AsyncTask<String, Integer, Bitmap>{

@Override
protected Bitmap doInBackground(String... params) {
Bitmap result = null;
if (params.length <= 0) {
return null;
}
for (int i = 0; i < params.length; i++) {
String aURL = params[i];
try {
HttpClient httpclient = (HttpClient) new DefaultHttpClient();
HttpGet getobj = new HttpGet(aURL);
HttpResponse response;
response = httpclient.execute(getobj);
if (response.getStatusLine().getStatusCode() == 200) {
HttpEntity anEntity = response.getEntity(); 
Header aHeader = anEntity.getContentType();
if (aHeader.getValue().contains("image/")) {
result = new BitmapDrawable(anEntity.getContent()).getBitmap();
}
}
} catch (ClientProtocolException e) {
Log.e(LOG_TAG, "Falied at ClientProtocolException with error: " + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
Log.e(LOG_TAG, "Falied at IOException with error: " + e.getMessage());
e.printStackTrace();
} catch (Exception e) {
Log.e(LOG_TAG, "Falied at Exception with error: " + e.getMessage());
e.printStackTrace();
}
}
return result;
}

@Override
protected void onPostExecute(Bitmap result) {
if (result != null) {
mImageView.setImageBitmap(result);
}
}
}




Link download project : tại đây






[Networking Tut] Làm việc với networking trong Android


Bài này mình sẽ hướng dẫn các bạn thao tác với networking cơ bản nhất.
Khi làm việc với môi trường networking trên android, có 1 điều bạn luôn phải nhớ là cấp quyền truy cập Internet cho ứng dụng của bạn. bằng cách vào trong file AndroidManifest.xml. Chọn thẻ Permision -> Chọn Add -> Uses Permision -> ở ô Name chọn quyền android.permission.INTERNET.
Ý tưởng : các bạn sẽ lấy dữ liệu của 1 file xml trên môi trường mạng và hiển thị lên EditText. Và dữ liệu 1 images và hiển thị lên 1 imageView.

File main.xml trong thư mục res có dạng như sau :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />
    <LinearLayout
        android:id="@+id/ll_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
        <Button
            android:id="@+id/button2"
            android:layout_width="115dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.29"
            android:onClick="clickMe"
            android:text="Load Image" />

        <Button
            android:id="@+id/button1"
            android:layout_width="118dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.34"
            android:onClick="clickMe"
            android:text="Connect" />
    </LinearLayout>
    <EditText
        android:id="@+id/edtExt"
        android:layout_width="match_parent"
        android:layout_height="196dp" >
       <requestFocus />
    </EditText>
    <ImageView
        android:id="@+id/imgv"
        android:layout_width="match_parent"
        android:layout_height="220dp"
        android:src="@drawable/ic_launcher" />
</LinearLayout>

Chúng ta tạo ra 1 phương thức để lấy dữ liệu theo dạng text như sau :

Với tham số truyển vào là 1 biến String chính là URL đến file xml.
Kết quả trả về cũng là 1 biến kiểu String.



public String getData(String urlStr) {
StringBuilder result = new StringBuilder();
try {
URL url = new URL(urlStr);
httpcon = (HttpURLConnection) url.openConnection();
int requestCode = httpcon.getResponseCode();
if(requestCode == HttpURLConnection.HTTP_OK){
InputStream is = httpcon.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
result.append(line).append("\n");
}
br.close();
isr.close();
is.close();

}
httpcon.disconnect();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


return result.toString();
}


Phương thức lấy dữ liệu kiểu image.
Tham số là 1 biến kiểu String
Kết quả trả ra là 1 bitmap.

public Bitmap getImageData(String urlStr) {
try {
URI uri = new URI(urlStr);
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(uri);
HttpResponse reponse = client.execute(get);
HttpEntity entity = reponse.getEntity();
InputStream is = entity.getContent();
bitmap = BitmapFactory.decodeStream(is);
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

return bitmap;
}


Hoàn thành project này các bạn lấy được thông tin như hình sau :
Chúc vui. thân mến. 

Vậy khuyết điểm của phương pháp này là gì ? Đó là khi đang trong quá trình load dữ liệu về. các control của giao diện màn hình sẽ bị đứng, ko xử lý nhạy được.Chính vì vậy thông thường người ta sẽ dùng Thread để truy xuất. Bài sau mình sẽ làm demo về Thread làm việc trên môi trường networking.

Download Project này tại đây . 


[Source code] App tạo bàn phím ảo trên android

Bài này của 1 bạn có nick name là Kill ở 1 diễn đàn viết. Sợ quên nên mình copy về blog đọc sau vậy. Bài viết khá là hay và công sức của bạn ấy.
Ý tưởng : tạo ra 1 bàn phím có chức năng đơn giản như hình sau :
Bạn cần copy những resource cần thiết vào project của bạn làm
copy từ \android\platforms\<platform> vào thư mục \data\res\ 
(Nếu khó tìm bạn có thể download project của mình dưới bài viết)

Trong file layout của bạn, bạn cần add keyboard vào: /res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <Button android:id="@+id/button" android:background="@drawable/sym_keyboard_done" android:layout_height="fill_parent" android:layout_width="fill_parent" /> <LinearLayout android:layout_height="wrap_content" android:layout_width="wrap_content"> <android.inputmethodservice.KeyboardView android:id="@+id/keyboardView" android:visibility="gone" android:focusable="true" android:focusableInTouchMode="true" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_weight="0" /> </LinearLayout> </FrameLayout>



Tạo một file define cho bàn phím: /res/xml/qwerty.xml

<?xml version="1.0" encoding="utf-8"?> <!-- /** * * Copyright 2008, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ --> <Keyboard xmlns:android="http://schemas.android.com/apk/res/android" android:keyWidth="10%p" android:horizontalGap="0px" android:verticalGap="0px"> <Row> <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/> <Key android:codes="119" android:keyLabel="w"/> <Key android:codes="101" android:keyLabel="e"/> <Key android:codes="114" android:keyLabel="r"/> <Key android:codes="116" android:keyLabel="t"/> <Key android:codes="121" android:keyLabel="y"/> <Key android:codes="117" android:keyLabel="u"/> <Key android:codes="105" android:keyLabel="i"/> <Key android:codes="111" android:keyLabel="o"/> <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/> </Row> <Row> <Key android:codes="97" android:keyLabel="a" android:horizontalGap="5%p" android:keyEdgeFlags="left"/> <Key android:codes="115" android:keyLabel="s"/> <Key android:codes="100" android:keyLabel="d"/> <Key android:codes="102" android:keyLabel="f"/> <Key android:codes="103" android:keyLabel="g"/> <Key android:codes="104" android:keyLabel="h"/> <Key android:codes="106" android:keyLabel="j"/> <Key android:codes="107" android:keyLabel="k"/> <Key android:codes="108" android:keyLabel="l" android:keyEdgeFlags="right"/> </Row> <Row> <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift" android:keyWidth="15%p" android:isModifier="true" android:isSticky="true" android:keyEdgeFlags="left"/> <Key android:codes="122" android:keyLabel="z"/> <Key android:codes="120" android:keyLabel="x"/> <Key android:codes="99" android:keyLabel="c"/> <Key android:codes="118" android:keyLabel="v"/> <Key android:codes="98" android:keyLabel="b"/> <Key android:codes="110" android:keyLabel="n"/> <Key android:codes="109" android:keyLabel="m"/> <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete" android:keyWidth="15%p" android:keyEdgeFlags="right" android:isRepeatable="true"/> </Row> <Row android:rowEdgeFlags="bottom"> <Key android:codes="-3" android:keyIcon="@drawable/sym_keyboard_done" android:keyWidth="20%p" android:keyEdgeFlags="left"/> <Key android:codes="-2" android:keyLabel="123" android:keyWidth="15%p"/> <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space" android:keyWidth="30%p" android:isRepeatable="true"/> <Key android:codes="46,44" android:keyLabel=". ," android:keyWidth="15%p"/> <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return" android:keyWidth="20%p" android:keyEdgeFlags="right"/> </Row> </Keyboard> 

Trong lớp activity của bạn có thể dùng như sau: 

package myApp.DemoKey; import android.app.Activity; import android.inputmethodservice.Keyboard; import android.inputmethodservice.KeyboardView; import android.inputmethodservice.KeyboardView.OnKeyboardActionListener; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnKeyListener; public class DemoKey extends Activity implements OnKeyListener, OnKeyboardActionListener { private static final String TAG = DemoKey.class.getName(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); KeyboardView keyboardView = (KeyboardView) findViewById(R.id.keyboardView); Keyboard keyboard = new Keyboard(this, R.xml.qwerty); keyboardView.setKeyboard(keyboard); keyboardView.setEnabled(true); keyboardView.setPreviewEnabled(true); keyboardView.setOnKeyListener(this); keyboardView.setOnKeyboardActionListener(this); View button = findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { toggleKeyboardVisibility(); } }); } private void toggleKeyboardVisibility() { KeyboardView keyboardView = (KeyboardView) findViewById(R.id.keyboardView); int visibility = keyboardView.getVisibility(); switch (visibility) { case View.VISIBLE: keyboardView.setVisibility(View.INVISIBLE); break; case View.GONE: case View.INVISIBLE: keyboardView.setVisibility(View.VISIBLE); break; } } @Override public void swipeUp() { Log.d(TAG, "swipeUp"); } @Override public void swipeRight() { Log.d(TAG, "swipeRight"); } @Override public void swipeLeft() { Log.d(TAG, "swipeLeft"); } @Override public void swipeDown() { Log.d(TAG, "swipeDown"); } @Override public void onText(CharSequence text) { Log.d(TAG, "onText? \"" + text + "\""); } @Override public void onRelease(int primaryCode) { Log.d(TAG, "onRelease? primaryCode=" + primaryCode); } @Override public void onPress(int primaryCode) { Log.d(TAG, "onPress? primaryCode=" + primaryCode); } @Override public void onKey(int primaryCode, int[] keyCodes) { Log.d(TAG, "onKey? primaryCode=" + primaryCode); int n1 = 0; // -1 count for (int keyCode : keyCodes) { if (keyCode == -1) { n1++; continue; } Log.v(TAG, "keyCode=" + keyCode); } Log.v(TAG, "keyCode=-1 *" + n1); } @Override public boolean onKey(View v, int keyCode, KeyEvent event) { Log.d(TAG, "onKey? keyCode=" + keyCode); return false; } } 

Bạn nào muốn demo thử thì tạo project rồi thử xem nhé. Khi nào mình có thời gian sẽ code hoàn thiện hơn rồi up link project lên tại đây. 


13 thg 3, 2012

Touch Event của Android

Như chúng ta biết Touch Mode trong android cung cấp cho chúng ta 3 loai. Thứ nhất là tap(Chạm ngón tay vào màn hình), drag(chạm vào màn hình và giữ ngón tay 1 lúc và di chuyển), pintch-zoom(dùng 2 ngón tay zoom đối tượng nào đó).
Ở đây tôi sẽ giới thiệu cho bạn loại thứ 2 là sự kiện drag :
ý tưởng : vẽ 1 line từ vị trí chạm lần đầu đến vị trí cuối khi người sử dụng bỏ tay ra khỏi screen.

Dưới đây là code thực hiện :

package app.test;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;

public class Test extends Activity implements OnTouchListener {
  ImageView imageView;
  Bitmap bitmap;
  Canvas canvas;
  Paint paint;
  float downx = 0, downy = 0, upx = 0, upy = 0;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    imageView = (ImageViewthis.findViewById(R.id.ImageView);

    Display currentDisplay = getWindowManager().getDefaultDisplay();
    float dw = currentDisplay.getWidth();
    float dh = currentDisplay.getHeight();

    bitmap = Bitmap.createBitmap((intdw, (intdh,
        Bitmap.Config.ARGB_8888);
    canvas = new Canvas(bitmap);
    paint = new Paint();
    paint.setColor(Color.GREEN);
    imageView.setImageBitmap(bitmap);

    imageView.setOnTouchListener(this);
  }

  public boolean onTouch(View v, MotionEvent event) {
    int action = event.getAction();
    switch (action) {
    case MotionEvent.ACTION_DOWN:
      downx = event.getX();
      downy = event.getY();
      break;
    case MotionEvent.ACTION_MOVE:
      break;
    case MotionEvent.ACTION_UP:
      upx = event.getX();
      upy = event.getY();
      canvas.drawLine(downx, downy, upx, upy, paint);
      imageView.invalidate();
      break;
    case MotionEvent.ACTION_CANCEL:
      break;
    default:
      break;
    }
    return true;
  }
}

Chúc các bạn học tốt. Thân mến.



[Tut]_libGDX : Video tut

Các video hướng dẫn dùng libGDX :










[Tut]_libGDX : Vòng đời của 1 ứng dụng


Bài này mô tả cấu trúc của 1 ứng dụng phát triển từ thư viện libGDX như thế nào và sự khác nhau giữa các playforms. 

The Application

Đây là điểm quan trọng của dự án libGDX. giao diện của ứng dụng được cung cấp các phương thức truy cập vào các thành phần chung như Graphices, Audio, Input, File I/O. Nó cũng cho phép truy cập đến thành phần Logging làm việc với tất cả các platforms.
LibGDX hiện tại đã hỗ trợ 2 thành phần cho ứng dụng desktop là lwjgl và jogl , cùng với đó là 1 thành phần cho android.
Để tạo 1 ứng dụng libGDX, cần phải implement phương thức ApplicationListener đầu tiên. 

The Application Listener

Bộ lắng nghe này phản hồi những khởi tạo của ứng dụng, cập nhật trạng thái game, rendering the output gamem tạm dừng game, lưu trạng thái game, hay giải phóng tài nguyên khi thoát ứng dụng.

Khi xây dựng 1 ứng dụng hay 1 game nào đó, chúng ta đều phải implements ApplicationListener interfaces. 
It is also the place where the application life-cycle events are handled. Every application/game, regardless of the back-end and/or target platform will have to implement the ApplicationListener interface. The implementation is exactly the same for all platforms.

ApplicationListener có dạng sau :

public class MyGame implements ApplicationListener {
        public void create () {
                // STUB
        }

        public void render () {
                // STUB
        }

        public void resize (int width, int height) { 
                // STUB
        }

        public void pause () { 
                // STUB
        }

        public void resume () {
                // STUB
        }

        public void dispose () { 
                // STUB
        }
}

Method signatureDescription
create ()Method được gọi 1 lần khi ứng dụng được tạo  ra.
resize(int width, int height)Method này được gọi tại mọi thời gian mà màn hình game được re-sized và game không ở trạng thái pause. Nó được gọi sau create() method.
render ()Method được gọi bởi vòng lặp của game từ mọi thời điểm của ứng dụng khi rendering xảy ra. 
pause ()Phương thức này được gọi trước khi game bị hủy. Androi gọi nó khi phím Home được nhấn xuống hoặc có cuộc gọi đến. Trên desktop game thì được gọi trước phương thức despose() khi thoát game.
resume ()Phương thức này chỉ có trên android.
dispose ()Gọi khi game bị hủy.

Application life-cycle


Creating the Desktop Application

The following class creates a desktop application using lwjgl from the previously created MyGame listener.
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
public class MyDesktopGame {
        public static void main(String[] args) {
                new LwjglApplication(new MyGame(), "My Game", 480, 320, false);
        }
}
Chạy game.
It creates a lwjgl backed application 480 pixels wide, 320 pixels tall. The last parameter indicates that OpenGL ES 2 is NOT to be used.
The following class creates a desktop application using JOGL as the back-end from the same MyGame listener.
import com.badlogic.gdx.backends.jogl.JoglApplication;
public class MyDesktopGame {
        public static void main(String[] args) {
                new JoglApplication(new MyGame(), "My Game", 480, 320, false);
        }
}
In both cases the appropriate libraries have to be used. In the first case the following jar files need to be included:
  • gdx.jar
  • gdx-natives.jar
  • gdx-backend-lwjgl.jar
  • gdx-backend-lwjgl-natives.jar
In the second case, for jogl, the following jars need to be included:
  • gdx.jar
  • gdx-natives.jar
  • gdx-backend-jogl.jar
  • gdx-backend-jogl-natives.jar
The constructor for the desktop application takes 5 parameters:
ApplicationListener listenerThis is an instance of the ApplicationListener created for the application game
String titleThe title of the application which will be shown on the title bar
int widthThe screen width of the application window
int heightThe screen height of the application window
boolean useGL2true if the we want the renderer to use OpenGL 2, or false to stick with OpenGL 1.x


Bản beta đầu tiên

Sau 6 tháng cả team cặm cụi làm việc điên cuồng, bản alpha cũng được giới thiệu ra toàn bộ công ty và được testing nội bộ công ty mà thôi. ...